register knockout define knockout.js publish-subscribe knockout-postbox

knockout.js - define - knockout js lifecycle



¿Cuál es la mejor manera de vincular/sincronizar modelos de visualización en Knockout? (4)

Si tiene varios modelos de vista en una página, ¿cómo se asegura de que pueda mantenerlos sincronizados? Por ejemplo, si se agrega un elemento o se hace clic en un botón en un modelo de visualización y desea que el otro modelo de vista sea sensible a ese cambio, ¿puede Knockout administrar esto de forma nativa o es mejor utilizar algún mensaje o arquitectura de pub / sub.

Quiero evitar tener que administrar observables entre modelos.


Knockout 2.0 incluye funcionalidad que le permite hacer pub / sub básico. Aquí hay una muestra donde dos modelos de vista se comunican a través de un mediador.

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

El primer modelo de vista se notifica a través del buzón sobre un tema específico y el segundo modelo de vista se suscribe a ese tema. No tienen dependencia directa el uno del otro.

Ciertamente, el buzón de correo no necesitaría ser global y podría pasarse a las funciones del constructor del modelo de vista o simplemente crearse dentro de una función autoejecutable.

Muestra: http://jsfiddle.net/rniemeyer/z7KgM/

Además, el postbox podría ser simplemente un ko.observable (que incluye las funciones ko.subscribable ).


Parece que estás conduciendo hacia objetivos contradictorios. La forma en que harías eso en Knockout es crear observables, pero aún así no pareces querer eso.

Si tiene objetos Foo y Bar con observables, es posible que no desee observables en Foo que interactúen con la barra o viceversa, pero ¿por qué no tener un widget que mire Foo y Bar y medie?


Creé una pequeña extensión para resolver este problema en un proyecto mío reciente. Ligeramente similar en metodología, pero agrega suscripciones al observable publicado directamente, y pondrá en cola a los suscriptores si se declaran antes de la declaración de un observable publicado.

Knockout PubSub


La forma en que encontré la sincronización de modelos es usando la librería de buzones de RP Niemeyer

Sin embargo, encontré algo interesante sobre el array observable. Y es por eso que creé una nueva respuesta. Solo para completar la respuesta de Niemeyer.

Al usar el buzón de correos y un array observable, los eventos "suscribirse a" y "publicar en" se activan cuando agrega o elimina un elemento de la matriz observable. No enciende nada cuando actualiza un elemento dentro de la matriz. Creo que esto no tiene nada que ver con la biblioteca del buzón, sino con una limitación de nocaut.

Si intenta obtener el evento al actualizar un elemento de una matriz observable, es mejor utilizar los métodos "publicar" y "suscribir" de la biblioteca del buzón.

Por favor vea la siguiente FIDDLE

Referencia de código:

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