Knockout.js привязывает массив объектов к повторяющимся ‹select›

У меня есть эта модель представления Knockout.js:

{
    "LanguageFromTos":
    [{
        "LanguageFromToId":0,
        "LanguageFromId":2,
        "LanguageFrom":null,
        "AllLanguagesFrom":[
            {"Selected":false,"Text":"English","Value":"1"},
            {"Selected":false,"Text":"French","Value":"2"},
            {"Selected":false,"Text":"Spanish","Value":"3"}
        ],

        "LanguageToId":1,
        "LanguageTo":null,
        "AllLanguagesTo":[
            {"Selected":false,"Text":"English","Value":"1"},
            {"Selected":false,"Text":"French","Value":"2"},
            {"Selected":false,"Text":"Spanish","Value":"3"}
        ],
        "Users":null
    }]
}

И эти html <select>s:

<div class="LanguageFromToRow">
    <input type="hidden" name="languageFromTos.index" autocomplete="off" value="c50532b0-65d2-4a81-baeb-59b768fd120f" />

    <label for="languageFromTos_c50532b0-65d2-4a81-baeb-59b768fd120f__LanguageFromId">From</label>:
    <select data-bind="???" data-val="true" data-val-number="The field From must be a number." data-val-required="The From field is required." id="languageFromTos_c50532b0-65d2-4a81-baeb-59b768fd120f__LanguageFromId" name="languageFromTos[c50532b0-65d2-4a81-baeb-59b768fd120f].LanguageFromId">
        <option value="1">English</option>
        <option selected="selected" value="2">French</option>
        <option value="3">Spanish</option>
    </select>
    <span class="field-validation-valid" data-valmsg-for="languageFromTos[c50532b0-65d2-4a81-baeb-59b768fd120f].LanguageFromId" data-valmsg-replace="true"></span>

    <label for="languageFromTos_c50532b0-65d2-4a81-baeb-59b768fd120f__LanguageToId">To</label>:
    <select data-bind="???" data-val="true" data-val-number="The field To must be a number." data-val-required="The To field is required." id="languageFromTos_c50532b0-65d2-4a81-baeb-59b768fd120f__LanguageToId" name="languageFromTos[c50532b0-65d2-4a81-baeb-59b768fd120f].LanguageToId">
        <option selected="selected" value="1">English</option>
        <option value="2">French</option>
        <option value="3">Spanish</option>
    </select>
    <span class="field-validation-valid" data-valmsg-for="languageFromTos[c50532b0-65d2-4a81-baeb-59b768fd120f].LanguageToId" data-valmsg-replace="true"></span>

    <a href="#" class="deleteLanguageFromTo">delete</a>
</div>

Может ли кто-нибудь сказать мне, что мне нужно добавить к атрибутам data-bind каждого select, чтобы связать их с моделью представления Knockout.js? value первого select должно быть связано с LanguageFromId в модели представления, а value второго select должно быть связано с LanguageToId в модели представления.

LanguageFromTos в модели представления является массивом, поэтому все, что вы видите внутри, может повторяться (например, 2 LanguageFromTos приведет к тому, что LanguageFromToRow div будет повторяться дважды). Количество повторов устанавливается как на стороне сервера (данные, отправленные контроллером, могут иметь несколько LanguageFromTos), так и на стороне клиента (кнопка «добавить», которая позволяет пользователю добавить еще один div с содержащимся в нем selects) в разных случаях, поэтому я предположим, что шаблоны Knockout не работают, поскольку MVC необходимо перебирать и отображать каждую строку, чтобы он мог поймать их все в «обычном» сообщении.

Любая помощь высоко ценится!

Редактировать

Вот модель MVC для страницы:

public class DirectorySearchModel
{
    [Display(Name = "User name contains")]
    public string UserName { get; set; }

    [Display(Name = "First name contains")]
    public string FirstName { get; set; }

    [Display(Name = "Last name contains")]
    public string LastName { get; set; }

    [Display(Name = "Languages translated")]
    public IEnumerable<LanguageFromTo> LanguageFromTos { get; set; }
}

Вот объект LanguageFromTo:

public class LanguageFromTo
{
    [Key]
    public virtual int LanguageFromToId { get; set; }

    [Display(Name = "From")]
    public virtual int LanguageFromId { get; set; }
    [ForeignKey("LanguageFromId")]
    public virtual Language LanguageFrom { get; set; }
    public virtual IEnumerable<SelectListItem> AllLanguagesFrom { get; set; }

    [Display(Name = "To")]
    public virtual int LanguageToId { get; set; }
    [ForeignKey("LanguageToId")]
    public virtual Language LanguageTo { get; set; }
    public virtual IEnumerable<SelectListItem> AllLanguagesTo { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

А вот код cshtml для представления MVC. Этот код находится в партиале, который повторяется в зависимости от того, сколько LanguageFromTo есть в DirectorySearchModel, переданном в представление MVC:

<div class="LanguageFromToRow">
    @using(Html.BeginCollectionItem("languageFromTos")) {
        @: @Html.LabelFor(m => m.LanguageFromId): @Html.DropDownListFor(m => m.LanguageFromId, Model.AllLanguagesFrom, new { data_bind = "value: getLanguageFromToById(0).LanguageFromId" }) @Html.ValidationMessageFor(m => m.LanguageFromId)
        @: @Html.LabelFor(m => m.LanguageToId): @Html.DropDownListFor(m => m.LanguageToId, Model.AllLanguagesTo, new { data_bind = "value: getLanguageFromToById(0).LanguageToId" }) @Html.ValidationMessageFor(m => m.LanguageToId)
        <a href="#" class="deleteLanguageFromTo">delete</a>
    }
</div>

person user1390429    schedule 24.05.2012    source источник
comment
Было бы полезно, если бы вы могли немного уменьшить этот HTML. Что со всеми огромными длинными идентификаторами?   -  person SystemParadox    schedule 25.05.2012
comment
@SystemParadox спасибо за ответ - я добавил модель mvc, которая была передана на страницу (и которую я хочу отправить обратно с помощью Knockout.js), и код для партиала, который выдает ужасные идентификаторы.   -  person user1390429    schedule 25.05.2012


Ответы (1)


Ваш дизайн здесь имеет несколько плохих вариантов. Шаблоны Knockout являются правильным выбором для этого, но это потребует от вас начать думать по другому шаблону. Вам не нужно использовать частичные повторения, чтобы выполнить повторение, которое вам нужно.

Вот скрипка, демонстрирующая шаблонное решение. http://jsfiddle.net/tyrsius/XgwLD/3/

Некоторые примечания: чтобы заполнить incomingData, простым способом будет использование @Html.Raw(Json.Encode(Model.DirectorySearchModel ));. Это превратит вашу модель в объект JSON, который может легко использовать конструктор viewModel.

Теперь я не использовал код MVC в скрипке, потому что не могу, но вы, очевидно, уже нашли, как можно поместить привязку данных в помощники MVC. Это не всегда плохая идея, но для таких вещей, как select и DIV, которые вы хотите использовать в качестве шаблонов, это, вероятно, просто усложнит чтение.

person Kyeotic    schedule 25.05.2012
comment
Спасибо @Tyrsius! Я был немного обеспокоен тем, что это будет означать, что я не смогу опубликовать обратно в MVC с помощью более обычной кнопки отправки, но это работает, еще раз спасибо! - person user1390429; 28.05.2012