This.store.find("model", {...}) server query resets client's record data

I’m using:

DEBUG: ------------------------------- 
DEBUG: Ember      : 1.3.1
DEBUG: Ember Data : 1.0.0-beta.6
DEBUG: Handlebars : 1.3.0 
DEBUG: jQuery     : 2.0.2 
DEBUG: ------------------------------- 

For my Ember application, I have a “search friends” Ember.Component. This component allows the application user to query the remote server for friends whose names match someProvidedString. Internally, this component uses store.find("user", {name: someProvidedString}).

Some other part of my Ember application changes data of user records.

When the application user uses the “search friends” component, at the moment the server query has returned matching records, all local record changes are discarded and replaced with the server-returned data.

How can I avoid that store.find("user", {...}) discards my client-local changes?

In the meantime, my application now uses

DEBUG: -------------------------------
DEBUG: Ember      : 1.7.0-beta.1+canary.0c75abb7
DEBUG: Ember Data : 1.0.0-beta.6
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 2.0.2
DEBUG: ------------------------------- 

I’m still running into the problem that when a query using DS.Store.find("modelType", {some: object}) finishes, then local model data of all returned models is reset to the returned data.

  • Is this expected Ember Data behavior?
  • What would I need to change in order to have DS.Store.find("modelType", {some: object}), /DS.Store.findQuery(...)/DS.store._findQuery(...) behave in a more idempotent manner (i.e. it’s fine to create new local records from the search if that’s the first time the Ember application sees that entity. But don’t change any data if there already exists a record with this ID)?

This is my solution:


Add the following code after Ember Data is loaded.

// compatible with Ember Data : 1.0.0-beta.6
DS.AdapterPopulatedRecordArray = DS.RecordArray.extend({
  query: null,

  replace: function() {
    var type = Ember.get(this, 'type').toString();
    throw new Error("The result of a server query (on " + type + ") is immutable.");
  },

  load: function(data) {
    var store = Ember.get(this, 'store'),
        type = Ember.get(this, 'type'),
        allLocalRecordsOfThisType = store.all(type);
        //records = store.pushMany(type, data), //this used to be the problematic line in original DS.AdapterPopulatedRecordArray implementation
        existingData = data.filter(function(entry) {
        	var isAlreadyInLocalStore = store.hasRecordForId(type, entry.id);
        	return isAlreadyInLocalStore;
        }),
        newData = data.filter(function(entry) {
        	var isNotYetInLocalStore = !store.hasRecordForId(type, entry.id);
        	return isNotYetInLocalStore;
        }),
        newRecords = store.pushMany(type, newData),
        existingRecords = existingData.map(function(existingDataEntry) {
        	return store.recordForId(type, existingDataEntry.id);
        }),
        records = Ember.A(existingRecords).addObjects(newRecords),
        meta = store.metadataFor(type);
    
    //see http://emberjs.com/api/classes/Ember.Observable.html#method_setProperties
    this.setProperties({
      content: Ember.A(records),
      isLoaded: true,
      meta: meta
    });

    // TODO: does triggering didLoad event should be the last action of the runLoop?
    Ember.run.once(this, 'trigger', 'didLoad');
  }
});