Add / Remove Items from Ember Data Supported by ArrayController

I use ArrayController in my application, which is served by calling Ember Data REST through the Router application:

postsController.connectOutlet('comment', App.Comment.find({post_id: post_id})); 

For the Post user interface, I have the ability to add / remove comments. When I do this, I would like to be able to update the contentArray from postsController by deleting or adding the same element to give the user visual feedback, but Ember Data is not fun:

 Uncaught Error: The result of a server query (on App.Comment) is immutable. 

In response to sly7_7 below, I noticed that the result is indeed DS.RecordArray when there is no request (App.Comment.find ()), but in case there is a request (App.Comment.find ({post_id: post_id}) is returned DS.AdapterPopulatedRecordArray.

Should I use .observes ('contentArray') and create a mutable copy? Or is there a better way to do this?

+7
source share
4 answers

Here is what I decided to implement to solve this problem. As suggested in the question, the only solution I know of is to create a mutable copy of the content that I support by adding and removing:

 contentChanged: function() { var mutableComments = []; this.get('content').forEach(function(comment) { mutableComments.pushObject(comment); }); this.set('currentComments', mutableComments); }.observes('content', 'content.isLoaded'), addComment: function(comment) { var i; var currentComments = this.get('currentComments'); for (i = 0; i < this.get('currentComments.length'); i++) { if (currentComments[i].get('date') < comment.get('date')) { this.get('currentComments').insertAt(i, comment); return; } } // fell through --> add it to the end. this.get('currentComments').pushObject(comment); }, removeComment: function(comment) { this.get('currentComments').forEach(function(item, i, currentComments) { if (item.get('id') == comment.get('id')) { currentComments.removeAt(i, 1); } }); } 

Then in the template, bind this computed property:

 {{#each comment in currentComments}} ... {{/each}} 

I am not satisfied with this decision - if there is a better way to do this, I would like to hear about it.

+7
source

The comment will be too long ...

I don’t know how you are trying to add an entry, but you can try to do this: App.Comment.createRecord ({}). If everything is correct, it will automatically update the contents of your controller. (I think the result of App.Comment.find () works like a "live" array, and when you create an entry, it automatically updates) Here's how we do it in our application:

 App.ProjectsRoute = Ember.Route.extend({ route: 'projects', collection: Ember.Route.extend({ route: '/', connectOutlets: function (router) { router.get('applicationController').connectOutlet({ name: 'projects', context: App.Project.find() }); } }) 

and then the project creation handler (in the router):

 createProject: function (router) { App.Project.createRecord({ name: 'new project name'.loc() }); router.get('store').commit(); }, 
+2
source

For the record only: today (using Ember Data 1.0.0-beta) the library takes this situation into account. When the record in the array is deleted, the array will be updated.

If you try to delete an element in this array manually, for example, using .removeObject (object_you_just_deleted) in the model of the contained controller (which is an ArrayController, therefore, its model is an array of records), you will get an error, for example:

"The result of the server request (in XXXXX β€” the model you are trying to update manually) is unchanged."

Therefore, it is no longer necessary to manually indicate the deletion of an entry from the array to which it belonged. This is great news because I felt like using ED and working all the time ... :)

0
source

Foreword

I had a similar problem and found a little complicated solution. Running through the Ember-Data source code and API documents cleared for me the fact that AdapterPopulatedRecordArray is returning from the requested search requests. This is what the manual says:

AdapterPopulatedRecordArray represents an ordered list of records whose order and membership is determined by the adapter. For example, a request sent to the adapter may initiate a search on the server, the results of which will be loaded into the adapterPopulatedRecordArray instance.

Therefore, a good reason for the immutability is that this data is controlled by the server. But what if I don't need it? For example, I have a Tasklist model with a series of Tasks, and I find them in the TasklistController in the way

 this.get('store').find('task',{tasklist_id: this.get('model').get('id')}) 

And also I have a red button "Add task", which should create and save a new record, but I do not want to make a new search request to the server to redraw my template and show a new task. Good practice for me will be something like

 var task = this.store.createRecord('task', { id: Utils.generateGUID(), name: 'Lorem ipsum' }); this.get('tasks').pushObject(task); 

In this case, I received a declared error. But hey, I want a drink-and-drive!

Decision

 DS.AdapterPopulatedRecordArray.reopen({ replace: DS.RecordArray.replace }) 

So what is it. A bit "on my own" flexible hacking.

0
source

All Articles