You're obviously coming from Asp.net WebForms background hence having a bit of a problem comparing MVC with WebForms.
Dynamic controls are usually added on the client
Adding additional HTML elements is simply done on the client because it's fast, convenient and doesn't require server side state preservation. And because there's (almost) no need to load these on the server. As you've probably found out, Asp.net MVC works completely differently from Asp.net WebForms.
An easy to understand example
So the simplest way is to have template loaded on the client and then add new items based on that particular template. This JSFiddle shows you how. If you can't provide template in the HTML you can always load it via Ajax, but that should only be done whenever there's either:
- too many different templates to add - an example would be a page with a list of users where each user requires a complex template which could slow things down due to DB requests and bloated HTML
- templates depend on other data already entered by the user in which case we can't prepare a template before user provides this data (although
.tmpl
provides conditionals and loops, so we should use these whenever possible).
Basically I've used jQuery and its .tmpl()
plugin to quickly generate complex items (by complex I mean not consisting of a single HTML element) with correct naming and IDs and so on. Control names correspond to how Asp.net MVC works. These generated fields would easily model bind to this controller action method:
public ActionResult Experiences(Experience experience)
{
// do what's appropriate
}
Related classes used in this code (only relevant properties):
public class Experience
{
[Required]
public IList<Company> Companies { get; set; }
...
}
public class Company
{
[Required]
public string Name { get; set; }
...
}
Model binding to IList<T>
is the idea here
Basically whenever you're model binding to IList<T>
(which basically is happening when you're dynamically adding new and new controls) you're having a bit of a problem that needs to be solved on the client with proper input form naming. You can read all the details related to this in my blog post as well where I explain the problem and provide a solution somewhat similar to this.
Important: Instead of linking to a CDN with jQuery .tmpl()
I had to copy the minimized version of it directly into HTML part in JSFiddle example, because otherwise it won't load the plugin.