This is an area which I hope gets quite a bit of attention from the MVC team. MvcContrib has had the NameValueDeserializer for a while now and I still use it because it handles arrays/lists very well.
As for how to do this with model binders currently, well, you have full access to the form collection so you can get all the keys, look for ones which contain "prefix.Address[X]" where X is some value unique to an Address, look for the model binder for the
Address type, and call GetValue passing in the string you found as the modelName.
var prefixRegex = new Regex( "^contact\.Address\[[\d]+\]" ); // beings with "contact.Address[", followed by some digits, followed by "]"
var addressPrefixes = controllerContext.HttpContext.Request.Form.AllKeys
.Select( s => prefixRegex.Match( s ) )
.Where( m => m != Match.Empty )
.Select( m => m.Value )
.Distinct();
var binder = ModelBinders.GetBinder( typeof(Address) );
contact.Addresses = new List<Address>();
foreach(var addressPrefix in addressPrefixes) { var address = (Address) binder.GetValue( controllerContext, addressPrefix, typeof(Address), modelState ); contact.Addresses.Add( address ); }
(This code is just off the top of my head so expect it to fail. lol) What this should do is, say you have several form fields with names like...
and try to use the model binder for Address which these strings as the modelName. For example, if the ComplexModelBinder was setup as the model binder for the Address type, it would correctly fill the properties of the Address object with the form values
because it looks for modelName + "." + propertyName.
Hope this gets you started.
Marked as answer by dines on Sep 16, 2008 03:44 PM
but I still cannot get it to work... I took a closer look at scottgu's article and the "LookUpValue"-Method... but I have still problems with the insert and edit functionality for complex object...[:'(]
after amcomplishing that basic input scenario I will work myself to a complexer form where it is possible to add even more emails and phones and addresses... may with some javascript....
but first things first... I need to understand concepts...
and the same for Phones. remember they can have the same name but not the same id! ConvertStringToEmail just takes a string and outputs an Email as the name suggests.
As for addresses you can use my earlier approach of using a regular expression to find all of the form keys beginning with "contact.Address[X]" and calling the model binder for Address passing in that prefix as the modelName.
NOTE: when accessing the Form collection, you should always prepend your keys with
modelName + "." this helps the view data evaluators and model binders work in sync. so if you have a property on your model called Contact, and you name all your fields "contact.X", and you POST the form to an action which has an argument of type Contact
called contact, the argument will automatically be populated correctly.
I finally managed it... I mixed the approaches but your hint about the naming convention for the controls and the
"modelName+"."" made it... thanks again...
dines
Member
582 Points
136 Posts
ModelBinder with Types that contains List<T>
Sep 07, 2008 12:27 PM|LINK
Hi,
I have a question according custom ModelBinder (IModelBinder). I found nice article for basic scenarios like
http://blog.maartenballiauw.be/post/2008/08/29/Using-the-ASPNET-MVC-ModelBinder-attribute.aspx
http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx
These are great articles! They discuss the ModelBinder approach very deep but only for types which have basic Properties (string, int, etc).
What if you have a type that contains a List<T> (T = any other object)...
Like
a contact that has many addresses or many phone numbers or many email-addresses.
Contact
-> string Name
-> string LastName
-> List<Adress> Adresses
-> List<Telphone> Phones
-> List<Email> Emails
How can I address scenarios like this
tgmdbm
Contributor
4392 Points
883 Posts
ASPInsiders
MVP
Re: ModelBinder with Types that contains List<T>
Sep 08, 2008 03:42 AM|LINK
This is an area which I hope gets quite a bit of attention from the MVC team. MvcContrib has had the NameValueDeserializer for a while now and I still use it because it handles arrays/lists very well.
As for how to do this with model binders currently, well, you have full access to the form collection so you can get all the keys, look for ones which contain "prefix.Address[X]" where X is some value unique to an Address, look for the model binder for the Address type, and call GetValue passing in the string you found as the modelName.
var addressPrefixes = controllerContext.HttpContext.Request.Form.AllKeys .Select( s => prefixRegex.Match( s ) ) .Where( m => m != Match.Empty ) .Select( m => m.Value ) .Distinct(); var binder = ModelBinders.GetBinder( typeof(Address) );(This code is just off the top of my head so expect it to fail. lol) What this should do is, say you have several form fields with names like...
contact.Address[1].Street1
contact.Address[1].PostCode
contact.Address[1].Contry
contact.Address[2].Street1
contact.Address[2].PostCode
contact.Address[2].Contry
contact.Address[3].Street1
contact.Address[3].PostCode
contact.Address[3].Contry
it should find the following 3 strings
contact.Address[1]
contact.Address[2]
contact.Address[3]
and try to use the model binder for Address which these strings as the modelName. For example, if the ComplexModelBinder was setup as the model binder for the Address type, it would correctly fill the properties of the Address object with the form values because it looks for modelName + "." + propertyName.
Hope this gets you started.
dines
Member
582 Points
136 Posts
Re: ModelBinder with Types that contains List<T>
Sep 12, 2008 10:03 PM|LINK
thank you very much for your reply,....
but I still cannot get it to work... I took a closer look at scottgu's article and the "LookUpValue"-Method... but I have still problems with the insert and edit functionality for complex object...[:'(]
maybe some more help can get me started...
tgmdbm
Contributor
4392 Points
883 Posts
ASPInsiders
MVP
Re: ModelBinder with Types that contains List<T>
Sep 12, 2008 10:56 PM|LINK
what are the form values? how do they map to properties in your object?
dines
Member
582 Points
136 Posts
Re: ModelBinder with Types that contains List<T>
Sep 12, 2008 11:08 PM|LINK
I want to have something like this
for example
a form with
Salutation
FirstName
LastName
Email
Phone
Street
Zip
City
State
Country
My Model looks like this
Contact
->Salutation
-> FirstName
->LastName
->List<Email>Emails
->List<Phones>Phones
->List<Address>Address
after amcomplishing that basic input scenario I will work myself to a complexer form where it is possible to add even more emails and phones and addresses... may with some javascript....
but first things first... I need to understand concepts...
thanks for helping...
tgmdbm
Contributor
4392 Points
883 Posts
ASPInsiders
MVP
Re: ModelBinder with Types that contains List<T>
Sep 12, 2008 11:38 PM|LINK
what is List<Email>? do you mean List<string>? or can you convert from a string to an Email? same for Phone?
you'll probaly want to name the form fields something like:
contact.Salutation
contact.FirstName
contact.LastName
contact.Emails
contact.Phones
contact.Address[0].Street
contact.Address[0].Zip
contact.Address[0].City
contact.Address[0].State
contact.Address[0].Country
assuming an Email is a string (or you can convert strings to Emails) then you can have the following:
<input name="contact.Emails" />
<input name="contact.Emails" />
<input name="contact.Emails" />
contact.Emails = request.Form.GetValues( modelName + ".Emails" ).Select( ConvertStringToEmail ).ToList();
and the same for Phones. remember they can have the same name but not the same id! ConvertStringToEmail just takes a string and outputs an Email as the name suggests.
As for addresses you can use my earlier approach of using a regular expression to find all of the form keys beginning with "contact.Address[X]" and calling the model binder for Address passing in that prefix as the modelName.
NOTE: when accessing the Form collection, you should always prepend your keys with modelName + "." this helps the view data evaluators and model binders work in sync. so if you have a property on your model called Contact, and you name all your fields "contact.X", and you POST the form to an action which has an argument of type Contact called contact, the argument will automatically be populated correctly.
dines
Member
582 Points
136 Posts
Re: ModelBinder with Types that contains List<T>
Sep 16, 2008 03:46 PM|LINK
Thanks,
I finally managed it... I mixed the approaches but your hint about the naming convention for the controls and the "modelName+"."" made it... thanks again...