简体   繁体   中英

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:

  • a successful POST request is sent
  • the button is not updated
  • the list is not updated

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

  • a successful DELETE request is sent
  • the button is not updated
  • the list is updated

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-following s 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

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
  }

  // ...
});

For these kind of questions, it really helps to have a smaller, replicated problem (eg 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 - ie 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 .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM