Можно ли передать Knockout значение по умолчанию элемента select при привязке параметров через AJAX?

Мне нужно получить как текущее значение, так и доступные параметры <select /> через два разных вызова AJAX (я не могу поставить их в очередь/связать по нескольким причинам).

Я не знаю, имеет ли это значение, но вызов, читающий текущее значение, каждый раз завершается до того, как вызов считывает доступные параметры.

Используя Knockout 2.0.0 и Knockout Mapping 2.0.3, я связал выбор с data-bind="options: values, value: valueComputed", но обнаружил, что Knockout удаляет/игнорирует значение, установленное первым вызовом AJAX, до тех пор, пока не завершится вызов, извлекающий доступные параметры, невозможно установить текущее значение.

Это правильно? Можно ли сказать Knockout «это текущее значение, когда станут доступны доступные параметры, выберите его»?

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

Я делаю что-то злое?

Пример jsFiddle: http://jsfiddle.net/KeNUU/

Код JavaScript, который я использую:

var viewModel = function () {
    var self = this;

    // The underlying observable where
    // the selected value is stored.
    self.value = ko.observable();

    // The observable bound to
    // the value of the drop down.
    self.values = ko.mapping.fromJS([]);

    // Use a computed observable to intercept the undefined
    // value placed by KnockOut when binding the drop down.
    self.valueComputed = ko.computed({
        "read": function () {
            return ko.utils.unwrapObservable(self.value);
        },
        "write": function (value) {
            // Update the underlying observable only when
            // there is a value, if it's undefined ignore it.
            if (value) {
                self.value(value);
            }
        }
    });

    // Simulate the AJAX request which fetches the actual value,
    // this request must complete before the second one.
    setTimeout(function () {
        self.valueComputed("b");
    }, 1000 * 1);

    // Simulate the AJAX request which fetches the available values,
    // this reqest must complete after the first one.
    setTimeout(function () {
        ko.mapping.fromJS(["a", "b", "c", "d"], {}, self.values);
    }, 1000 * 2);
};

$(document).ready(function () {
    ko.applyBindings(new viewModel());
});

person Albireo    schedule 05.03.2012    source источник


Ответы (1)


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

Я думаю, что более простой выбор - просто кэшировать начальное значение в ненаблюдаемом объекте, а затем использовать его для заполнения value, когда список возвращается. Если бы список был первым, тогда не было бы начального значения, и он мог бы работать как обычно.

Что-то типа:

setTimeout(function () {
    self.initialValue = "b";
    self.value("b");
}, 1000 * 1);

// Simulate the AJAX request which fetches the available values,
// this reqest must complete after the first one.
setTimeout(function () {
    ko.mapping.fromJS(["a", "b", "c", "d"], {}, self.values);
    if (self.initialValue) {
         self.value(self.initialValue);
         self.initialValue = null;
    }    
}, 1000 * 2);

http://jsfiddle.net/rniemeyer/gB3E5/

Теперь вы обрабатываете это заранее без (незначительных) накладных расходов, связанных с вычислением наблюдаемого перехвата каждого изменения в раскрывающемся списке.

person RP Niemeyer    schedule 05.03.2012
comment
см. новый ответ на основе нокаута 3.1 (выпущенного вчера) stackoverflow.com/questions/22198994/ - person ctrl-alt-delor; 05.03.2014