0

I have a Fairly Complex Form that I need to post to my MVC controller.

Here is the View model which I initially pass to the view on creation:

public class EditViewModel
{
    public Service service { get; set; }
    public bool sms { get; set; }
    public bool email { get; set; }
    public string userId { get; set; }
}

Here is my View (simplified):

@model IList<Service_Monitor_Web_Interface.Models.ViewModels.EditViewModel>
@{
  ViewBag.Title = "Configure User Notifications";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@ViewBag.Title</h2>

@using (Html.BeginForm("Edit", "Users", FormMethod.Post, new { @class = "stdform stdform2", role = "form" }))
{
@Html.AntiForgeryToken()
<hr />

<p>
    <label><u> Service:</u> </label>
    <span class="field">
        <u>Notification Methods:</u>
    </span>
</p>


for (int i = 0; i < Model.Count; i++)
{
    <p>
        <label>@Model[i].service.Name</label>
        <span class="field">
            @Html.CheckBoxFor(model => model[i].sms)
            SMS &nbsp;&nbsp;
            @Html.CheckBoxFor(model => model[i].email)
            Email &nbsp;&nbsp;
        </span>
    </p>
}
<br clear="all" /><br />

<p class="stdformbutton">
    <button class="submit radius2">Save</button>
    <input type="reset" class="reset radius2" value="Reset Form" />
</p>
}

And here is my Action method in my controller:

    //
    // POST: /Users/Edit
    [HttpPost]
    public ActionResult Edit(IList<EditViewModel> viewModel)
    {
        return View(viewModel);
    }

How Can I bind my view model when receiving it on the controller? Currently when I debug the action method receives a ViewModel which looks like so:

enter image description here

How can I get service and userId not to be null?

Zapnologica
  • 22,170
  • 44
  • 158
  • 253

1 Answers1

2

Note that in your helpers' lambdas, say in model => service.sms right part (service.sms) formally is not derived from the left part (model). That causes all name attributes of resulting inputs to be the same, and gives you request parameters that you did not expect.

The standard practice is to use for instaed of foreach in loop cases. That way name attributes for resulting html are generated correctly:

for(int i=0; i<Model.Count; i++)
{
    <p>
        <label>@Model[i].service.Name</label>
        <span class="field">                
            @Html.CheckBoxFor(model => model[i].sms)
            SMS &nbsp;&nbsp;               
            @Html.CheckBoxFor(model => model[i].email)
            Email &nbsp;&nbsp;
        </span>
    </p>
}

Note that this requires Model to be of type implementing IList rather than IEnumerable.

Update. For other values, that do not have any UI for them, you can use hidden fields, so that they are not visible for the user and are nevertheless posted to the server:

<label>@Model[i].service.Name</label>
<span class="field">                
    @Html.CheckBoxFor(model => model[i].sms)
    SMS &nbsp;&nbsp;               
    @Html.CheckBoxFor(model => model[i].email)
    Email &nbsp;&nbsp;
    @Html.HiddenFor(mode => model[i].userId)
    @Html.HiddenFor(mode => model[i].service.Name)
    ...other field of service you want to be posted...
</span>
Andrei
  • 55,890
  • 9
  • 87
  • 108
  • It doesn't like your solution. !st error is in the for loop it says that `Operator > cannot be applied to operands of type int and method group` and then secondly in the checkbox `Cannot apply indexing with [] to an expression of type IEnumerable` – Zapnologica Feb 25 '14 at 12:21
  • 1
    @Zapnologica, oh yeah, forgot to mention - you need your model to be of `IList` type for this to work. since `IEnumerable` is a broader interface and does not support indexing. Basically you can just call `ToList()` when passing model to View, and adjust the View's type – Andrei Feb 25 '14 at 12:22
  • Do I then have to receive a IList viewModel in my action method? – Zapnologica Feb 25 '14 at 12:30
  • @Zapnologica, no, it should work without changing signature of the post-receiving action – Andrei Feb 25 '14 at 12:31
  • OMW You are amazing. Thank you thank you so much. You where really helpful and you saved me hours. Is there a reason that you are meant to user a for loop rather than a foreach? – Zapnologica Feb 25 '14 at 12:50
  • 1
    @Zapnologica, glad it helped. The reason I've tried to explain in the beginning of the answer briefly. You might want to inspect resulting html for `for` and `foreach` loops to understand what is going on. – Andrei Feb 25 '14 at 12:52