开发者

How to validate and post data from dynamic form in ASP.NET MVC 2

I have an existing ASP.NET MVC 2 application that I've been asked to extend. I am adding a new feature to the site where I generate an employee assessment form based on a dynamic list of questions retrieved from our HR system. I have everything working with the exception of validation and posting the responses back to the site. Here's some details:

  1. I retrieve a list of "Questions" from our back-end system via a web service call.
  2. Each "Question" contains the text to display as well as the following settings:
    • The question Type (corresponds to textbox, textarea, radio button list or checkbox list)
    • If comments are allowed
    • If an answer is required
    • When applicable, the list of possible responses

To generate the form, I use a for-each loop over the list of Questions. I use the value of the QuestionType property to determine which partial view to render (one for each of the types). For example, if QuestionType == SingleChoice, that partial renders the choices as a radio button list. If comments are allowed for the question, I also render an additional textarea field to hold the user's comments.

As I said, rendering the form is working fine but now I need to:

A. Enforce when an answer is required. I'm using DataAnnotations for validation everywhere else in the solution but since I'm not working against a static model, I don't see how I can do开发者_JAVA百科 that.

B. Post the results back to the site. For each question, there can be text entered into a textbox or textarea, a selected value for a radio button list or multiple selected values for a checkbox list. Plus, each question could also have additional text sent back in the form of a comment.

All of the examples that I've seen working with dynamic "lists" are only concerned with posting a single value for each field and it is always the same type (e.g. a list of textboxes). With the variations I have to support, plus the need to send back the entered/selected value(s) and a comment for each question, I'm stumped.

Any guidance is appreciated.


I've just finished completing exactly the same task.

I chose to write a custom model binder for my dynamic form object. The model binder pulled out a bunch of prefixed form keys for hidden fields which contained some delimited meta data about the question (i.e IsRequired, QuestionType, QuestionId etc etc)

I'm using MVC3 but I think this should all work in MVC2.

I created a ModelBinder like:

public class DynamicFormModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Create the object to be bound to (I had a kind of form object
        // with a simple list of answer objects
        DynamicForm form = new DynamicForm(new List<Answer>());

        HttpRequestBase request = controllerContext.HttpContext.Request;

        var keys = request.Form.AllKeys.Where(k => k.StartsWith("MyFormsKeyPrefix_Meta_"));
        foreach (var key in keys)
        {
            // Loop over each question's meta data. Metadata will always be present 
            // even if the user hasn't selected an answer as it's a hidden field

            // TODO: Split the meta data and pull out IsRequired, QuestionType etc

            // TODO: Get all the posted form values for the question (these values 
            //       will come from textboxes, dropdowns, checkboxes etc)
            //       Use a prefix like: MyFormsKeyPrefix_Answer_{QuestionId}
            //       textboxes & dropdowns will only ever have one value 
            //       but checkboxes could have multiple

            // TODO: If it's a mandatory question then ensure there is at least
            //       one posted value that is not an empty string

            // If there is a validation error then add it to the model state
            bindingContext.ModelState.AddModelError(key, "Field is required");

            foreach(var answerHtmlName in answerHtmlNames)
            {
                // TODO: Loop over each posted answer and create some kind of nice
                //       Answer object which holds the QuestionId, AnswerId, AnswerOptionId 
                //       and Value etc.


                // Add the answer to the forms answers list
                form.Answers.Add(answer);
            }
        }

        return form;
    }

}

I register the ModelBinder in Global.asax using the following:

ModelBinders.Binders.Add(typeof(DynamicForm), new DynamicFormModelBinder());

So, the action method that recieves the form post looks something like:

public ActionResult ProcessForm(DynamicForm form) {
    if(ModelState.IsValid) 
    {
        DynamicFormService.Process(form);

        return RedirectToAction("TheHttpGetAction");
    }
    return TheHttpGetAction();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