2012-04-03 6 views
8

I tienen una DS.Store que utiliza el DS.RESTAdapter y un objeto ChatMessage definido como tal:Adición del artículo a resultado filtrado de brasa datos

App.ChatMessage = DS.Model.extend({ 
    contents: DS.attr('string'), 
    roomId: DS.attr('string') 
}); 

Nota que existe un mensaje de chat en una habitación (no mostrado por simplicidad) , así que en mi controlador de mensajes de chat (que se extiende Ember.ArrayController) yo sólo quiero cargar los mensajes de la sala el usuario se encuentra actualmente en:

loadMessages: function(){ 
    var room_id = App.getPath("current_room.id"); 
    this.set("content", App.store.find(App.ChatMessage, {room_id: room_id}); 
} 

Esto establece el content a un DS.AdapterPopulatedModelArray y mi vista muestra felizmente todos los mensajes de chat devueltos en un bloque {{#each}}.

Ahora se trata de añadir un nuevo mensaje, Tengo el siguiente en el mismo controlador:

postMessage: function(contents) { 
    var room_id = App.getPath("current_room.id"); 
    App.store.createRecord(App.ChatMessage, { 
     contents: contents, 
     room_id: room_id 
    }); 

    App.store.commit(); 
} 

Esto inicia una solicitud de ajax para guardar el mensaje en el servidor, todo bien hasta ahora, pero doesn 't actualizar la vista. Esto tiene mucho sentido ya que es un resultado filtrado y si elimino el filtro room_id en App.store.find, se actualiza como se esperaba.

Probar this.pushObject(message) con el registro de mensaje devuelto desde App.store.createRecord provoca un error.

¿Cómo agrego manualmente el elemento a los resultados? No parece haber una manera en lo que puedo decir, ya que tanto DS.AdapterPopulatedModelArray como DS.FilteredModelArray son inmutables.

Respuesta

0

Mi lectura de la fuente (DS.Store.find) muestra que lo que realmente estaría recibiendo en esta instancia es un AdapterPopulatedModelArray. Un FilteredModelArray se actualizará automáticamente a medida que crea registros. Hay exámenes aprobados para este comportamiento.

+0

Tienes razón, es un AdapterPopulatedModelArray. He actualizado la pregunta: disculpa por el error tipográfico. – rlivsey

8

modo par de reflexiones:

(Referencia https://github.com/emberjs/data/issues/190)

cómo escuchar para los nuevos registros en el almacén de datos

un Model.find normal()/findQuery() devolverá usted un AdapterPopulatedModelArray, pero esa matriz se mantendrá sola ... no sabrá que se ha cargado algo nuevo en la base de datos

a Model.find() sin par ams (o store.findAll()) devolverá que ALL registra un FilteredModelArray, y Ember-Data lo "registrará" en una lista y todos los registros nuevos cargados en la base de datos se agregarán a esta matriz.

llamando a Model.filter (func) le devolverá un FilteredModelArray, que también está registrado en la tienda ... y cualquier registro nuevo en la tienda causará que los datos de asteriscos "actualicen ArramesModelo", lo que significa que llamará a su filtrar la función con el nuevo registro, y si devuelve verdadero, entonces lo pegará en su matriz existente.

LO QUE TERMINÉ HACIENDO: inmediatamente después de crear la tienda, llamé a store.findAll(), que me devuelve una serie de todos los modelos ... y los adjunto a la tienda ... . Luego, en cualquier otro lugar del código, puedo agregar ArrayObservers a esas listas.algo así como:

App.MyModel = DS.Model.extend() 
App.store = DS.Store.create() 
App.store.allMyModels = App.store.findAll(App.MyModel) 

//some other place in the app... a list controller perhaps 
App.store.allMyModels.addArrayObserver({ 
    arrayWillChange: function(arr, start, removeCount, addCount) {} 
    arrayDidChange: function(arr, start, removeCount, addCount) {} 
}) 

la manera de impulsar un modelo en una de esas matrices "inmutables":

En primer lugar tener en cuenta: todas las instancias Ember-Data Model (registros) tiene una propiedad clientId ... que es un número entero único que identifica el modelo en el caché del almacén de datos, ya sea que tenga o no un real id-servidor aún (ejemplo: justo después de hacer un Model.createRecord).

por lo que AdapterPopulatedModelArray en sí tiene una propiedad de "contenido" ... que es una matriz de estos clientId ... y cuando itera sobre AdapterPopulatedModelArray, el iterador pasa por encima de estos clientId y le devuelve las instancias de modelo completas (registros) que se asignan a cada ID de cliente.

SO lo que he hecho (! Esto no quiere decir que es "correcto") es ver esas matrices findAll, e impulsar nuevas de ClientId en la propiedad del contenido AdapterPopulatedModelArray ... algo así como:

arrayDidChange:function(arr, start, removeCount, addCount){ 
    if (addCount == 0) {return;} //only care about adds right now... not removes... 
     arr.slice(start, start+addCount).forEach(function(item) { 
      //push clientId of this item into AdapterPopulatedModelArray content list 
      self.getPath('list.content').pushObject(item.get('clientId')); 
     }); 
    } 

lo que puedo decir es: "está funcionando para mí" :) ¿se romperá en la próxima actualización de datos? totalmente posible

2

Para aquellos que todavía luchan con esto, puede conseguirse una dinámica DS.FilteredArray en lugar de una estática DS.AdapterPopulatedRecordArray utilizando el método destore.filter. Es takes 3 parameters: tipo, consulta y finalmente una devolución de llamada del filtro.

loadMessages: function() { 
    var self = this, 
     room_id = App.getPath('current_room.id'); 

    this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) { 
    return msg.get('roomId') === room_id; 
    }) 
    // set content only after promise has resolved 
    .then(function (messages) { 
    self.set('content', messages); 
    });   
} 

También puede hacer esto en el gancho modelo sin el desorden extra, porque el modelo de gancho aceptará una promesa directa:

model: function() { 
    var self = this, 
     room_id = App.getPath("current_room.id"); 

    return this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) { 
    return msg.get('roomId') === room_id; 
    }); 
} 
Cuestiones relacionadas