Какой лучший способ связывания / синхронизации моделей просмотра в Knockout?


Если у вас есть несколько моделей представлений на одной странице, как вы можете гарантировать, что они будут синхронизированы? Например, если один элемент добавлен или кнопка нажата на одной модели представления, и вы хотите, чтобы другая модель представления была чувствительна к этому изменению, может ли Knockout управлять этим изначально или лучше использовать некоторые сообщения или архитектуру pub/sub.

Я хочу держаться подальше от необходимости управлять наблюдаемыми между моделями.

4 14

4 ответа:

Knockout 2.0 включает в себя функциональность, которая позволяет вам делать базовый паб / sub. Вот пример, где две модели представления взаимодействуют через посредника.

var postbox = new ko.subscribable();

var ViewModelOne = function() {
    this.items = ko.observableArray(["one", "two", "three"]);
    this.selectedItem = ko.observable();
    this.selectedItem.subscribe(function(newValue) {
        postbox.notifySubscribers(newValue, "selected");
    });
};

var ViewModelTwo = function() {
    this.content = ko.observable();
    postbox.subscribe(function(newValue) {
        this.content(newValue + " content");
    }, this, "selected");
};

ko.applyBindings(new ViewModelOne(), document.getElementById("choices"));
ko.applyBindings(new ViewModelTwo(), document.getElementById("content"));

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

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

Пример: http://jsfiddle.net/rniemeyer/z7KgM/

Также, postbox может быть просто ko.observable (который включает в себя функции ko.subscribable).

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

Если у вас есть объекты Foo и Bar с наблюдаемыми объектами,вы можете не хотеть, чтобы наблюдаемые объекты на Foo взаимодействовали с bar или наоборот, но почему бы не иметь виджет, который наблюдает Foo и Bar и опосредует?

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

Нокаут PubSub

Способ синхронизации моделей, который я нашел, использует библиотеку почтовых ящиков RP Niemeyer

Однако я нашел кое-что интересное относительно наблюдаемого беспорядка. Вот почему я придумал новый ответ. Просто чтобы закончить ответ от Нимейера.

При использовании postbox и observableArray события" subscribeTo "и" publishOn " запускаются при добавлении или удалении элемента из observableArray. Он ничего не запускает при обновлении элемента в массиве. Я думаю, что это не имеет ничего общего с библиотекой почтовых ящиков, но ограничение нокаута.

Если вы пытаетесь получить событие при обновлении элемента наблюдаемого массива, то лучше использовать методы" publish "и" subscribe"из библиотеки postbox.

Пожалуйста, смотрите следующее скрипка

Ссылка на код:

function FundEntity (fund)
{
    var self = this;
    self.id = fund.id;
    self.fundName = fund.fundName;
    self.description = fund.description;
    self.isFavorite = ko.observable(fund.isFavorite);
}


function GridViewModel(model) {
    var self = this;
    self.fundList = ko.observableArray();
    model.funds.forEach(function(fund) {
        self.fundList.push(new FundEntity(fund));
    }); 
    self.favorite = function (id, index) {
        var newValue = {
            id: id,
            index: index,
            isFavorite: self.fundList()[index].isFavorite()
        };
        ko.postbox.publish("itemChanged", newValue);
        return true;
    };
    self.isEditable = ko.observable().subscribeTo("myEditableTopic");
}

function FundDetailViewModel(model) {
    var self = this;
    self.fundList = ko.observableArray();
    model.funds.forEach(function(fund) {
        self.fundList.push(new FundEntity(fund));
    });    
    ko.postbox.subscribe("itemChanged", function (newValue) {        
        self.fundList()[newValue.index].isFavorite(newValue.isFavorite);        
    });
    self.editable = ko.observable(false).publishOn("myEditableTopic");
}