mvc3 - overriding formcollection keys

740 views Asked by At

I'm using mvc3 with dynamically created forms, and the default modelBinder is not helping me.

I'd like to obtain control over the form collection keys that are associated with control values and posted back in the form collection.

controllerContext.HttpContext.Request.Form["IWantToSetThisKeyRightHere"]

Currently those keys are auto-generated someplace that I don't understand to support default model binding, which doesn't work for me anyways.

How do I set those values when creating the view so that I can experiment with my own custom model binder to extract the data when the dynamic form is posted?

Thanks

2

There are 2 answers

0
Todd On

The key to the form collection comes from the name property of the input element. I was trying to override that by using an html helper and passing in a new value for the name attribute.

Like this:

@{ var uniqueNameAttribute = new { name = Model.UniqueName };}   
@Html.TextBox(Model.MessageText, Model.Answer, uniqueNameAttribute)

The name value I was trying to set (Model.UniqueName) was being overwritten by a string that was presumably designed by mvc to allow it to map the value back to the same Model class during modelBinding after the post.

Since my system is dynamic, mvc cannot map the data back to the Model. I wanted to take control of that value to enable me to map the data back manually on post.

The solution was very simple, all I had to do was not use the @Html.TextBox helper to generate the textbox, and create it myself with my intended name property.

<input type="text" class="vmFreeTextAnswer" name="@Model.UniqueName" value="" />

This permits me to hook the posted values back into my dynamically structured model on post.

2
Erik Funkenbusch On

Based on your previous question, your problem doesn't seem to be that complex. You're making it a lot harder than it has to be. All you need is a simple model that looks like this:

public class Container {
    public List<Container> Containers {get;set;}
    public Question Question {get;set;}
}

public class Question {
    public List<Answer> Answers {get;set;}
}

Just guessing here, an Answer probably can't contain anything, so it needs its own object and a question can only contain answers. If a Question can contain other questions or Containers, then you can modify this a bit to make that work.

None of this needs a special model binder.

You don't need to inherit all your objects from a single base, and you don't need to use your weird template selector either.

You do this by doing something like this:

EditorTemplates/Container.cshtml

@model Container

@Html.EditorFor(m => m.Containers)
@Html.EditorFor(m => m.Question)

EditorTemplates/Question.cshtml

@model Question

@Html.EditorFor(m => m.Answers)

EditorTemplates/Answer.cshtml

@model Answer

// whatever your answer code is.. if you have multiple answer types then you 
// need a template for each type

The default MVC templating system will handle all this for you, and model bind everything for you. You just need to instantiate your model correctly before you pass it to the view.