While trying RC1 I found out that the input values in forms for strongly typed views are not automatically filled for nested model objects.
I have the following class hierarchy and the first time a navigation is done to Home/Test the controller initializes the input values in the action method Test(). When the page is rendered (using View 1 below) the text
box for InputValue is populated but the text boxes for ListOfNestedClasses[0].InputValue and ListOfNestedClasses[1].InputValue are left empty. I initially thought that nested objects may not be supported but if the user enters something in those text boxes
and then click on Save the POST action method receives the input object filled properly with a list of 2 MyNestedClass.
Ultimately I was able to make it work using View 2 below but since the post method is able to create the correct object structure it gives me the feeling that this is a bug and not a limitation by design. Or am I doing
something wrong?
p.s. I must add that so far I really enjoy MVC! Thanks for the hard work.
// Classes
public
class
MyNestedClass{ public
String InputValue {
get;
set; }
}
public
class
MyInputClass{
public
String InputValue {
get;
set; } public
List<MyNestedClass> ListOfNestedClasses {
get;
set; }
}
// Actions
public
ActionResult Test(){
MyInputClass input =
new
MyInputClass();
input.InputValue = "1";
input.ListOfNestedClasses =
new
List<MyNestedClass>(){
new
MyNestedClass(){ InputValue =
"2" },
new
MyNestedClass(){ InputValue =
"3" }
};
return View(input);
}
[
AcceptVerbs(HttpVerbs.Post)]
public
ActionResult Test(MyInputClass input){
return View(input);
We have an internal work item tracking this issue. Essentially, the problem is that there is a mismatch between the syntaxes used by the DefaultModelBinder and ViewData.Eval(). The DefaultModelBinder expects ListOfNestedClasses[0].InputValue,
but ViewData.Eval() [and thus the HTML helpers] expects ListOfNestedClasses.0.InputValue.
Unfortunately this is unlikely to be fixed for v1.0. A workaround is to copy the ListOfNestedClasses into ViewData:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test(MyInputClass input){
for (int i = 0; i < input.ListOfNestedClasses.Length; i++) {
ViewData["ListOfNestedClasses[" + i.ToString() + "]"] = input.ListOfNestedClasses[i];
}
return View(input);
}
Marked as answer by levib on Feb 05, 2009 02:48 AM
The behavior didn't change from Beta to RC. If there's an error in the model and we have to redisplay the user input, e.g. the user typed "dog" when we expected an integer, then the code above will work since we're going to ModelState to get the user input,
and ModelState just used the entire field name verbatim as a key.
However, when there's not an error and we instead pull the value from ViewData, we use ViewData.Eval(), which has its own semantics for pulling data from collections. ViewData.Eval() uses a dot-syntax for pulling items from a collection rather than a bracket-syntax,
so it's unable to find any value for "people[0].FirstName" because it's expecting "people.0.FirstName".
Yep, I understand that because I've spent the last 10 minutes going through the mvc code and I've noticed that behvaiour (btw, when will you guys release pdb files so that I don't have to recompile the source and remove/add it to project in order to debug
the code?). I've also found Phil's code and he's doing the reverse, ie, fillling a list of objects from form's fields....
--
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu
The PDB files will be updated when CodePlex is updated with the RC Refresh bits. I don't have an ETA for that since the person who normally does it is out of the office, but it shouldn't be more than a few days. Thanks!
Ok glad to here that this is under control but a little sad that this isn't workingl Anyways...
Thank you for your suggestion but I think I prefer to have the view get the info from the model (as in my View2 above) than have the controller tweak how the data is passed to the view as it apprears to be a view problem/concern.
Also, I changed my view to use the dotted format to test what the effect would be but still it is not working ???
I forgot that ViewData.Eval() [and hence the HTML helpers] only supports some types of dictionaries for collections, not lists or arrays, so the
people.0.firstname example I gave above isn't a good example. Rather, if your model had a property
People that was an IDictionary<string, Person>, then you could do
people.abc.firstname, which would go to the People dictionary, look for the entry with key
abc, and pull the FirstName property.
Long story short - at the moment it's painful to try to use the HTML helpers for displaying data from a collection. If you insist on using the HTML helpers, I strongly recommend you use the method I showed above where you loop through the data and populate
ViewData manually. It's annoying, but it's the best we can do until the problem is resolved.
The PDB files will be updated when CodePlex is updated with the RC Refresh bits.
hum...I was unde the impression that MVC RC1 is already there, so I'm assuming that you're talking about the refresh you've released after the initial RC? btw, I'm assuming that they will only be available on your servers when you release the RTM version,
right?
--
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu
PascalN
0 Points
3 Posts
Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 05:33 AM|LINK
Hello,
While trying RC1 I found out that the input values in forms for strongly typed views are not automatically filled for nested model objects.
I have the following class hierarchy and the first time a navigation is done to Home/Test the controller initializes the input values in the action method Test(). When the page is rendered (using View 1 below) the text box for InputValue is populated but the text boxes for ListOfNestedClasses[0].InputValue and ListOfNestedClasses[1].InputValue are left empty. I initially thought that nested objects may not be supported but if the user enters something in those text boxes and then click on Save the POST action method receives the input object filled properly with a list of 2 MyNestedClass.
Ultimately I was able to make it work using View 2 below but since the post method is able to create the correct object structure it gives me the feeling that this is a bug and not a limitation by design. Or am I doing something wrong?
p.s. I must add that so far I really enjoy MVC! Thanks for the hard work.
// Classes
public class MyNestedClass{ public String InputValue { get; set; }}
public class MyInputClass{ public String InputValue { get; set; } public List<MyNestedClass> ListOfNestedClasses { get; set; }}
// Actions
public ActionResult Test(){ MyInputClass input = new MyInputClass(); input.InputValue = "1";input.ListOfNestedClasses =
new List<MyNestedClass>(){ new MyNestedClass(){ InputValue = "2" }, new MyNestedClass(){ InputValue = "3" }};
return View(input);}
[
AcceptVerbs(HttpVerbs.Post)] public ActionResult Test(MyInputClass input){ return View(input);}
// View 1<% using (Html.BeginForm()){%>
<%
= Html.TextBox("InputValue")%><br /><%
= Html.TextBox("ListOfNestedClasses[0].InputValue")%><br /><%
= Html.TextBox("ListOfNestedClasses[1].InputValue")%><br /> <input type="submit" value="Save" /><% } %>
// View 2
<% using (Html.BeginForm()){%>
<%
= Html.TextBox("InputValue")%><br /><%
= Html.TextBox("ListOfNestedClasses[0].InputValue", Model.ListOfNestedClasses[0].InputValue)%><br /><%
= Html.TextBox("ListOfNestedClasses[1].InputValue", Model.ListOfNestedClasses[1].InputValue)%><br /> <input type="submit" value="Save" /><% } %>
ASP.NET MVC htmlhelper
levib
Star
7702 Points
1099 Posts
Microsoft
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 07:33 PM|LINK
Hello Pascal - thanks for the report!
We have an internal work item tracking this issue. Essentially, the problem is that there is a mismatch between the syntaxes used by the DefaultModelBinder and ViewData.Eval(). The DefaultModelBinder expects ListOfNestedClasses[0].InputValue, but ViewData.Eval() [and thus the HTML helpers] expects ListOfNestedClasses.0.InputValue.
Unfortunately this is unlikely to be fixed for v1.0. A workaround is to copy the ListOfNestedClasses into ViewData:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Test(MyInputClass input){ for (int i = 0; i < input.ListOfNestedClasses.Length; i++) { ViewData["ListOfNestedClasses[" + i.ToString() + "]"] = input.ListOfNestedClasses[i]; } return View(input); }Luis Abreu
All-Star
25674 Points
5369 Posts
MVP
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 08:09 PM|LINK
Yep. it seems like a bug...I'm under the impression that it should work...
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu
Luis Abreu
All-Star
25674 Points
5369 Posts
MVP
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 08:11 PM|LINK
oh, levi already answered it...
wasn't this workin in the previous release? at least I was under the impression that there was a post by Phil explaining how to use lists of items...
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu
levib
Star
7702 Points
1099 Posts
Microsoft
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 08:16 PM|LINK
The behavior didn't change from Beta to RC. If there's an error in the model and we have to redisplay the user input, e.g. the user typed "dog" when we expected an integer, then the code above will work since we're going to ModelState to get the user input, and ModelState just used the entire field name verbatim as a key.
However, when there's not an error and we instead pull the value from ViewData, we use ViewData.Eval(), which has its own semantics for pulling data from collections. ViewData.Eval() uses a dot-syntax for pulling items from a collection rather than a bracket-syntax, so it's unable to find any value for "people[0].FirstName" because it's expecting "people.0.FirstName".
Luis Abreu
All-Star
25674 Points
5369 Posts
MVP
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 08:21 PM|LINK
Yep, I understand that because I've spent the last 10 minutes going through the mvc code and I've noticed that behvaiour (btw, when will you guys release pdb files so that I don't have to recompile the source and remove/add it to project in order to debug the code?). I've also found Phil's code and he's doing the reverse, ie, fillling a list of objects from form's fields....
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu
levib
Star
7702 Points
1099 Posts
Microsoft
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 02, 2009 10:33 PM|LINK
The PDB files will be updated when CodePlex is updated with the RC Refresh bits. I don't have an ETA for that since the person who normally does it is out of the office, but it shouldn't be more than a few days. Thanks!
PascalN
0 Points
3 Posts
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 03, 2009 02:58 AM|LINK
Ok glad to here that this is under control but a little sad that this isn't workingl Anyways...
Thank you for your suggestion but I think I prefer to have the view get the info from the model (as in my View2 above) than have the controller tweak how the data is passed to the view as it apprears to be a view problem/concern.
Also, I changed my view to use the dotted format to test what the effect would be but still it is not working ???
<%
= Html.TextBox("InputValue")%><br /><%
= Html.TextBox("ListOfNestedClasses.0.InputValue")%><br /> <%= Html.TextBox("ListOfNestedClasses.1.InputValue")%><br />levib
Star
7702 Points
1099 Posts
Microsoft
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 03, 2009 07:22 AM|LINK
I forgot that ViewData.Eval() [and hence the HTML helpers] only supports some types of dictionaries for collections, not lists or arrays, so the people.0.firstname example I gave above isn't a good example. Rather, if your model had a property People that was an IDictionary<string, Person>, then you could do people.abc.firstname, which would go to the People dictionary, look for the entry with key abc, and pull the FirstName property.
Long story short - at the moment it's painful to try to use the HTML helpers for displaying data from a collection. If you insist on using the HTML helpers, I strongly recommend you use the method I showed above where you loop through the data and populate ViewData manually. It's annoying, but it's the best we can do until the problem is resolved.
Luis Abreu
All-Star
25674 Points
5369 Posts
MVP
Re: Input value using HtmlHelper in form not automatically filled for nested objects
Feb 03, 2009 08:06 AM|LINK
hum...I was unde the impression that MVC RC1 is already there, so I'm assuming that you're talking about the refresh you've released after the initial RC? btw, I'm assuming that they will only be available on your servers when you release the RTM version, right?
Regards,
Luis Abreu
email: labreu_at_gmail.com
EN blog:http://msmvps.com/blogs/luisabreu