EDIT2
I have created a quick sample project which works. There is one thing I do not like and that is that I cannot pass the list itself around. I have to create the blank list every time and read all the values from the textboxes and save this in the list and give this updated list to the new view. Next round same thing. But it works.
Basically:
public ActionResult About() {
List<FormMetaData> formItems = GetFormItems();
return View(formItems);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult About(FormCollection form)
{
List<FormMetaData> formItems = GetFormItems();
//TryUpdateModel(formItems);
// update project members
foreach (var key in form.AllKeys) {
if (key.ToString().StartsWith("TextBox")) {
string field = (key.ToString().Replace("TextBox", ""));
if (!string.IsNullOrEmpty(form.Get(key.ToString()))) {
formItems.Find(delegate(FormMetaData t) { return t.Field == field; }).Value = form.Get(key.ToString());
}
else { }
// this.ProjectRepository.DeleteMemberFromProject(id, userId);
}
}
ModelState.AddModelError("test", "this is a test error");
if(ModelState.IsValid)
{
///
}
else
{
return View(formItems);
}
return View(formItems);
}
private List<FormMetaData> GetFormItems() {
List<FormMetaData> output = new List<FormMetaData>();
FormMetaData temp1 = new FormMetaData("TextBox",true,"temp1","displayText1");
FormMetaData temp2 = new FormMetaData("TextBox", true, "temp2", "displayText2");
output.Add(temp1);
output.Add(temp2);
return output;
}
and then you have your view:
<% using (Html.BeginForm()) {%>
<table>
<% foreach (var item in Model) {
if (!item.isActive) {
continue;
} %>
<tr>
<td>
<%=Html.Encode(item.DisplayValue)%>
</td>
<td>
<% if (item.FieldType == "TextBox") {%>
<%=Html.TextBox("TextBox"+item.Field, item.Value)%>
<%} if (item.FieldType == "CheckBox") {%>
<%=Html.CheckBox("Value")%>
<%}%>
</td>
<td>
</td>
</tr>
<%} %>
<p>
<input type="submit" value="submit" />
</p>
<% } %>
</table>
I have uploaded a zipfile for you @ http://www.bastijn.nl/zooi/dynamicSample.rar
EDIT
I have tried this example and it goes wrong with the modelbinder. When I use "FormCollection form" as input to the POST create method the values of my textboxes are there under the key supplied. So you have to either your custom model binder or make a model which will work with the default model binder.
To be more specific. It goes wrong because in this case your textboxes are updating properties in objects inside the List, which is the Model passed. Normally your textboxes are updating properties inside the Object which is also your Model and the key used for the textbox (for automatic modelbinding) is the name of the property you update.
So I suppose the model binder does not bind the values in the textbox to your items in the list since it simply does not know how to do this automatically. It is 3.17 am here right now so I'm off to bed, the question is interesting and I might finish the answer tomorrow.
original
<%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%>
It seems you are generating your form every time with the values set to null.
Try to init them something like:
<%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
And in your controller, when you check for ModelState.isValid do something like:
if(ModelState.isValid){
//code when it works
}
else{
return View(formItems) // these should contain the just added values
}
That should do the trick.
So, in a simple example you get something like:
public ActionResult Create()
{
List<FormMetadata> formItems = GetFormItems();
return View(formItems);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(List<FormMetadata> formItems)
{
if(ModelState.isValid)
{
MyUpdate()
save()
}
else
{
return view(formItems)
}
}
And your view:
<%
if (item.FieldType == "TextBox")
{%>
<%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
<%}
if (item.FieldType == "CheckBox")
{%>
<%=Html.CheckBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
<%}