2012-03-27 16 views
13

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 modelo de vista y desea que el otro modelo de vista sea sensible a ese cambio, ¿puede Knockout administrarlo de forma nativa o es mejor utilizar algún mensaje o arquitectura de pub/sub.¿Cuál es la mejor manera de vincular/sincronizar modelos de visualización en Knockout?

Quiero estar lejos de tener que administrar observables entre modelos.

Respuesta

25

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

La primera vista de modelo notifica a través del buzón de correos sobre un tema específico y el segundo modelo de vista 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 sólo un ko.observable (que incluye los ko.subscribable funciones).

+0

esto se ve genial, gracias. – jaffa

+0

@RP Niemeyer - ¿Cuál es la diferencia entre ko.subscribable y observable? – Ryan

+3

ko.subscribable es una "clase" base que observables y observables calculados obtienen funcionalidad de. Proporciona las características básicas de pub/sub que utilizan observables y observables computados. –

0

Parece que conduce 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, puede que no quiera observables en Foo que interactúen con la barra o viceversa, pero ¿por qué no tener un Widget que mire Foo y Bar?

+0

¿Qué pasa con la situación en la que tiene un modelo de cuadro de búsqueda en cada página?Desea indicarle a todos los demás modelos que se vuelvan a vincular usando el texto en la búsqueda. Cada página tendrá el modelo de cuadro de búsqueda, pero un modelo de vista diferente en cada página. – jaffa

0

He creado 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

0

La manera que encontré para modelos de sincronización está utilizando la biblioteca de buzón de correos RP Niemeyer

Sin embargo he encontrado algo interesante con respecto a la observableArray. Y es por eso que creé una nueva respuesta. Solo para completar la respuesta de Niemeyer.

Al utilizar el buzón de correos y un Arreglo 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 está intentando 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 de correos.

Por favor, vea la siguiente referencia FIDDLE

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