Brou
Brou

Reputation: 90

Ember-data: model refresh on DS.Store.createRecord

Embsters!

I am trying to figure out why my model isn't refreshed after I create a new record and save it to the store.

My route computes the model as follows:

model: function (params) {
  var postID = params.post_id,
      userID = this.get('session.currentUser.id');

  var post = this.store.findRecord('post', postID) ;

  var followings = this.store.query('post-following', {
      filter: { post: postID }
  }) ;
  var userFollowing = this.store.queryRecord('post-following', {
      filter: { post: postID, user: userID }
  }) ;

  return new Ember.RSVP.hash({
      post:          post,
      followings:    followings,
      userFollowing: userFollowing
  });
}

My template then renders a list and a button:

{{#each model.followings as |following|}}
    ...
{{/each}}

{{#if model.userFollowing}}
    <button {{action 'follow'}}>Follow</button>
{{else}}
    <button {{action 'unFollow'}}>Unfollow</button>
{{/if}}

And my controller creates/deletes the relevant post-following record:

actions: {
    follow: function () {
        var user = this.get('session.currentUser'),
            post = this.get('model.post') ;

        this.store.createRecord('post-following', {
            user: user,
            post: post
        }).save();
    },
    unFollow: function () {
        this.get('model.userFollowing').destroyRecord() ;
    }
}  

When I click the [Follow] button:

When I (refresh the page then) click the [Unfollow] button:

Do you have any idea of what I'm doing wrong?
Could it be a problem with my payload?


EDIT: Solved!

Well, it sounds like I was expecting too much from ember.

The framework won't automatically update my post-followings array on store.createRecord('post-following', {...}) call.

I then adjusted my controller logic to "manually" update my model:

// in follow action…
userFollowing.save().then( function(){
    var followings = store.query('post-following', {
        filter: { post: postID }
    }).then( function (followings) {
        _this.set('model.userFollowing', userFollowing);
        _this.set('model.followings', followings);
    }) ;
});
// in unFollow action…
userFollowing.destroyRecord().then( function () {
    _this.set('model.userFollowing', null);
    _this.notifyPropertyChange('model.followings') ;
}); 

Please note that my backend API design has been criticized by @duizendnegen (see comments). More best practices in this article.

Thanks you for all your help !!!
Brou

Upvotes: 2

Views: 765

Answers (3)

nem035
nem035

Reputation: 35481

Your issue is that you aren't re-setting the property model to point to the newly created object. You are always accessing the same model property, even after creating a new one.

First thing to be aware of is that, after the model hook in your route, the setupController hook is called that executes:

controller.set('model', resolvedModel)

meaning that the model property on your controller is, by default, set every time the route loads (the model hook resolves). However, this doesn't happen after you create a new record so you must do it explicitly:

let newModel = this.store.createRecord('post-following', {
  user: user,
  post: post
})

// since model.save() returns a promise
// we wait for a successfull save before
// re-setting the `model` property
newModel.save().then(() => {
  this.set('model', newModel);
});

For a more clear design, I would also recommend that you create an alias to the model property that more specifically describes your model or override the default behavior of setupController if you are also doing some initial setup on the controller. So either:

export default Ember.Controller.extend({
  // ...

  blog: Ember.computed.alias('model') // more descriptive model name   

  // ...
});

Or:

export default Ember.Route.extend({
  // ...

  setupController(controller, resolvedModel) {
    controller.set('blog', resolvedModel); // more descriptive model name 
    // do other setup
  }

  // ...
});

Upvotes: 1

duizendnegen
duizendnegen

Reputation: 73

For these kind of questions, it really helps to have a smaller, replicated problem (e.g. through Ember Twiddle)

Fundamentally, the new post-following record doesn't match the filter: it is filtered for an attribute { post: 123 } and your post-following object contains something in the lines of { post: { id: 123, name: "" } }. Moreover, your post-following object doesn't contain a property called filter or what it could be - i.e. the query it executes to the server are different than those you want to filter by on the client.

My approach here would be to, as a response to the follow and unfollow actions, update the model, both the userFollowing and followings.

Upvotes: 1

Jevado
Jevado

Reputation: 392

Your model is set when you enter the page. When changes are made, your model doesn't change. The only reason why the list is updated when you destroy the record is because it simply doesn't exist anymore. Reload the model after clicking the follow button or unfollow button, or manually change the values for the list/button.

Upvotes: 0

Related Questions