tony
tony

Reputation: 2392

Better way of creating repeating HTML section

I've asked this once before but without any code to look at, here I have an implementation and I'm wondering if there is a better way to accomplish this.

I want a repeating html section like so:

<div>
  <input id=id1 name=id1 type=text/>
</div>
<div>
  <input id=id2 name=id2 type=text/>
</div
etc

This could contain any number of input boxes which map to the List of 'something' classes I have in the model, I presently do this with a View

@using (Html.BeginForm())
{
    for (int i = 0; i < Model.Somethings.Count; i++)
    {
        Model.Index = i;
        @Html.Action("Index", "HtmlSection", Model);
    }
    // other stuff
}

and a partial view

@{
int index = Model.Index;
}
@Html.TextBoxFor(x => x.Somethings[index].TheProperty)

Where the model looks like this

public class HtmlSectionModel
{
    public List<Something> Somethings { get; set; }
    public int Index { get; set; }
}

Finally the action looks like this

public ActionResult Index(HtmlSectionModel model)
{
// do stuff
}

To me this works but isn't ideal

This seems to me to be a common pattern so others must have solved it in other ways?

I guess what I'm after here is the MVC equivalent of Asp.Net UserControls/Webcontrols (which seem to be child actions/partial views), but, combined with model binding which seems to require unique names

Upvotes: 0

Views: 1124

Answers (2)

tony
tony

Reputation: 2392

What I wanted can be accomplished with editor templates

Controller

   public class UsesEditorController : Controller
    {
        [HttpGet]
        public ActionResult Index()
        {
            return View(new SomeModel());
        }

        [HttpPost]
        public ActionResult Index(SomeModel model)
        {
            return View(model);
        }
    }

Model

public class Blob
{
    public string Name { get; set; }
    public string Address { get; set; }

    public Blob()
    {
        Name = string.Empty;
        Address = string.Empty;
    }
}

public class SomeModel
{
    public List<Blob> Blobs { get; set; }

    public SomeModel()
    {
        int count = 5;
        this.Blobs = new List<Blob>(count);

        for (int i = 0; i < count; i++)
        {
            this.Blobs.Add(new Blob());
        }
    }
}

View

@model MyProject.Areas.EditorTemplates.Models.SomeModel

@using (Html.BeginForm())
{
    for (int i = 0; i < Model.Blobs.Count; i++)
    {       
        @Html.EditorFor(m => m.Blobs[i], "CustomEditorForBlob");
    }
    <input type="submit" value="Send data back" />
}

And Editor, which can be anywhere in the view folder as I'm referring to it directly

@model MyProject.Areas.EditorTemplates.Models.Blob

@Html.TextBoxFor(m => m.Name)

@Html.TextBoxFor(m => m.Address)

This renders with ids like:

<input class="k-textbox" id="Blobs_1__Name" name="Blobs[1].Name" ...

So this gives me

  • List item
  • a repeating structure, just like UserControls in Asp.Net
  • The editor template only refers to the Blob class, it has no knowledge of the SomeModel class
  • Binding works (tested it)

Upvotes: 1

Jason Nesbitt
Jason Nesbitt

Reputation: 740

It looks to me like what you are trying to accomplish is unique IDs for your inputs, and you certainly don't need a partial to do this. You can output your text box inside your for loop like the following:

@Html.TextBoxFor(x => x.Somethings[i].TheProperty)

This will generate a unique id something like id="Somethings_1_TheProperty". If you don't like that id, you can certainly make your own with something like this:

@Html.TextBoxFor(x => x.Somethings[i].TheProperty, new {id="id" + (i+1)})

Upvotes: 0

Related Questions