How does MVC decide which value to bind when there are multiple inputs with the same name?
How does MVC decide which value to bind when there are multiple inputs with the same name?
I have an edit page where several fields are conditionally disabled, based on the user's role. When the fields are disabled, their values are not posted to the server (as expected), which causes the ModelState to be invalid, as the values are required.
To get around this, I want to add Html.HiddenFor() for the fields; so that a value will still get posted (and so that it will retain those values if the View is returned). However, in the case that those fields are not disabled, I will then have both a TextBoxFor and a HiddenFor going to the same model property.
I have run a couple tests, and it appears that when this happens, the value of the first element on the form will be binded to the model, while the next one just gets ignored. If this is the case, then I should be able to just put the HiddenFor after the TextBoxFor, in which case the value of the hidden input will only be posted when the regular input is disabled.
@Html.TextBoxFor(m => m.FirstName)
@Html.HiddenFor(m => m.FirstName) @*Only gets binded to the model if the above text box is disabled*@
(There is some JavaScript that conditionally disabled the visible TextBox).
So two questions: 1) Is it documented that MVC binding will always work this way; can I safely have both of these fields?
And, 2) Is there a better approach to accomplishing this? I know that I can but the HiddenFor inside an @If statement so that it will only get created if the TextBox is disabled; but that is a lot of extra logic in the View that I'd like to avoid.
1 Answer
1
The DefaultModelBinder reads the values from the request in order and binds the first matching name/value pair and ignores subsequent matches (unless the property is IEnumerable). This is how the CheckBoxFor() method ensures a true or false value is always submitted to the controller (the method generates a checkbox with value="True" and a hidden input with value="False"), so you can safely add the hidden input after the textbox.
DefaultModelBinder
IEnumerable
CheckBoxFor()
true
false
value="True"
value="False"
One option you might consider rather than a disabled textbox, is to make it readonly, which means it will always submit a value, therefore you only need one input (and you can always style it to look disabled if that is what you want).
readonly
Forms post back the name/value pairs of their successful form controls in the order they appear in the DOM, and the
DefaultModelBinder (or specifically the FormValueProvider) reads then in that order– user3559349
Sep 13 '18 at 13:55
DefaultModelBinder
FormValueProvider
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Thanks; given that the built-in CheckBoxFor works this way; it seems like a good solution for me. When the elements are siblings; it's clear which value would be found first. But if they were in different nested areas; it might not be so clear. I'm curious now how the order of the request body is determined.
– GendoIkari
Sep 13 '18 at 13:48