Зависимый наблюдаемый массив в нокауте JS - PullRequest
1 голос
/ 28 сентября 2011

Я начал играть с knockoutjs и делать простое связывание / зависимое связывание.Моя цель - заполнить список 1 <select> на основе значения другого списка <select>.Оба загружаются из ajax-вызова в мой веб-сервис asp.net.

Итак, у меня есть два <select> списка

<select id="make" data-bind="options: availableMakes, value: selectedMake, optionsText: 'text', optionsCaption: 'Choose a make'"></select>
<select id="model" data-bind="options: availableModels, value: selectedModel, optionsText: 'text', optionsCaption: 'Choose a model'"></select>

Тогда мой javascript выглядит так:

$(function () {

            // creating the model
            var option = function (text, value) {
                this.text = text;
                this.value = value;
            }

            // creating the view model
            var searchModel = {
                availableMakes: ko.observableArray([]),
                availableModels: ko.observableArray([]),
                selectedMake: ko.observable(),
                selectedModel: ko.observable()
            }

            // adding in a dependentObservable to update the Models based on the selected Make
            searchModel.UpdateModels = ko.dependentObservable(function () {
                var theMake = searchModel.selectedMake() ? searchModel.selectedMake().text : '';
                if (theMake != '') {
                    $.ajax({
                        url: "/data/service/auction.asmx/GetModels",
                        type: 'GET',
                        contentType: "application/json; charset=utf-8",
                        data: '{make:"' + theMake + '"}',
                        success: function (data) {
                            var makes = (typeof data.d) == 'string' ? eval('(' + data.d + ')') : data.d;
                            var mappedModels = $.map(makes, function (item) {
                                return new option(item.text, item.value);
                            });
                            searchModel.availableModels(mappedModels);
                        },
                        dataType: "json"
                    });
                }
                else {
                    searchModel.availableModels([]);
                }
                return null;
            }, searchModel);

            // binding the view model
            ko.applyBindings(searchModel);

            // loading in all the makes
            $.ajax({
                url: "/data/service/auction.asmx/GetMakes",
                type: 'GET',
                contentType: "application/json; charset=utf-8",
                data: '',
                success: function (data) {
                    var makes = (typeof data.d) == 'string' ? eval('(' + data.d + ')') : data.d;
                    var mappedMakes = $.map(makes, function (item) {
                        return new option(item.text, item.value);
                    });
                    searchModel.availableMakes(mappedMakes);
                },
                dataType: "json"
            });

        });

В настоящее время это работает как ожидалось, но я думаю, что я делаю это неправильно, поскольку код выглядит довольно длинным, и я мог бы сделать это, не используя knockoutjs в меньшем количестве кода.Также способ, которым я загружаю availableModels, явно не верен, потому что я использую зависимый объект, называемый UpdateModels, который я добавил для загрузки availableModels на основе значения selectedMake().text

Надеюсь, это имеет смысл, и вы можете указать на улучшенную версию этого?Или просто скажите мне Как перезагрузить Модели на основе выбора Марки?

Большое спасибо,

Ответы [ 2 ]

4 голосов
/ 28 сентября 2011

Я думаю, что ваш код выглядит довольно нормально. Для UpdateModelspendentObservable вы можете использовать ручную подписку на selectedMake, например:

searchModel.selectedMake.subscribe(function (newMake) {
    if (newMake) {
        //ajax request
    }
    else {
        searchModel.availableModels([]);
    }
}, searchModel);

Это не изменило бы функциональность, просто более явный способ подписаться на одно наблюдаемое изменение.

Вы также можете использовать optionsValue: 'text' (или 'значение') в привязке, и ваш selectedMake будет напрямую установлен на текст или значение.

Если бы ваши модели были дочерними по отношению к объектам make, то вы могли бы даже связать модели с selectedMake().models (необходимо было бы защитить от selectedMake, являющегося нулевым, что можно было бы сделать с помощью DO, привязки потока управления 1.3 или inline как selectedMake() ? selectedMake().models : []

2 голосов
/ 30 декабря 2011

Я согласен с ответом Райана.

Рассматривая его немного по касательной, я немного реорганизовал его, чтобы не использовать ajax и упростить пример (вы всегда можете добавить это обратно).Но вот скрипка, которая демонстрирует, что вы собираетесь делать с некоторыми образцами данных.

http://jsfiddle.net/johnpapa/vGg2h/

...