Каков наилучший способ связывания/синхронизации моделей просмотра в Knockout?
Если у вас несколько моделей просмотра на одной странице, как вы можете обеспечить их синхронизацию?
Например, если один элемент добавлен или нажата кнопка на одной модели представления, и вы хотите, чтобы другая модель представления была чувствительной к этому изменению, может ли Knockout управлять этим изначально или лучше использовать некоторую систему обмена сообщениями или pub/sub.
Я хочу держаться подальше от необходимости управлять наблюдаемыми между моделями.
Ответы
Ответ 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");
}