1

I have a view with a table that displays my model items. I've extracted the relevant portions of my view:

@model System.Collections.Generic.IEnumerable<Provision>

@using (Html.BeginForm("SaveAndSend", "Provision", FormMethod.Post))
{
    if (Model != null && Model.Any())
    {
        <table class="table table-striped table-hover table-bordered table-condensed">
            <tr>
                ...
                // other column headers
                ...
                <th>
                    @Html.DisplayNameFor(model => model.IncludeProvision)
                </th>
                ...
                // other column headers
                ...
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    ...
                    // other columns
                    ...
                    <td>
                        @Html.CheckBoxFor(modelItem => item.IncludeProvision)
                    </td>
                    ...
                    // other columns
                    ...
                </tr>
            }
        </table>
        <button id="save" class="btn btn-success" type="submit">Save + Send</button>
    }
    ...
}

This works fine and the checkbox values are displayed correctly in the view depending on the boolean value of the IncludeProvision field for the given model item.

As per Andrew Orlov's answer, I've modified the view and controller and the SaveAndSend() controller method is now:

[HttpPost]
public ActionResult SaveAndSend(List<Provision> provisions)
{
    if (ModelState.IsValid)
    {
        // perform all the save and send functions
        _provisionHelper.SaveAndSend(provisions);
    }
    return RedirectToAction("Index");
}

However, at this point the passed in model object is null.

Including the Provision model object for completeness:

namespace
{
    public partial class Provision
    {
        ...
        // other fields
        ...
        public bool IncludeProvision { get; set; }
    }
}

My question is, what is the best way to grab the checked/unchecked value from each checkbox and update the session IncludeProvision field for each model item when the 'SaveAndSend' button is clicked?

3
  • 3
    You should just have a HttpPost method and not a JavaScript redirect, then submit your model and you can then put your data in the session and do the redirect. Commented Aug 21, 2015 at 14:56
  • Try to avoid of checking model for null on view. It is controller job in your case. Commented Aug 21, 2015 at 23:44
  • @AndrewOrlov hmm I was just following ReSharper's suggested code refactor on this one, assuming it's not completely optimized to follow MVC best practices. Commented Aug 24, 2015 at 14:22

2 Answers 2

1

You cannot use a foreach loop to generate form controls for properties in a collection. It creates duplicate name attributes (in your case name="item.IncludeProvision") which have no relationship to your model and duplicate id attributes which is invalid html. Use either a for loop (you models needs to be IList<Provision>

for(int i = 0; i < Model.Count; i++)
{
  <tr>
    <td>....</td>
    <td>@Html.CheckBoxFor(m => m[i].IncludeProvision)<td>
  </tr>
}

or create an EditorTemplate for typeof Provision. In /Views/Shared/EditorTemplates/Provision.cshtml (note the name of the template must match the name of the type)

@model Provision
<tr>
  <td>....</td>
  <td>@Html.CheckBoxFor(m => m.IncludeProvision)<td>
</tr>

and in the main view (the model can be IEnumerable<Provision>)

<table>
  @Html.EditorFor(m => m)
</table>
Sign up to request clarification or add additional context in comments.

Comments

1

As @mattytommo said in comments, you should post your model to controller. It can be done with putting your checkbox inside a form. After clicking on button "Save and exit" all data from inputs inside this form will be serialized and sent to your controller where you can perform manipulations with session variables and so on. After that you can redirect wherever you like.

Model

public class YourModel
{
    ...
    public bool IncludeProvision { get; set; }
    ...
}

View

@model YourModel

...
@using (Html.BeginForm("SaveAndSend", "Test", FormMethod.Post))
{
    ...
    @Html.CheckBoxFor(model => model.IncludeProvision)
    ...
    <button type="submit">Save and send</button>
}
...

Controller

public class TestController : Controller
{
    ...
    [HttpPost]
    public ActionResult SaveAndSend(YourModel model)
    {
         if (ModelState.IsValid)
         {
             // Some magic with your data
             return RedirectToAction(...);
         }

         return View(model); // As an example
    }
    ...
}

6 Comments

Hmm my model in the view is of type List<Provision>, rather than Provision. Wrapping the table in a form with an HttpPost to my controller method with the following signature results in a null provisions object. public ActionResult SaveAndSend(List<Provision> provisions)
How did you generate your table ? Parse your model.List<Provision> with a foreach to create each <tr><td> and when you submit post, you will retrieve the model
Well, we've should see your view and model for more accurate answer.
@User.Anonymous That's exactly how I generated my table.
@AndrewOrlov updated my question with snippets of view, controller method and model code. Thanks for your help
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.