Reputation: 1561
The router of my application looks like this (it's CoffeeScript):
App.Router.map () ->
@resource 'conversations', { path: '/' } ->
@resource 'conversation', { path: ':conversation_id' }
@route 'new'
So, in my app, I have paths like /new
, /1
, /2
, etc.
I would like to detect a transition from /1
to /2
to make some initializations in my view (basically, put the focus on a textarea field). Unfortunately, as /1
and /2
use the same route, it seems nearly impossible to detect that transition.
I tried by using didInsertElement
in the view (as described here) or by observing currentPath
in the controller (as described here). It works fine if I go from /new
to /1
(different routes) but not if I go from /1
to /2
.
I found this gist suggesting to use the StateManager
but it seems outdated (and I'm not sure it's really what I need).
What do you suggest me to do?
EDIT
It seems that setupController
is called every time so I decided to overload it like this:
App.ConversationRoute = Ember.Route.extend {
setupController: (controller, model) ->
controller.set 'model', model
# do something here?
}
And I want the init
method in my view to be called:
App.ConversationView = Ember.View.extend {
init: ->
@$('form textarea').focus()
}
But I still can't figure out how to make these two things work together (it's a problem because I read that the controller is not supposed to know about the view).
Thank you for your help!
Upvotes: 0
Views: 2283
Reputation: 2700
The didInsertElement
method of the view is the best method if you need to instantiate something on your view. If you need to have the controller do something when the template loads, you can put the call in the setupController
method of your route:
App.FirstRoute = Ember.Route.extend({
setupController: function(controller){
controller.onload();
}
});
Here's a jsfiddle with a full example: http://jsfiddle.net/jgillick/Q5Kbz/
This will be called each time that route is loaded. Try the jsfidle. Click along to the second template and then use your browser's back button. The onload should fire again.
Also, fun fact, you can use the deactivate
method as an unload, to do anything you need to that controller when the user navigates away from that route:
App.FirstRoute = Ember.Route.extend({
deactivate: function(){
this.controller.unload();
}
});
One thing to note, (not directly related to your question) if you set the model on the controller in the setupController
method, it will overwrite your controllers content
property each time that route is loaded. To prevent this, put a conditional around the assignment:
setupController: function(controller, model) {
controller.onload();
if (model && (!controller.content || Ember.keys(controller.content).length === 0)) {
controller.set('content', model);
}
}
Upvotes: 1
Reputation: 15276
Use the didInsertElement
view hook and an observer.
App.ConversationView = Ember.View.extend
didInsertElement: ->
@focusOnTextarea()
modelChanged: (->
@focusOnTextarea()
).observes('controller.model')
focusOnTextarea: ->
@$('form textarea').focus()
In the case of going from /1 to /2, the route and view are not changing. Ember does the least amount of work possible. There's no need to re-render the view, so it doesn't. But this tripped me up too, and I think it's a big gotcha.
Also, if you override init
in your view, make sure to call @_super()
.
Note: the model
hook is only called when landing on a page to deserialize the URL, not when transitioning from another page and changing the model instance.
Upvotes: 3
Reputation: 65242
Route#model
is your friend here. It will receive a params
hash containing information from the URL on every route change (even when changing just which instance of a class is being viewed) In your case,
App.ConversationRoute = Ember.Route.extend {
model: (params) ->
App.Conversation.find params.conversation_id
setupController: (controller, conversation) ->
// you have the correct Conversation object
The guides have more examples.
Upvotes: 1