1

Sample code for my question is here. It's a simple Ember app that displays the SearchView containing a TextField by default.

When the user enters some text and hits Enter, I want to transition to another state (displayUserProfile) passing the value entered in the textbox.

At first, in the Textbox's insertNewline callback, I called the transitionTo method of the application's router, passing the value as part of the parameter object:

App.SearchTextFieldView = Em.TextField.extend({
  insertNewline: function() {
    App.router.transitionTo('displayUserProfile', {
      username: this.get('value')
    });
  }
});

That works fine, but then I noticed that pangratz's answer on a question about infinite scrolling, uses a different approach. Instead he invokes a method on the view's controller, which in turn calls a method on the controller's target (which is the router).

This changes my code to:

App.SearchTextFieldView = Em.TextField.extend({
  insertNewline: function() {
    Em.tryInvoke(this.get('controller'), 'displayUserProfile', this.get('value').w());
  }
});

App.SearchController = Em.Object.extend({
  displayUserProfile: function(username) {
    this.get('target').transitionTo('displayUserProfile', {
      username: username
    });
  }
});

My question is: which approach is better? Calling transitionTo directly from the view or delegating it to the view's controller?

Community
  • 1
  • 1
bazzel
  • 833
  • 7
  • 21

2 Answers2

3

I would recommend a different approach. insertNewLine should trigger an action that is handled by the router, which will then transition its state.

App.SearchTextFieldView = Em.TextField.extend({
  insertNewline: function() {
    this.get('controller.target').send('showUser', {username: this.get('value')});
  }
});

App.Router = Ember.Router.extend({
  ...
  foo: Ember.Router.extend({
    showUser: function(router, evt) {
      router.transitionTo('displayUserProfile', evt);
    });
  }
});

You should put the showUser handler at the top-most route where it is valid in your app.

This approach follows the general pattern of events in Ember apps that views handle DOM-level events and where appropriate, turn them into semantic actions that are handled by the router.

Luke Melia
  • 8,340
  • 31
  • 40
  • Thank, Luke. Got it implemented in one of my [sample apps](https://github.com/bazzel/twitter_browser). – bazzel Aug 31 '12 at 04:46
  • 1
    Interresting Luke. When I saw your presentation http://www.lukemelia.com/blog/archives/2012/08/23/architecting-ember-js-apps/, at slide 53, I understood that the event should traverse from view to router, passing by controller. It seems I misunderstood. Though, in your example here, the `evt` in showUser, is not an event, but an object with username, or is this object transformed into a jQuery.Event by ember ? If this is really an event, it's fine, else there could be an error if I directly call showUser from an {{action}} helper, as here this is a jQuery event. – sly7_7 Aug 31 '12 at 07:21
  • 2
    @sly7_7 2 things: 1) they pass through the controller, typically just by way of the controller's target property. 2) yes, there is a disconnect re: data structure between events sent to the router from action helpers (which are jQuery events with a context property added), and typical sends from elsewhere in the app. To keep them the same, you could send `{ context: { username: myUsername } }`. It gets a little verbose, but it may well be a better way to go. – Luke Melia Aug 31 '12 at 20:53
2

Personally I think the second approach is better. The first thing is that it's a bad idea to access the router statically. Then for me, you have to keep the views logic-less, so delegating to controller seems a good choice.
In your case this is only a call to the router, but you can imagine processing some algorithms on the textfield value. If you do this proccessing in you view, this will lead to a view, mixing UI code, and logic code. View should handle only UI code.

sly7_7
  • 11,781
  • 3
  • 36
  • 53