2011-04-01 53 views
5

當我在視圖上只有一個模型實例時,遠程驗證正常工作。在模型集合上使用AdditionalFields進行遠程驗證

問題是當我的視圖處理模型的集合。這裏是我的模型:

public class TableFormTestModel 
{ 
    public GridRow[] GridData { get; set; } 
    public class GridRow 
    { 
     public Int32 Id { get; set; } 

     [Required, StringLength(50), Remote("IsNameAvailable", "TableFormTest", "Admin", AdditionalFields = "Id")] 
     public String Name { get; set; } 
    } 
} 

在我看來,我有:

@model TableFormTestModel 
@using (Html.BeginForm()) 
{ 
    Html.EnableClientValidation(); 
    Html.EnableUnobtrusiveJavaScript(); 
    for(var i = 0;i<Model.GridData.Length;i++) 
    { 
    <div> 
     @Html.HiddenFor(x => Model.GridData[i].Id) 
     @Html.TextBoxFor(x => Model.GridData[i].Name) 
     @Html.ValidationMessageFor(x => Model.GridData[i].Name)  
    </div> 
    } 
} 

這是生成表單的相當長的路,任何人都可以提高語法我好嗎?

以下HTML形式產生:

<form method="post" action="/Admin/TableFormTest/"> <div> 
    <input type="hidden" value="1" name="GridData[0].Id" id="GridData_0__Id" data-val-required="The Id field is required." data-val-number="The field Id must be a number." data-val="true"> 
    <input type="text" value="abc" name="GridData[0].Name" id="GridData_0__Name" data-val-required="The Name field is required." data-val-remote-url="/Admin/TableFormTest/IsNameAvailable" data-val-remote-additionalfields="*.Name,*.Id" data-val-remote="&amp;#39;Name&amp;#39; is invalid." data-val-length-max="50" data-val-length="The field Name must be a string with a maximum length of 50." data-val="true"> 
    <span data-valmsg-replace="true" data-valmsg-for="GridData[0].Name" class="field-validation-valid"></span>  
</div> 
<div> 
    <input type="hidden" value="2" name="GridData[1].Id" id="GridData_1__Id" data-val-required="The Id field is required." data-val-number="The field Id must be a number." data-val="true"> 
    <input type="text" value="def" name="GridData[1].Name" id="GridData_1__Name" data-val-required="The Name field is required." data-val-remote-url="/Admin/TableFormTest/IsNameAvailable" data-val-remote-additionalfields="*.Name,*.Id" data-val-remote="&amp;#39;Name&amp;#39; is invalid." data-val-length-max="50" data-val-length="The field Name must be a string with a maximum length of 50." data-val="true"> 
    <span data-valmsg-replace="true" data-valmsg-for="GridData[1].Name" class="field-validation-valid"></span>  
</div> 

儘管上面的html看起來相當好(從收集每個模型都有了唯一的ID和姓名)有與遠程驗證的附加字段問題:

data-val-remote-additionalfields="*.Name,*.Id" 

當第二行激發遠程驗證時,第一行的Id會被拾取。

+0

嘗試使用DisplayTemplates,然後使用@Html。DisplayFor(model => model.GridData) – mimo 2014-02-06 14:03:39

回答

1

首先,是的,您可以改進視圖的語法。使用EditorTemplates

創建Views\Shared\EditorTemplates\GridRow.cshtml

@model TestMvc.Models.TableFormTestModel.GridRow 
<div> 
    @Html.HiddenFor(x => x.Id) 
    @Html.TextBoxFor(x => x.Name) 
    @Html.ValidationMessageFor(x => x.Name) 
</div> 

現在您的主視圖中僅需要:

@model TableFormTestModel 
@using (Html.BeginForm()) 
{ 
    Html.EnableClientValidation(); 
    Html.EnableUnobtrusiveJavaScript(); 
    @Html.EditorFor(x => x.GridData) 
} 

至於RemoteAttribute煩惱,它的棘手。問題是由於MVC爲數組創建的輸入的名稱。如您所見,您的輸入被命名,例如,GridData[1].Id,GridData[1].Name(等)。那麼,jQuery通過將這些名稱提供給查詢字符串來進行ajax調用。

因此,那些最終得到被稱爲是

/Admin/TableFormTest/IsNameAvailable?GridData%5B1%5D.Name=sdf&GridData%5B1%5D.Id=5 

又名

/Admin/TableFormTest/IsNameAvailable?GridData[1].Name=sdf&GridData[1].Id=5 

...,默認模式粘結劑真的不知道如何處理這一點。

我的建議是編寫自己的自定義模型聯編程序。告訴MVC如何讀取這個查詢字符串,然後創建你想要的對象。

這是一個概念驗證。 (但不要在生產用這個東西:它需要太多的假設,並會和好如初的任何意外。)

public class JsonGridRowModelBinder : IModelBinder { 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
     var model = new TableFormTestModel.GridRow(); 
     var queryString = controllerContext.HttpContext.Request.QueryString; 
     model.Name = queryString[queryString.AllKeys.Single(x => x.EndsWith("Name"))]; 
     string id = queryString[queryString.AllKeys.Single(x => x.EndsWith("Id"))]; 
     model.Id = string.IsNullOrWhiteSpace(id) ? 0 : int.Parse(id); 

     return model; 
    } 

} 

然後,告訴你IsNameAvailable的方法來使用這個模型綁定:

public JsonResult IsNameAvailable([ModelBinder(typeof(JsonGridRowModelBinder))] TableFormTestModel.GridRow gridRow) { 
    ... 
} 
相關問題