Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Нокаут 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).

Ответ 2

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

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

Ответ 3

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

Нокаут PubSub

Ответ 4

Как я нашел для синхронизации моделей, используется библиотека postbox RP Niemeyer

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

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

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

См. следующий 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");
}