Search code examples
.netajaxasp.net-mvcasp.net-mvc-4razor-2

Adding fields to a form using ajax


I'm adding items to a list of fields dynamically using ajax.

The problem is these items do not have the correct IDs or name so they don't get mapped correctly and are not reflected in the model when the form is submitted.

This is the structure of my code:

public class Main
{
    public IEnumerable<FieldSection> Sections { get; set; }
}

public class FieldSection
{
    public virtual IList<Field> Fields { get; set; }
}

public class Field
{
    [Required]
    public string Value { get; set; }
}

This is how I'm rendering Main:

<div class="field-sections">
    <div id="sections">
        @Html.EditorFor(model => model.Sections)
    </div>
    <p>
        <span class="add-section">Add Section</span>
    </p>
</div>

A Section has an EditorTemplate like this:

<div class="field-list">
    @Html.EditorFor(model => model.Fields)
</div>
<p>
    <span class="add-field">Add Field</span>
</p>

A Field has an EditorTemplate like this:

<div class="editor-field">
    @Html.LabelFor(model => model.Value)
    @Html.EditorFor(model => model.Value)
    @Html.ValidationMessageFor(model => model.Value)
</div>

If I have one section and two fields the last textbox for the Value field has an ID of Sections_0__Fields_1__Value and a name of Sections[0].Fields[1].Value.

I'm adding a Field by ajax by rendering my EditorTemplate Field.cshtml, returning it to the page and adding it to the section. However the ID will be Value and the name will be Value.

This is obviously incorrect. It seems that I could modify my HTML before I add it to the page using javascript to give it the correct ID/name, but that is a really awful solution. How can I get my view to render with the correct names and IDs? Or am I approaching this the wrong way?

EDIT

Render field code:

[HttpGet]
public string Field()
{
    return MvcRenderUtility.RenderToString(this, "EditorTemplates/TemplateField", new TemplateField());
}

And the render utility:

public static class MvcRenderUtility
{
    public static string RenderToString(Controller controller, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = controller.ControllerContext.RouteData.GetRequiredString("action");

        controller.ViewData.Model = model;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);
            return sw.GetStringBuilder().ToString();
        }
    }
}

Solution

  • I would suggest you add fields in the browser, maybe using jQuery, and retrieve values of the new fields in a post action method:

    public ActionResult Edit(MyModel model, FormCollection raw) {
    
      // scan the raw collection for new fields and add them to your model
    
    }