How to Pass Ienumerable List to Controller in MVC Including Checkbox State

How to pass IEnumerable list to controller in MVC including checkbox state?

Use a list instead and replace your foreach loop with a for loop:

@model IList<BlockedIPViewModel>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

@for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(x => x[i].IP)
@Html.CheckBoxFor(x => x[i].Checked)
</td>
<td>
@Html.DisplayFor(x => x[i].IP)
</td>
</tr>
}
<div>
<input type="submit" value="Unblock IPs" />
</div>
}

Alternatively you could use an editor template:

@model IEnumerable<BlockedIPViewModel>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.EditorForModel()
<div>
<input type="submit" value="Unblock IPs" />
</div>
}

and then define the template ~/Views/Shared/EditorTemplates/BlockedIPViewModel.cshtml which will automatically be rendered for each element of the collection:

@model BlockedIPViewModel
<tr>
<td>
@Html.HiddenFor(x => x.IP)
@Html.CheckBoxFor(x => x.Checked)
</td>
<td>
@Html.DisplayFor(x => x.IP)
</td>
</tr>

The reason you were getting null in your controller is because you didn't respect the naming convention for your input fields that the default model binder expects to successfully bind to a list. I invite you to read the following article.

Once you have read it, look at the generated HTML (and more specifically the names of the input fields) with my example and yours. Then compare and you will understand why yours doesn't work.

Pass List of Checkboxes into View and Pull out IEnumerable

You cannot bind to a collection using a foreach loop. Nor should you be manually generating your html, which in this case would not work because unchecked checkboxes do not post back. Always use the strongly typed html helpers so you get correct 2-way model binding.

You have not indicated what you models are, but assuming you have a User and want to select Roles for that user, then create view models to represent what you want to display in the view

public class RoleVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class UserVM
{
public UserVM()
{
Roles = new List<RoleVM>();
}
public int ID { get; set; }
public string Name { get; set; }
public List<RoleVM> Roles { get; set; }
}

In the GET method

public ActionResult Edit(int ID)
{
UserVM model = new UserVM();
// Get you User based on the ID and map properties to the view model
// including populating the Roles and setting their IsSelect property
// based on existing roles
return View(model);
}

View

@model UserVM
@using(Html.BeginForm())
{
@Html.HiddenFor(m => m.ID)
@Html.DisplayFor(m => m.Name)
for(int i = 0; i < Model.Roles.Count; i++)
{
@Html.HiddenFor(m => m.Roles[i].ID)
@Html.CheckBoxFor(m => m.Roles[i].IsSelected)
@Html.LabelFor(m => m.Roles[i].IsSelected, Model.Roles[i].Name)
}
<input type"submit" />
}

Then in the post method, your model will be bound and you can check which roles have been selected

[HttpPost]
public ActionResult Edit(UserVM model)
{
// Loop through model.Roles and check the IsSelected property
}

Pass IEnumerable to View and Display It

After researching and learning more about Razor, I figured the easiest way to accomplish this was to create a view model containing an IEnumerator<Cars>, a SelectedItem SelectedCar and OwnerModel Car. I then initialized the new view model in the controller and was able to pass along the data.

Passing IEnumerable property of model to controller post action- ASP MVC

The context of the model in the view is from the model being passed to it.
E.g. by passing

Model.Filter.CustomsitemDetails[i]

