Loading parent relation of hasMany


#1

In my app, a post has many comments. I have a new-comment route at posts/:id/new-comment. The controller looks like:

Blogger.NewCommentController = Ember.ObjectController.extend({
  actions: {
    save: function() {
      var comment = this.store.createRecord('comment', {
        text: this.get('text')
      });
      comment.save();

      var post = this.get('model');
      post.get('comments').pushObject(comment);
      post.save();
      
      this.transitionToRoute('post', post);
    }
  }
});

And the route looks like this:

Blogger.NewCommentRoute = Ember.Route.extend({
  model: function(params) {
    return this.modelFor('post');
  }
});

Is it the “right way” to load the parent object as the model? I don’t see any other way to get access to it, but it feels weird that the post should be the model for this route, since the purpose of the route is to create a new comment.


#2

It depends, in your case I would put the “this.store.createRecord(‘comment’)” in the model-hook.

Blogger.NewCommentRoute = Ember.Route.extend({
    beforeModel: function(model, transition) {
        this.controllerFor('post').set('content', this.modelFor('post');
    },
    model: function(params) {
        var comment = this.store.createRecord('comment');
    }
});

Now you can work with your inputFields directly on the properties of the comment.

{{input type="text" value=content.text}}

This way the comment gets automaticly filled when typing.

Blogger.NewCommentController = Ember.ObjectController.extend({
    needs: ['post'],
    actions: {
        save: function() {
            var comment = this.get('content');
            comment.save();

            var post = this.get('controllers.post.content');
            post.get('comments').pushObject(comment);
            post.save();
  
            this.transitionToRoute('post', post);
         }
      }
});

There other ways to do it, but thats one. I think in the model-hook belongs the model of the route… As the name “NewComment” says the model is a new comment. I all depends abit on how you make up your routes.


#3

Thanks for the suggestion, @gerrit. It feels a lot more complex to do it this way, but it does feel like the responsibilities line up more neatly.


#4

How do you delete the new record when user clicks “Cancel” but not save? As I know the newly created record is in the store. I just know that calling “comment.rollback()” can remove it from the store, but I don’t know where I should put this logic in.


#5

There is a hook in every route which is called #

 willTransition; function(model, transition){
     // model.rollback() if the model isnt persisted
 }

@michaelrkn I know it looks more complex, but its cleaner and theres a place for everything… beforeModel = prepare dependencies for the model model = the resource belonging to this route afterModel = the stuff you only can when you have the model… like loading async relations etc.


#6

I’m playing around with this, and it looks like you don’t actually need this.controllerFor('post').set('content', this.modelFor('post'). Instead, in your controller, you can simply do var post = this.get('controllers.post.model').

In this case, I don’t want to create the new comment object in my route, because I have a list of comments in another template, where the incomplete comment would show up before the user saves it. That’s why I’m creating the record in the controller, rather than the route.

Here’s what my controller looks like now:

Blogger.NewCommentController = Ember.ObjectController.extend({
  needs: 'post',
  actions: {
    save: function() {
      var comment = this.store.createRecord('comment', {
        text: this.get('text')
      });
      comment.save();

      var post = this.get('controllers.post.model');
      post.get('comments').pushObject(comment);
      post.save();

      this.transitionToRoute('post', post);
    }
  }
});