2

I have a company model and it has employees list model as shown below

public class Company
{
    [Required]
    [Display(Name = "Company Name")]
    public string Name { get; set; }

    public List<EmployeeModel> Managers { get; set; }
}

and the Employee model as below

public class EmployeeModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}

and my parent view is as shown below

@using (Html.BeginForm("CompanySignupSuccess", "Home", FormMethod.Post, new { @class = "horizontal-form", role = "form", enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()

    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div>
        <div class="form-group">
            @Html.LabelFor(m => m.Name, new { @class = "control-label" })<span class="required">*</span>
            @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
        </div>

        <div class="form-group">
            <label for="file">Logo:</label>
            <input type="file" name="logo" id="logo"                    accept=".png,.jpg,.jpeg" /> 

        </div>
        <div id="managerList">

            <div id="editorRowsManagers">
                @foreach (var item in Model.Managers)
                {
                    @Html.Partial("DetailsView", item)
                }
            </div>

        </div>

        <div class="form-group">
            <input type="submit" class="btn btn-default pull-right" value="Send" />
        </div>
    </div>            
}

and the partial view shown below

@model yourAssembly.EmployeeModel
<div style="border:1px solid;margin:20px; padding:10px;">
    Manager Details:
    <div class="form-group">
        @Html.LabelFor(m => m.Name, new { @class = "control-label" })
        @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "control-label" }) <span class="required">*</span>
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Phone, new { @class = "control-label" }) <span class="required">*</span>
        @Html.TextBoxFor(m => m.Phone, new { @class = "form-control phoneno" })
    </div>

</div>

When I click on submit button, the model that goes to controller does have only Name and Logo properties filled in and the list object(Managers) is null, so I am not sure what is that I am missing here. BTW, I used the list of employees , because I would like add more employees by having a 'Add' button, and the Add button will just render another partial view.

public ActionResult CompanySignupSuccess(Company model)
{
    if (ModelState.IsValid)
    {
         //do some process
    }
    else
    {
        ModelState.AddModelError("", "Invalid Data entered.");
    }
    // If we got this far, something failed, redisplay form
    return View("CompanySignup", Model);
}

Can anyone please help me on how to send the child list object along with some properties on parent class when the Submit button is hit.

Bhaskar
  • 153
  • 2
  • 9

1 Answers1

5

You cannot use a partial to generate controls for a collection unless you pass the HtmlFieldPrefix (refer this answer for an example). However the correct way to do this is to use an EditorTemplate. Rename your partial to EmployeeModel.cshtml (i.e. to match the name of the class) and move it to the /Views/Shared/EditorTemplates folder (or /Views/YourControllerName/EditorTemplates folder).

Then replace your loop in the view with

@Html.EditorFor(m => m.Managers)

which will correctly generate the necessary name attributes for binding, i.e

<input ... name="Managers[0].Name" />
<input ... name="Managers[1].Name" />

etc (currently all your generating is duplicate name attributes (and duplicate id attributes which is invalid html)

Community
  • 1
  • 1
  • Thanks Stephen, I tried your suggestion but somehow the html didn't render properly. I am not sure how to insert an image in the comments section, I took a snapshot of what it rendered and my DevelperTools to show you. – Bhaskar Aug 28 '16 at 12:27
  • What did not render properly? The solution I showed you works fine. –  Aug 28 '16 at 12:30
  • The above is what rendered on screen upon changing the loop in main view as @Html.EditorFor(m => m.Managers) – Bhaskar Aug 28 '16 at 12:33
  • What? No where do you even have a `
  • ` element. And the fact you have generated `Managers.Index` with a `Guid` suggests you might be using `BeginCollectionItem` which you have not mentioned at all in your question or the code.
  • –  Aug 28 '16 at 12:37
  • I am sorry, am not expert in MVC, but I didn't use BeginCollectionItem anywhere – Bhaskar Aug 28 '16 at 12:43
  • BTW, do I need to change anything on my partial view after moving it to EditorTemplates? – Bhaskar Aug 28 '16 at 12:46
  • No. But its not possible that your generating that hidden input unless you have some other code you have not shown us (and I am assuming that you actually have `@model yourAssembly.EmployeeModel` at the top of that partial. If there is anything else in it, edit your question to show the all the code in that partial) –  Aug 28 '16 at 12:49
  • Oh sorry, yes I have that @model yourAssembly.EmployeeModel, will update my question – Bhaskar Aug 28 '16 at 12:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122034/discussion-between-bhaskar-and-stephen-muecke). – Bhaskar Aug 28 '16 at 12:57