Adding an element to the filtered result from ember-data

I have a DS.Store that uses DS.RESTAdapter and a ChatMessage , defined as such:

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

Note that the chat message exists in the room (not shown for simplicity), so in my chat message controller (which is extended by Ember.ArrayController ) I only want to download messages for the room the user is in:

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

This sets the content to DS.AdapterPopulatedModelArray , and my view happily displays all the returned chat messages in the {{#each}} block.

Now you need to add a new message, in the same controller there is the following:

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

This initiates an ajax request to save the message to the server, all is good so far, but it does not update the view. This makes a lot of sense, as it is the result of filtering, and if I remove the room_id filter on App.store.find , then it will be updated as expected.

Attempting this.pushObject(message) with a message entry returned from App.store.createRecord throws an error.

How to manually add an item to the results? There seems to be no way, as far as I can tell, that both DS.AdapterPopulatedModelArray and DS.FilteredModelArray immutable.

+8
ember-data
source share
3 answers

so a couple of thoughts:

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

how to listen to new records in the data warehouse

normal Model.find () / findQuery () will return AdapterPopulatedModelArray, but this array will stand by itself ... it does not know that something new has been loaded into the database

a Model.find () without parameters (or store.findAll ()) will return ALL FilteredModelArray records to you, and ember data will "register" it in the list, and any new records loaded into the database will be added to this array.

calling Model.filter (func) will provide you with a FilteredModelArray, which is also registered in the store ... and any new records in the store will call ember-data for "updateModelArrays", that is, it will call your filter function with a new record, and if you return true , then it will be attached to your existing array.

SO WHAT I FINISHED: did right after creating the store, I call store.findAll (), which returns me an array of all the models for the type ... and I attach it to the repository ... then somewhere else in the code, I can add ArrayObservers to these lists .. something like:

 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) {} }) 

how to push the model to one of these "immutable" arrays:

First of all, pay attention: all Ember-Data Model instances (records) have the clientId property ... which is a unique integer that identifies the model in the data warehouse cache, does it have a real server-id yet (example: immediately after creating the Model .createRecord).

therefore, AdapterPopulatedModelArray itself has the "content" property ... which is an array of these clientId identifiers ... and when you iterate through AdapterPopulatedModelArray, the iterator iterates over these clientId and passes you all the model instances (records) that are mapped to each client.

SO WHAT I DID (this does not mean that it is β€œright”!) To watch these findAll arrays and insert a new clientId into the content AdapterPopulatedModelArray ... SOMETHING LIKE property:

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

what can I say: β€œits work for me” :) will it be split into the next update of the ember data? completely possible

+8
source share

For those still struggling with this, you can get dynamic DS.FilteredArray instead of static DS.AdapterPopulatedRecordArray using the store.filter method. It takes 3 parameters : type, query, and finally a filter callback.

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

You can also do this in the model hook without unnecessary clutter, because the model hook will accept the promise directly:

 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; }); } 
+2
source share

My reading of the source (DS.Store.find) shows that what you actually get in this instance is AdapterPopulatedModelArray. FilteredModelArray will be automatically updated when records are created. Tests are being conducted for this behavior.

0
source share

All Articles