2011-05-09 27 views
2

我有一個現有的ASP.NET MVC 2應用程序,我被要求擴展。我在該網站添加了一項新功能,該功能基於從我們的HR系統檢索到的動態問題列表生成員工評估表單。除了驗證之外,我都有一些工作,並將回覆發佈回網站。以下是一些詳細信息:如何從ASP.NET MVC 2動態表單驗證和發佈數據

  1. 我通過Web服務調用從我們的後端系統檢索「問題」列表。
  2. 每一個「問題」包含要顯示的文本以及以下設置:
    • 問題類型(對應於文本框,文本區域,單選按鈕,列表或複選框列表)
    • 如果允許註釋
    • 如果需要一個答案
    • 適用時,可能的響應

列表要生成形式,我使用for-each循環遍歷問題列表。我使用QuestionType屬性的值來確定呈現哪個局部視圖(每個類型都有一個)。例如,如果QuestionType == SingleChoice,則該部分將選項呈現爲單選按鈕列表。如果對該問題允許評論,我還會渲染一個額外的textarea字段來保存用戶的評論。

正如我所說的,呈現形式工作正常,但現在我需要:

A.當需要一個答案強制執行。我在解決方案的其他地方使用DataAnnotations進行驗證,但由於我沒有針對靜態模型,我不明白我該如何做到這一點。

B.將結果發回網站。對於每個問題,可以在文本框或文本區中輸入文本,爲單選按鈕列表選擇一個值或爲複選框列表選擇多個值。此外,每個問題還可以以評論的形式發回額外的文本。

所有我見過的使用動態「列表」的例子只關心爲每個字段發佈一個值,並且它總是相同的類型(例如文本框列表)。隨着我必須支持的變化,加上需要發回輸入/選定的值和每個問題的評論,我很難過。

任何指導表示讚賞。

回答

1

我剛剛完成完全相同的任務。

我選擇爲我的動態表單對象編寫自定義模型聯編程序。模型活頁夾爲隱藏字段提取了一堆前綴表單鍵,其中包含一些關於該問題的分隔元數據(即IsRequired,QuestionType,QuestionId等)

我正在使用MVC3,但我認爲這應該都適用於MVC2。

我創建了一個模型綁定器,如:

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; 
    } 

} 

我註冊ModelBinder的全球。ASAX使用下列內容:

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

所以,這臨危形式後的操作方法如下所示:

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

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

你可以分享一些代碼的任何機會呢?我沒有編寫自定義模型綁定器,因此一個示例會很有幫助。 – SonOfPirate 2011-05-09 17:39:09

+0

我已經更新了答案,試着給出幾個指針。我爲另一家公司編寫了它,並且目前沒有代碼交付,所以我剛剛寫了一些僞代碼和一些註釋 – 2011-05-09 18:22:28

+0

由於某種原因,我在保存編輯時丟失了代碼着色 - 無法工作爲什麼... – 2011-05-09 18:30:21