to your partial, you have changed the root from the Model object to your CustomiseDetails object. (so the name of the input will be "CustomsItemClassificationID" instead of "Filter.CustomsitemDetails[i].CustomsItemClassificationID", and so will not be rebound when posted, as will no longer match the property it is being bound to.

The correct way to do this is to use an Editor Template. This will preserve the model's origin. To do this, Create a folder called EditorTemplates under Views > Shared.

Copy your partial into it, and rename it to be called the name of your type. For example, if the type of Model.Filter.CustomsitemDetails[i] is CustomsitemDetail then your file under the editor template folder will be called CustomsitemDetails.cshtml.

Now, instead of

@Html.RenderPartial("CustomsItemDetailsUserControl", Model.Filter.CustomsitemDetails[i]);

Use

@Html.EditorFor(m => m.Filter.CustomitemDetails[i])

Alternatively, if you don't want to rename or move your file, you can specify it's current location instead:

@Html.EditorFor(m => m.Filter.CustomitemDetails[i], "~/Views/{controller}/CustomsItemDetailsUserControl.cshtml")

UPDATE

So I've learnt something new:

If a template whose name matches the templateName parameter is found in the controller's EditorTemplates folder, that template is used to render the expression. If a template is not found in the controller's EditorTemplates folder, the Views\Shared\EditorTemplates folder is searched for a template that matches the name of the templateName parameter. If no template is found, the default template is used. from MSDN.

So contrary to the second part of my answer, you do need to move your partial to

"~/Areas/TaxCalculation/Views/Home/EditorTemplates/CustomsItemDetailsUserControl.cshtml"

And use:

@Html.EditorFor(m => m.Filter.CustomitemDetails[i], "CustomsItemDetailsUserControl")

UPDATE 2

As per Stephen's comment - EditorFor() has an overload that accepts IEnumerable so you can just use

@Html.EditorFor(m => m.Filter.CustomitemDetails, "CustomsItemDetailsUserControl")

Or if you have an EditorTemplate named CustomitemDetails.cshtml located in the /Views/Shared/EditorTemplates/ folder:

@Html.EditorFor(m => m.Filter.CustomitemDetails)

pass value from MVC View to MVC Controller depending on checkbox checked

Your generating checkboxes with name="code" therefore you POST method signature needs to be

public ActionResult ShowRecords(int[] code)

The code parameter will contain an array of the values of the checked checkboxes.

Based on your edit using a view model, your view will need to use a for loop or custom EditorTemplate so that the name attributes are generated correctly for binding to a collection (refer Post an HTML Table to ADO.NET DataTable for more detail)

@for (int i = 0; i < Model.Count; i++)
{
<td>
@Html.CheckBoxFor(m => m[i].code) // include hidden input so its submitted
@Html.DisplayFor(m=> m[i].code)
</td>
....
<td>@Html.CheckBoxFor(m => m[i].isChecked)</td>
}

and the POST method signature would be

public ActionResult ShowRecords(List<Developer> model)

how can i pass (save) a list from a view to an controller?

Assuming you have IEnumerable<TRecord> as model bound to view, you can change foreach loop to for loop with index array of every properties inside model and set binding type to IList to match with controller input parameter:

@model IList<TRecord>

@using (Html.BeginForm())
{
// display names area

@for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
@Html.DisplayFor(item => item[i].Tid)
</td>
<td>
@Html.EditFor(item => item[i].Tname)
</td>
</tr>
}

// submit button area
}

The other way to post IEnumerable collection is creating editor template and put HTML helpers inside it, then use EditorForModel (see Darin Dimitrov's approach here).

Similar issues:

How to pass IEnumerable list to controller in MVC including checkbox state?

MVC passing IEnumerable<CustomVM> to Controller

Pass IEnumerable list to controller

MVC Pass IDs from view to controller from checkbox multiselection

There are probably other ways to do this, but I have done it like this previously - Create a new Checkbox class like:

public class CheckboxModel
{
//Value of checkbox
public int Value { get; set; }
//description of checkbox
public string Text { get; set; }
//whether the checkbox is selected or not
public bool IsChecked { get; set; }
}

Initialise static list of users, to give you an idea (you probably have to generate it dynamically):

ListOfUserID = new List<CheckboxModel>
{
new CheckboxModel { Value = 1, Text = "User1" },
new CheckboxModel { Value = 2, Text = "User2" },
new CheckboxModel { Value = 3, Text = "User3" }
};

Use this class in the view (for example in a loop):

@Html.CheckBoxFor(m => Model.ListOfUserID[i].IsChecked)@Model.ListOfUserID[i].Text
@Html.HiddenFor(m => Model.ListOfUserID[i].Value)
@Html.HiddenFor(m => Model.ListOfUserID[i].Text)

Then you have the text or value of the checkbox in Controller action when the form is posted.

How to use Html.CheckBox (list) with IEnumerable T with validation

You could create a custom html extensions class and overload the CheckBoxFor method like below. The method evaluates the metadata.Model to the value passed into it (like U.S. State). You can get the checkbox value/s from the FormCollection in the ControllerAction:

public ActionResult Edit(FormCollection formCollection) 
{
// Get the value(s)
string checkBox = formCollection["State"];

// perform validation
....
}

Example assumes a keyvaluepair generic list

<% foreach (var element in UnitedStatesDictionary())
{ %>
<%= Html.CheckBoxFor(model => model.State, null, element.Key) %><%= element.Value %><br />
<% } %>

HtmlExtensions.cs

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Routing;

public static class HtmlExtensions
{
/// <summary>
/// Checks the box for.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="html">The HTML.</param>
/// <param name="expression">The expression.</param>
/// <returns>Checkbox</returns>
public static MvcHtmlString CheckBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
return CheckBoxFor(html, expression, new RouteDirection());
}


/// <summary>
/// Checks the box for.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="html">The HTML.</param>
/// <param name="expression">The expression.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <returns>Checkbox</returns>
public static MvcHtmlString CheckBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{

return CheckBoxFor(html, expression, htmlAttributes, "");
}

/// <summary>
/// Checks the box for.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="html">The HTML.</param>
/// <param name="expression">The expression.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <param name="checkedValue">The checked value.</param>
/// <returns>Checkbox</returns>
public static MvcHtmlString CheckBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes, string checkedValue)
{

ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);

TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("type", "checkbox");
tag.Attributes.Add("name", metadata.PropertyName);
if (!string.IsNullOrEmpty(checkedValue))
{
tag.Attributes.Add("value", checkedValue);
}
else
{
tag.Attributes.Add("value", metadata.Model.ToString());
}

