If your outputting a list of checkboxes using CheckBoxFor from within a loop and are having problems getting the checkboxes to bind back when submitting make sure you are looping with a for loop rather than a foreach loop. This is because looping through a collection with a foreach loop will output the same name for all checkboxes which will be based on the name of the iteration variable (not the particular item in the viewModel collection) in your foreach statement and the name of the bool property and thus MVC will not find anything to bind to.
You can have multiple non nested forms all posting to different action methods from different submit buttons, you can also have multiple submit buttons posting to the same form and hence action method. In an MVC action method which is posted to by multiple submit buttons, how does one tell which button was responsible for the form post? Two easy ways are outlined on stackoverflow which I’m reposting as is here just to add a bit of extra ‘commentary’. Author is highlighted in yellow.
- In your razor mark-up each submit button has a different name property. Since only the name of the button which caused the submit will be posted in the HTTP request header, in your action method you can check the Request.Form collection to see which submit button property name exists and take action accordingly. In this case you don’t have to change your action method signature and given that the value property of your submit buttons is insignificant to determining which button was pressed, all your submit buttons can have the same label/text if needs be.
- In your razor mark-up each submit button has the same property name but different value, since only the name (and significantly value) of the button which caused the submit will be posted in the HTTP request header, you can add a property to your action method signature for MVC to bind to and populate. You can then check the value of that property and take action accordingly. This is the more MVC (and perhaps elegant) way I guess as your using default model binder rather than checking form collections directly, personally however I prefer the approach above as you don’t have to change the action method signature and the button test is not based on some visible on page property which could matter in some scenarios.
http://stackoverflow.com/questions/19650345/mvc-razor-form-with-multiple-different-submit-buttons – Stackoverflow page with a number of solutions including the two above and an AJAX based one too.
When using ASP.NET MVC sometimes after a request viewModel properties you expect to be binded and populated are not. For HTTP GET action methods debugging why this might be is easy as the params are visible in your URL. For HTTP POST requests the name/value pairs are sent in the header so they are not as easy to review.
One could use Fiddler or the Chrome/IE developer tools to look at the raw name/values pairs being posted across from the view but the Visual Studio Locals window gives you access to this information too. Just set a breakpoint in your action method and examine the current request object in the Locals window as shown below, the particular property you want to look at is Form. In the example below we can see the raw name/value pair string isSelectedCity=4&Country=United+States
Quite often you have a scenario whereby a parent dropdown causes another element to be updated based on what is selected, but not on the value selected directly but rather another piece of information related to the option selected.
For example, you want to show a country name in a textbox based on the city a user has selected in a dropdown, but the option value of each city is its primary key, not its associated parent country name so you have no direct link between option selected and a country name.
There are a number of ways to proceed including hitting the server via Ajax on city dropdown change to get the associated country and outputting a client side lookup table of sorts. A simple approach however is just to output the secondary information (in the form of a data-* attribute) to each dropdown option along with its primary value which will give you a select box whose HTML is similar to below:
After this, extracting country name from the selected option is easy.
In MVC how we’d commonly output a select box would be using a DropDownListFor HTML helper control, however if you want to add data attributes to each option when using a DropDownListFor control…well, you can’t but you can ditch the DropDownListFor helper and just output your select box manually using a foreach in razor code. Sample Razor code which will allow you to do this is below, followed by JQuery which helps you to extract the data attribute from the selected dropdown item (source code is available below).
Overview of steps to add data-* annotations
- Manually output the select tag, with an id/class/name which you can use to hook a change event to using JQuery
- Output an option for each of your collection items, to include one or more data attributes (in this case data-country) and a test to check if something should be selected.
- In jQuery, add a change event to your dropdown and extract the value by using the :selected pseudo class and the data function for getting data-* attribute values.
- Note that even though you are manually outputting your select, you can still use strongly typed LabelFor, ValidationMessageFor (assuming the names match) etc. controls around your manually outputted dropdown.
- Note the use of @Html.NameFor when generating the name of the dropdown. You’ll want to use the name which matches the viewmodel property so binding occurs correctly. This helper avoids the need for hard coding.
- Watch out for the razor syntax to output text from within an if block. You will likely need the text tag or it’s alternative :@
WordPress messes up code so I just put the images in above, but you can see the source for a sample manually outputted dropdown on .Net Fiddle
In ASP.Net MVC a common technique when dropdowns and textboxes are required to be disabled but their values still need posting back is to include a hidden backing field corresponding to the same model property. In the case of CheckBoxFor the idea is the same, except there is one extra peculiarity with CheckBoxFor due to the fact that for this HMTL helper MVC renders a hidden text field of its own (along with the checkbox) which does not have the disabled attribute even if you have added it to the main CheckBoxFor HTML Helper. For example here is what is rendered for a disabled checkbox whose underlying bool property is set to true.
As nothing gets sent to the server if the checkbox is not checked, the binder has nothing to bind to so MVC always renders this hidden field and always sets its value to false. Due to the fact it appears after the checkbox, the true from the checkbox will bind first if the user has checked it, as MVC always binds to the first matched property. Therefore when we are dealing with disabled but checked checkboxes and we want to post the value, we need to ensure our hidden field appears before the @Html.CheckBoxFor hidden field. The first image below for example always bind as false (even though the checkbox is checked), while the second one binds are true.
I think this is a common enough problem, so hopefully the above helps.
Credit to Darin Dimitrov for his answer on stackoverflow which outlines the approach above, however crucially he does not mention the importance of having the backing field before the @Html.CheckBoxFor statement which is why I imagine some people mentioned in the comments that a hidden backing field did not work for them.