I'm just venturing out into the world of MVC (v4) and I'm having real trouble getting the actual selected values of a list of radiobutton lists. I'm pulling the data from an Umbraco database (but I guess the principle of what I'm trying to do will be the same) where there are list of questions with each question having a list of answers. I'll post everything that I've done so far in the hope that someone more intelligent than I could point me in the right direction:
Here's my content structure
My Model
namespace ICASolution.Models
{
public class MultipleChoiceViewModel
{
public int iQuestionID { get; set; }
public string zQuestionTitle { get; set; }
public string zQuestionText { get; set; }
public List<Answers> lAnswers { get; set; }
}
public class Answers
{
public int iAnswerID { get; set; }
public string zAnswerText { get; set; }
public bool bCorrect { get; set; }
public string selectedAnswer { get; set; }
}
}
My surface controller:
namespace ICASolution.Controllers
{
public class MultipleChoiceSurfaceController : SurfaceController
{
//
// GET: /MultipleChoiceSurface/
//public ActionResult Index()
//{
// return PartialView("MultipleChoice", new MultipleChoiceViewModel());
//}
[HttpPost]
public ActionResult Grade(MultipleChoiceViewModel model)
{
return RedirectToCurrentUmbracoPage();
}
public ActionResult Index()
{
var TestPage = Umbraco.Content(CurrentPage.Id);
var questions = new List<MultipleChoiceViewModel>();
foreach (var child in TestPage.Children)
{
var questionid = child.Id;
var questiontitle = child.GetPropertyValue("questionTitle");
var questiontext = child.GetPropertyValue("questionText");
questions.Add(new MultipleChoiceViewModel { iQuestionID = questionid, zQuestionTitle = questiontitle, zQuestionText = questiontext, lAnswers = answerList(questionid) });
}
return PartialView("MultipleChoice", questions);
}
public List<Answers> answerList(int iMyQuestionID)
{
var questionPage = Umbraco.Content(iMyQuestionID);
var answers = new List<Answers>();
foreach(var child in questionPage.Children)
{
answers.Add(new Answers { iAnswerID = child.Id, zAnswerText = child.GetPropertyValue("answerTitle"), bCorrect = child.GetPropertyValue("correctAnswer") });
}
return answers;
}
}
}
and finally my partial:
#model IEnumerable<ICASolution.Models.MultipleChoiceViewModel>
<div class="ethicsTestContainer">
<div class="col-md-12">
<div class="col-md-12 noRPadding">
#using (Html.BeginUmbracoForm<ICASolution.Controllers.MultipleChoiceSurfaceController>("Grade")) {
foreach (var item in Model)
{
<div class="form-group">
<p><strong>#item.zQuestionTitle</strong></p>
<p>#item.zQuestionText</p>
#{
foreach (var answerItem in item.lAnswers)
{
<div class="radio radio-danger">
#Html.RadioButton(answerItem.iAnswerID.ToString(), answerItem.iAnswerID, new { #type = "radio", #id = answerItem.iAnswerID, #name = item.iQuestionID })
#*<input type="radio" name="#item.iQuestionID" id="#answerItem.iAnswerID" value="option1">*#
<label for="#answerItem.iAnswerID">
#answerItem.zAnswerText <span> </span>#answerItem.bCorrect
</label>
</div>
}
}
</div>
}
<div class="col-sm-8 col-sm-push-2">
<button type="submit" class="btn btn-default btn-block">CLICK HERE TO COMPLETE YOUR ETHICS TEST</button>
</div>
}
</div>
</div>
</div>
Everything renders fine when displayed to the user:
But I just can't work out how to get the selections that the user has made on the HTTPPOST (basically I need to count the amount of correct answers that they have made).
Your problem is that you are generating the controls for MultipleChoiceViewModel in a foreach loop with generates duplicate name attributes which cannot be bound to a collection (they do not include indexers) and duplicate id attributes which is invalid html. You need to generate the controls in a for loop (or use a custom EditorTemplate for type of MultipleChoiceViewModel)
You also need to move the selectedAnswer property to MultipleChoiceViewModel (not in selectedAnswer)
Using a for loop (the model must be IList<MultipleChoiceViewModel>)
for(int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => m[i].iQuestionID) // for post back
#Html.DisplayFor(m => m[i].zQuestionTitle)
...
foreach(var item in Model[i].lAnswers)
{
#Html.RadioButtonFor(m => m[i].selectedAnswer, item.iAnswerID, new { id = item.iAnswerID })
<label for="#item.iAnswerID">#item.zAnswerText</label>
}
}
To use an EditorTempate, create a partial view in /Views/Shared/EditorTemplates named MultipleChoiceViewModel.cshtml
#model yourAssembly.MultipleChoiceViewModel
#Html.HiddenFor(m => m.iQuestionID)
#Html.DisplayFor(m => m.zQuestionTitle)
...
foreach(var item in Model.lAnswers)
{
#Html.RadioButtonFor(m => m.selectedAnswer, item.iAnswerID, new { id = item.iAnswerID })
<label for="#item.iAnswerID">#item.zAnswerText</label>
}
and then in the main view,replace the for loop with
#Html.EditorFor(m => m)
The EditorFor() method will generate the html based on the template for each item in the collection.
Side notes: RadioButtonFor() generates type="radio" so adding a html for #type = "radio" is pointless. And NEVER override the name attribute when using html helpers
You can create the radio buttons using below code:
<div class="mt-radio-inline">
<label class="mt-radio">
<input type="radio" name="q1" value="q1_Chart"> Chart
<span></span>
</label>
<label class="mt-radio">
<input type="radio" name="q1" value="q1_AnySize"> Any Size
<span></span>
</label>
</div>
And get the selected radio button value from code given below:
string q = form["q1"];
In above code form is the object of FormCollection
This will gives you a string of the selected radio button from a group.
Related
Model:
public class TaxCertificateMailing
{
public IList<Report> SelectReports { get; set; }
public class Report
{
public string Text { get; set; }
public bool Selected { get; set; }
}
}
View:
#model LandNav.Areas.Reports.Models.TaxCertificateMailing
#{
ViewData["Title"] = "Tax Certificate Mailing List";
}
#using (Html.BeginForm("TaxCertificateMailing", "Reports", FormMethod.Post, new { id = "reportForm", #class = "report-form col-9" }))
{
<!--Start of the form body-->
<div class="row">
<div class="col-12">
<label><b>Select the report to run:</b></label><br />
#for (var x = 0; x < Model.SelectReports.Count; x++)
{
<input type="radio" asp-for="SelectReports" name="#reports" value="#Model.SelectReports[x].Selected" />
<input type="hidden" asp-for="SelectReports[x].Text"/>
<b>#Model.SelectReports[x].Text</b>
}
</div>
</div>
...
Controller:
[HttpPost]
public ActionResult TaxCertificateMailing(
//IFormCollection form
TaxCertificateMailing TCM
)
{
return View();
}
When the form is posted the SelectReports IList has a count of 0. What is the best way to handle posting a radio button group using .net core?
The name attribute of the input field should be #Model.SelectReports[x].Selected.
Use the code below for the for loop;
#for (var x = 0; x < Model.SelectReports.Count; x++)
{
<input type="radio" asp-for="SelectReports" name="#Model.SelectReports[x].Selected" value="#Model.SelectReports[x].Selected" />
<input type="hidden" asp-for="SelectReports[x].Text"/>
<b>#Model.SelectReports[x].Text</b>
}
Assuming only one value is selected at a time (which is how radio buttons are intended to be used), you have some issues with your models. I'd suggest this:
public class TaxCertificateMailing
{
public TaxCertificateMailing()
{
Reports = new HashSet<Report>();
}
public int SelectedReportID { get; set; }
public ICollection<Report> Reports { get; set; }
}
public class Report
{
public string Text { get; set; }
public int ID { get; set; }
}
This assumes you're pulling these from some sort of database - change the identifier to whatever makes sense, updating SelectedReportID's type to match.
Then, your view would look something like this:
<form asp-action="TaxCertificateMailing" asp-controller="Reports" method="post" id="reportForm" class="report-form col-9">
<fieldset>
<legend>Select the report to run:</legend>
#foreach (var report in Model.Reports)
{
<div class="form-group form-check">
<input type="radio" asp-for="SelectedReportID" id="report-#(report.ID)" value="#report.ID" class="form-check-input" />
<label for="report-#(report.ID)" class="form-check-label">#report.Text</label>
</div>
}
</fieldset>
</form>
I'm developping a website in ASP.NET MVC 4 and in one of my views, I've got 2 partial views :
<div id="timeDaysAndBeds">
<div id="timeAndBeds">
#Html.Action("TimeAndBedParameters")
</div>
<div id="daysOff">
#Html.Action("DaysOff")
</div>
</div>
My problem occurs in the second partial view. First, here's my GET method :
[HttpGet]
public ActionResult DaysOff()
{
context = new SchedulingDataClassesDataContext();
List<DBDayOfWeekOff> listDaysOff = (from doff in context.DBDayOfWeekOff select doff).ToList();
DaysOffViewModel dovm = new DaysOffViewModel();
string[] tableDays = new string[]
{
"Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi","Dimanche"
};
List<DaysViewModel> listDays = new List<DaysViewModel>();
for (int i = 1; i <= tableDays.Length; i++)
{
DaysViewModel dvm = new DaysViewModel()
{
DayId = i,
DayName = tableDays[i - 1],
IsOff = false
};
dovm.DaysOff.Add(dvm);
}
foreach (DBDayOfWeekOff dayOff in listDaysOff)
{
dovm.DaysOff.ElementAt(dayOff.DayOfWeekNumber - 1).IsOff = dayOff.IsOff;
}
return PartialView(dovm);
}
And here's the View Models I'm using :
public class DaysViewModel
{
public int DayId { get; set; }
public string DayName { get; set; }
public bool IsOff { get; set; }
}
public class DaysOffViewModel
{
public List<DaysViewModel> DaysOff { get; set; }
public DaysOffViewModel()
{
DaysOff = new List<DaysViewModel>();
}
}
So, when I'm invoking my GET method, I'm getting my partial view eand everything seems to be okay. However, when I'm trying to call my POST method, I got an empty DaysOff list (count = 0). Here's my View and my POST method :
#model AstellasSchedulerV2.Models.DaysOffViewModel
#using (Html.BeginForm("DaysOff", "Home", FormMethod.Post, new { dovm = Model }))
{
<fieldset id="fsDaysOff">
<legend>Jours de fermeture</legend>
#foreach (AstellasSchedulerV2.Models.DaysViewModel dvm in Model.DaysOff)
{
<div class="editor-label">
#dvm.DayName
</div>
<div class="editor-field">
#Html.CheckBoxFor(d => dvm.IsOff)
</div>
}
<input id="registerDayOffBtn" type="submit" name="Enregistrer" value="Enregistrer" />
</fieldset>
}
And my POST mehtod :
[HttpPost]
public ActionResult DaysOff(**DaysOffViewModel dovm**=> the List "DaysOff" has no item at all)
{
//some code
}
As I said, in my POST mehtod gets a DaysOffViewModel which has an empty list. What could it be?
Instead for each loop use for loop like this:
#for (int i=0; i<Model.DaysOff.Count; i++)
{
<div class="editor-label">
#Model.DaysOff[i].DayName
</div>
<div class="editor-field">
#Html.CheckBoxFor(d => Model.DaysOff[i].IsOff)
</div>
}
I've got a viewmodel for a page where fields are combined into fieldsets.
The VM looks like this:
public class FieldsetVM
{
public Int64 ID { get; set; }
public string Name { get; set; }
[Display(Name = "Available Fields")]
public ICollection<SelectListItem> AvailableFields { get; set; }
[Display(Name = "Current Fields")]
public ICollection<SelectListItem> UsedFields { get; set; }
public FieldsetVM(int id, string name, List<Field> availFields, List<Field> usedFields)
{
this.ID = id;
this.Name = name;
this.AvailableFields = new List<SelectListItem>();
foreach (Field field in availFields)
this.AvailableFields.Add(new SelectListItem { Text = string.Format("{0} ({1})", field.Name, field.FieldType.ToString()), Value = field.FieldID.ToString() });
this.UsedFields = new List<SelectListItem>();
foreach (Field field in usedFields)
this.UsedFields.Add(new SelectListItem { Text = string.Format("{0} ({1})", field.Name, field.FieldType.ToString()), Value = field.FieldID.ToString() });
}
public FieldsetVM()
{
}
}
Get in the controller looks like this:
[HttpGet]
public ActionResult Create()
{
FieldsetVM vm = new FieldsetVM(0, "", uw.FieldRepo.Get().ToList(), new List<Field>());
return View(vm);
}
Relevant piece of the view looks like this:
<div class="col-md-3 col-xs-6">
<div class="editor-label">
#Html.LabelFor(m => m.AvailableFields)
</div>
<div class="editor-field">
#Html.ListBoxFor(m => m.AvailableFields, Model.AvailableFields)
</div>
<button type="button" onclick="moveSelected('AvailableFields','UsedFields');">Move Selected</button>
</div>
<div class="col-md-3 col-xs-6">
<div class="editor-label">
#Html.LabelFor(m => m.UsedFields)
</div>
<div class="editor-field">
#Html.ListBoxFor(m => m.UsedFields, Model.UsedFields)
</div>
<button type="button" onclick="moveSelected('UsedFields','AvailableFields');">Remove Selected</button>
</div>
A tiny bit of JavaScript wires up the two listboxes:
function moveSelected(firstSelectId, secondSelectId) {
$('#' + firstSelectId + ' option:selected').appendTo('#' + secondSelectId);
$('#' + firstSelectId + ' option:selected').remove();
}
And then I have a POST in the controller:
[HttpPost]
public ActionResult Create(FieldsetVM postedVm)
{
Fieldset fs = new Fieldset();
fs.Name = postedVm.Name;
if (fs.Fields == null)
fs.Fields = new List<Field>();
fs.Fields.Clear();
foreach (SelectListItem item in postedVm.UsedFields)
fs.Fields.Add(uw.FieldRepo.GetByID(item.Value));
uw.FieldsetRepo.Insert(fs);
return RedirectToAction("Index");
}
My expectation is that in the postedVm, we would be able to see the values the user selected into UsedFields. Instead, UsedFields and AvailableFields are ALWAYS blank when the user posts back to the HttpPost Create() action.
I'm trying to figure out why: Surely moving items between list boxes is a fairly common way to configure things? Shouldn't MVC take a look at the values in the generated and use them to populate the postedVm object?
EDIT Based on feedback from best answer, here is my revised Create/Post action.
[HttpPost]
public ActionResult Create(FieldsetVM postedVm, int[] UsedFields)
{
Fieldset fs = new Fieldset();
fs.Name = postedVm.Name;
fs.Fields = new List<Field>();
foreach (int id in UsedFields)
fs.Fields.Add(uw.FieldRepo.GetByID(id));
uw.FieldsetRepo.Insert(fs);
uw.Save();
return RedirectToAction("Index");
}
When you post the form, only the Ids for AvailableFields and UsedFields will be posted. If you have multiple values, then you'll get a comma seperated list of ids, so modelbinding will not be able to bind those posted Ids to FieldsetVM postedVm.
If you do something like public ActionResult Create(int[] availableFields, int[] usedFields) you should be able to get the selected Ids.
I have the following cshtml form
#using (Html.BeginForm(Html.BeginForm("Create", "UserRole", Model, FormMethod.Post)))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Role</legend>
<div class="editor-label">
#Html.Label(Model.User.UserName)
</div>
<div class="editor-field">
#Html.CheckBoxList(Model.CheckboxList)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
And I wish to get the Model.CheckboxList selected Items in my action.
I have the following Create Action in my Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserRoleViewModel userRoleViewModel)
{
if (ModelState.IsValid)
{
//_context.Role.Add(role);
//_context.SaveChanges();
//return RedirectToAction("Index");
}
return View(viewModel);
}
However the viewModel.CheckboxList is 0.
How can I pass the selected values of the checkboxlist, and also the Model.User to the Controller Action?
My ViewModel looks like this :-
public User User { get; set; }
public IEnumerable<Role> RoleList { get; set; }
public List<UserRoleViewModel> UserList { get; set; }
public IEnumerable<SelectListItem> CheckboxList { get; set; }
public UserRoleViewModel()
{
}
public UserRoleViewModel(User user, IEnumerable<Role> roleList )
{
User = user;
RoleList = roleList;
}
Thanks for your help and time!
UPDATE ----------- After reading this post enter link description here, I tried to adapt my code to follow the example, but I am still finding problems with this updated code.
Now I have the following :-
cshtml :-
#model IEnumerable<MvcMembership.ViewModels.RoleCheckboxListViewModel>
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
Views/Role/EditorTemplates/RoleCheckboxListViewModel.cshtml
#model MvcMembership.ViewModels.RoleCheckboxListViewModel
#Html.HiddenFor(x => x.RoleId)
#Html.HiddenFor(x => x.RoleName)
<div>
#Html.CheckBoxFor(x => x.Checked)
#Html.LabelFor(x => x.Checked, Model.RoleName)
</div>
ViewModels :-
public class RoleCheckboxListViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public bool Checked { get; set; }
}
and the controller action is as follows :-
public ActionResult Create(int? uid)
{
var checkBoxList = new[]
{
new RoleCheckboxListViewModel() {
RoleId = "1", Checked = true, RoleName = "item 1" },
new RoleCheckboxListViewModel() {
RoleId = "2", Checked = true, RoleName = "item 2" },
new RoleCheckboxListViewModel() {
RoleId = "3", Checked = true, RoleName = "item 3" },
};
return View(checkBoxList);
}
The problem I have now is that on the Create.cshtml. I cannot see the checkboxlist, but only 123 displayed as well as the OK button.
Any help would be very much appreciated cause I am at a dead end at the moment.
I've accomplished this with the following parts:
1) A view model for the child element that adds the bool property that will represent whether or not the checkbox is checked in the View later... ie:
public class CategoryViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public bool Assigned { get; set; }
}
2) A view model for the parent element that adds a collection property for this new child element view model, ie:
public class ManufacturerViewModel
{
public Manufacturer Manufacturer { get; set; }
public IList<CategoryViewModel> Categories { get; set; }
public ManufacturerViewModel()
{
Categories = new List<CategoryViewModel>();
}
}
3) A service layer method for getting a list of all child elements, while also setting the bool property for each ("Assigned" in my example). To be used by your controller.
public IList<CategoryViewModel> GetCategoryAssignments(Manufacturer mfr)
{
var categories = new List<CategoryViewModel>();
foreach (var category in GetCategories())
{
categories.Add(new CategoryViewModel
{
ID = category.ID,
Name = category.Name,
Assigned = mfr.Categories.Select(c => c.ID).Contains(category.ID)
});
}
return categories;
}
4) A method for updating the parent item's collection based on your checkboxlist selections. To be used by your controller.
public void UpdateCategories(string[] selectedCategories, ManufacturerViewModel form)
{
if (selectedCategories == null)
selectedCategories = new string[] { };
var selectedIds = selectedCategories.Select(c => int.Parse(c)).ToList();
var assignedIds = form.Manufacturer.Categories.Select(c => c.ID).ToList();
foreach (var category in GetCategories())
{
if (selectedIds.Contains(category.ID))
{
if (!assignedIds.Contains(category.ID))
form.Manufacturer.Categories.Add(category);
}
else
{
if (assignedIds.Contains(category.ID))
form.Manufacturer.Categories.Remove(category);
}
}
}
5) Modifications to your Create/Edit view. ie:
#Html.EditorFor(model => model.Categories)
You must also add this so that the original assigned values are included in post data. You'll have to add a HiddenFor for each property that you have set as Required through validation.
for (int i = 0; i < Model.Manufacturer.Categories.Count; i++)
{
#Html.HiddenFor(model => model.Manufacturer.Categories[i].ID);
#Html.HiddenFor(model => model.Manufacturer.Categories[i].Name);
}
6) And finally, a new EditorTemplate for your child view model element. ie:
#model YourProject.ViewModels.CategoryViewModel
<li>
<input type="checkbox"
id="#string.Format("cb{0}{1}", #Model.Name, #Model.ID)"
name="selectedCategories" //Notice this name corresponds to string[] selectedCategories so that it can be extracted from the post data
value="#Model.ID"
#(Html.Raw(Model.Assigned ? "checked=\"checked\"" : "")) />
<label for="#string.Format("cb{0}{1}", #Model.Name, #Model.ID)">#Model.Name</label>
#Html.HiddenFor(model => model.ID)
</li>
Hopefully my own application gives you a better idea of how to solve this issue.
Store your selected value into the variable as follows, and pass it to an hidden field, then you can access it easily
var modelSelected = document.getElementById("modelName");
document.getElementById('selectedModel').value =
modelSelected.options[modelSelected.selectedIndex].text;
<input id="selectedModel" name="selectedModel" type="hidden" runat="server" />
I am currently working on an Edit function for my project and I cannot seem to get the View Model right to allow it to be passed back into the Controller from the View. The structure of the View Model is as such:
public class CreateUserViewModel : ICreateUserViewModel
{
#region Properties
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string SelectedUserType { get; set; }
public List<ICreateUserItemViewModel> UserTypes { get; set; }
public List<ICreateUserItemViewModel> Products { get; set; }
public List<ICreateUserItemViewModel> Languages { get; set; }
#endregion
#region Constructor
public CreateUserViewModel()
{
}
public CreateUserViewModel(List<Product> products, List<Language> languages)
{
Products = new List<ICreateUserItemViewModel>();
foreach (var prod in products)
{
var prodVM = new CreateUserItemViewModel
{
Name = prod.Name,
IsSelected = false,
ID = (int)prod.ID
};
Products.Add(prodVM);
}
Languages = new List<ICreateUserItemViewModel>();
foreach (var lang in languages)
{
var langVM = new CreateUserItemViewModel
{
Name = lang.Name,
IsSelected = false,
ID = (int)lang.ID
};
Languages.Add(langVM);
}
}
#endregion
}
The subclass ViewModel CreateUserItemViewModel:
public class CreateUserItemViewModel : ICreateUserItemViewModel
{
public string Name { get; set; }
public int ID { get; set; }
public bool IsSelected { get; set; }
}
I want this subclass to be represented in the view as a checkbox, so the user can choose to include it or not.
User Controller:
[HttpPost]
public ActionResult Create(CreateUserViewModel model)
{
if (ModelState.IsValid)
{
User newUser = new User();
newUser.UserName = model.UserName;
newUser.Password = model.Password;
newUser.Email = model.Email;
newUser.Products = model.Products; //Always NULL
When I put a break point on this part of the application the properties for username password and email are populated but Products and Languages are empty. I used Fiddler2 to watch what was being passed into the controller and this was the output:
UserName=asdasdsdasd&Password=asd&Email=asD%40asd.com&type.IsSelected=Admin
&prod.ID=1&prod.IsSelected=true&prod.IsSelected=false
&prod.ID=2&prod.IsSelected=false
&prod.ID=3&prod.IsSelected=false
&prod.ID=4&prod.IsSelected=false
&lang.ID=1&lang.IsSelected=true&lang.IsSelected=false
&lang.ID=2&lang.IsSelected=true&lang.IsSelected=false
&lang.ID=3&lang.IsSelected=false
&lang.ID=4&lang.IsSelected=false
&lang.ID=5&lang.IsSelected=false
&lang.ID=6&lang.IsSelected=false
&lang.ID=7&lang.IsSelected=false
&lang.ID=8&lang.IsSelected=false
&lang.ID=9&lang.IsSelected=false
&lang.ID=10&lang.IsSelected=false
&lang.ID=11&lang.IsSelected=false
&lang.ID=12&lang.IsSelected=false
&lang.ID=13&lang.IsSelected=false
&lang.ID=14&lang.IsSelected=false
&lang.ID=15&lang.IsSelected=false
&lang.ID=16&lang.IsSelected=false
&lang.ID=17&lang.IsSelected=false
&lang.ID=18&lang.IsSelected=false
&lang.ID=19&lang.IsSelected=false
A nugget of the code for the Create View is:
<div class="editor-label">
#Html.Label("User Products:")
</div>
<div class="editor-field">
#foreach (var prod in Model.Products)
{
#Html.Label(prod.Name)
#Html.HiddenFor(x => prod.ID)
#Html.CheckBoxFor(x => prod.IsSelected, new { name = prod.Name })
}
</div>
<div class="editor-label">
#Html.Label("User Languages:")
</div>
<div class="editor-field">
#foreach (var lang in Model.Languages)
{
#Html.Label(lang.Name)
#Html.HiddenFor(x => lang.ID)
#Html.CheckBoxFor(x => lang.IsSelected, new { name = lang.Name })
}
</div>
<p>
<input type="submit" value="Create" />
</p>
I have been working on this for quite a while and I am beginning to think what I am trying to do is not possible. I want it to return the CreateUserViewModel fully populated with all the values that the user has selected, but I just do not know how to achieve this.
Any ideas?
Use a for loop instead of a foreach.
#for (int i=0; i < Model.Products.Count; i++)
{
#Html.Label(prod.Name)
#Html.HiddenFor(model => model.Products[i].ID)
#Html.CheckBoxFor(model => model.Products[i].IsSelected, new { name = prod.Name })
}
Your property expression needs to contain enough information for the model binder to figure out how to bind the POST values to the model.
You could also try creating an Editor Template for ICreateUserItemViewModel and then changing your markup to the following.
#Html.EditorFor(model => model.Products)
As already mentioned in posted answer, it can be done by applying indexes but if the elements are non-sequential refer below article
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
Also refer below one for introduction to "Model Binding"
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Adding to the suggestion list, consider removing the CreateUserViewModel(List products, List languages) from the viewmodel. ViewModel should contain only properties and place additional logic (i.e, attaching UserTypes, etc., in your case) inside the controller.