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

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

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

4 ответа

Решение

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

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 функции).

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

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

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

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

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

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

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

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

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");
}

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

Нокаут PubSub

Другие вопросы по тегам