Удаленная проверка с дополнительными полями на коллекции моделей - PullRequest
5 голосов
/ 01 апреля 2011

Удаленная проверка работает нормально, когда у меня есть только один экземпляр моей модели в представлении.

Проблема в том, что мое мнение касается коллекции моделей. Вот моя модель:

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 выглядит довольно хорошо (каждая модель из коллекции имеет уникальный идентификатор и имя), существует проблема с дополнительными полями при удаленной проверке:

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

Идентификатор из первого ряда выбирается при запуске удаленной проверки во втором ряду.

1 Ответ

1 голос
/ 16 мая 2014

Во-первых, да, вы можете улучшить синтаксис своего представления.Используйте 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 

aka

/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) {
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...