Robert M. Robert M. - 8 months ago 51
Javascript Question

A Partial View passing a collection using the Html.BeginCollectionItem helper

I made a small project to understand the answer from Stephen Muecke here: Submit same Partial View called multiple times data to controller?

Almost everything works. The javascript adds new fields from the Partial View, and I can tell they're bound to the model by the "temp" values inserted by the controller method for the partial view.

However, when I submit the new fields the AddRecord() method throws an exception showing that the model isn't getting passed in ("Object reference not set to an instance of an object").

Also, when I view the page source, the BeginCollectionItem helper is inserting a hidden tag as it should around the table in the main view that displays pre-existing records, but not around the new fields that the javascript adds.

What am I doing wrong? I'm pretty new at this so thanks for your patience!

My main view:

@model IEnumerable<DynamicForm.Models.CashRecipient>

@using (Html.BeginForm("AddDetail", "CashRecipients", FormMethod.Post))
<div id="CSQGroup">

<input type="button" value="Add Field" id="addField" onclick="addFieldss()" />

function addFieldss()
//alert("ajax call");
url: '@Url.Content("~/CashRecipients/RecipientForm")',
type: 'GET',
success:function(result) {
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hi there and greetings!");
newDiv.innerHTML = result;
var currentDiv = document.getElementById("div1");
error: function(result) {

My Partial View:

@model DynamicForm.Models.CashRecipient
@using HtmlHelpers.BeginCollectionItem

@using (Html.BeginCollectionItem("recipients"))
<div class="editor-field">
@Html.LabelFor(model => model.Id)
@Html.LabelFor(model => model.cashAmount)
@Html.TextBoxFor(model => model.cashAmount)
@Html.LabelFor(model => model.recipientName)
@Html.TextBoxFor(model => model.recipientName)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />

My model:

public class CashRecipient
public int Id { get; set; }
public string cashAmount { get; set; }
public string recipientName { get; set; }

In my controller:

public ActionResult AddDetail([Bind(Include = "Id,cashAmount,recpientName")] IEnumerable<CashRecipient> cashRecipient)
if (ModelState.IsValid)
foreach (CashRecipient p in cashRecipient) {
return RedirectToAction("Index");


return View(cashRecipient);

public ActionResult RecipientForm()
var data = new CashRecipient();
data.cashAmount = "temp";
data.recipientName = "temp";
return PartialView(data);

Answer Source

First start by creating a view model to represent what you want to edit. I'm assuming cashAmount is a monetary value, so therefore should be a decimal (add other validation and display attributes as required)

public class CashRecipientVM
    public int? ID { get; set; }
    public decimal Amount { get; set; }
    [Required(ErrorMessage = "Please enter the name of the recipient")]
    public string Recipient { get; set; }  

Then create a partial view (say) _Recipient.cshtml

@model CashRecipientVM
@using (Html.BeginCollectionItem("recipients"))
    @Html.HiddenFor(m => m.ID)
    @Html.LabelFor(m => m.Recipient)
    @Html.TextBoxFor(m => m.Recipient)
    @Html.ValidationMesssageFor(m => m.Recipient)
    @Html.LabelFor(m => m.Amount)
    @Html.TextBoxFor(m => m.Amount)
    @Html.ValidationMesssageFor(m => m.Amount)

and a method to return that partial

public PartialViewResult Recipient()
    return PartialView("_Recipient", new CashRecipientVM());

Then your main GET method will be

public ActionResult Create()
    List<CashRecipientVM> model = new List<CashRecipientVM>();
    .... // add any existing objects that your editing
    return View(model);

and its view will be

@model IEnumerable<CashRecipientVM>
@using (Html.BeginForm())
    <div id="recipients">
        foreach(var recipient in Model)
            @Html.Partial("_Recipient", recipient)
    <button id="add" type="button">Add</button>
    <input type="submit" value="Save" />

and will include a script to add the html for a new CashRecipientVM

var url = '@Url.Action("Recipient")';
var recipients = $('#recipients');
$('#add').click(function() {
    $.get(url, function(response) {

And the form will post back to

public ActionResult Create(IEnumerable<CashRecipientVM> recipients)