if (htmlAttributes != null)
{
tag.MergeAttributes(new RouteValueDictionary(htmlAttributes));
}

if (metadata.Model.ToString() == checkedValue)
{
tag.Attributes.Add("checked", "checked");
}
return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
}
}

While I'm at it, here's my list of United States to complete code:

/// <summary>
/// United States dictionary.
/// </summary>
/// <returns>List of United States</returns>
public static List<KeyValuePair<string, string>> UnitedStatesDictionary()
{
var arrList = new List<KeyValuePair<string, string>>();
arrList.Add(new KeyValuePair<string, string>("AL", "Alabama"));
arrList.Add(new KeyValuePair<string, string>("AK", "Alaska"));
arrList.Add(new KeyValuePair<string, string>("AZ", "Arizona" ));
arrList.Add(new KeyValuePair<string, string>("AR", "Arkansas" ));
arrList.Add(new KeyValuePair<string, string>("CA", "California" ));
arrList.Add(new KeyValuePair<string, string>("CO", "Colorado" ));
arrList.Add(new KeyValuePair<string, string>("CT", "Connecticut" ));
arrList.Add(new KeyValuePair<string, string>("DE", "Delaware" ));
arrList.Add(new KeyValuePair<string, string>("DC", "District Of Columbia" ));
arrList.Add(new KeyValuePair<string, string>("FL", "Florida" ));
arrList.Add(new KeyValuePair<string, string>("GA", "Georgia" ));
arrList.Add(new KeyValuePair<string, string>("HI", "Hawaii" ));
arrList.Add(new KeyValuePair<string, string>("ID", "Idaho" ));
arrList.Add(new KeyValuePair<string, string>("IL", "Illinois" ));
arrList.Add(new KeyValuePair<string, string>("IN", "Indiana" ));
arrList.Add(new KeyValuePair<string, string>("IA", "Iowa" ));
arrList.Add(new KeyValuePair<string, string>("KS", "Kansas" ));
arrList.Add(new KeyValuePair<string, string>("KY", "Kentucky" ));
arrList.Add(new KeyValuePair<string, string>("LA", "Louisiana" ));
arrList.Add(new KeyValuePair<string, string>("ME", "Maine" ));
arrList.Add(new KeyValuePair<string, string>("MD", "Maryland" ));
arrList.Add(new KeyValuePair<string, string>("MA", "Massachusetts" ));
arrList.Add(new KeyValuePair<string, string>("MI", "Michigan" ));
arrList.Add(new KeyValuePair<string, string>("MN", "Minnesota" ));
arrList.Add(new KeyValuePair<string, string>("MS", "Mississippi" ));
arrList.Add(new KeyValuePair<string, string>("MO", "Missouri" ));
arrList.Add(new KeyValuePair<string, string>("MT", "Montana" ));
arrList.Add(new KeyValuePair<string, string>("NE", "Nebraska" ));
arrList.Add(new KeyValuePair<string, string>("NV", "Nevada" ));
arrList.Add(new KeyValuePair<string, string>("NH", "New Hampshire" ));
arrList.Add(new KeyValuePair<string, string>("NJ", "New Jersey" ));
arrList.Add(new KeyValuePair<string, string>("NM", "New Mexico" ));
arrList.Add(new KeyValuePair<string, string>("NY", "New York" ));
arrList.Add(new KeyValuePair<string, string>("NC", "North Carolina" ));
arrList.Add(new KeyValuePair<string, string>("ND", "North Dakota" ));
arrList.Add(new KeyValuePair<string, string>("OH", "Ohio" ));
arrList.Add(new KeyValuePair<string, string>("OK", "Oklahoma" ));
arrList.Add(new KeyValuePair<string, string>("OR", "Oregon" ));
arrList.Add(new KeyValuePair<string, string>("PA", "Pennsylvania" ));
arrList.Add(new KeyValuePair<string, string>("RI", "Rhode Island" ));
arrList.Add(new KeyValuePair<string, string>("SC", "South Carolina" ));
arrList.Add(new KeyValuePair<string, string>("SD", "South Dakota" ));
arrList.Add(new KeyValuePair<string, string>("TN", "Tennessee" ));
arrList.Add(new KeyValuePair<string, string>("TX", "Texas" ));
arrList.Add(new KeyValuePair<string, string>("UT", "Utah" ));
arrList.Add(new KeyValuePair<string, string>("VT", "Vermont" ));
arrList.Add(new KeyValuePair<string, string>("VA", "Virginia" ));
arrList.Add(new KeyValuePair<string, string>("WA", "Washington" ));
arrList.Add(new KeyValuePair<string, string>("WV", "West Virginia" ));
arrList.Add(new KeyValuePair<string, string>("WI", "Wisconsin" ));
arrList.Add(new KeyValuePair<string, string>("WY", "Wyoming" ));
return arrList;
}


Related Topics



Leave a reply



Submit