Ember.js action bubbling but controller undefined in action - ember.js

I have a route that has an afterModel hook.
afterModel: function(model, transition){
transition.send('doInAppRoute');
}
I have an action in my application route:
doInAppRoute: function(){
var controller = this.get('controller');
controller.set('someProp', true);
}
When I allow the action to bubble from the route with the afterModel hook, I get the following error.
Error while processing route: embed Cannot read property 'set' of undefined TypeError: Cannot read property 'set' of undefined
If I put an action call to doInAppRoute in the application template, everything runs as expected.
If the action call to doInAppRoute bubbles, this.get('controller') in my application route is undefined. Why?
And how can this be changed so the bubbled action updates the application controller property?

Thanks to #torazaburo for leading me in the right direction.
This is what I did.
Set someProp to an initial value in application route.
someProp: false,
Then in the the application route action do something like:
doInAppRoute: function(){
this.set('someProp', true);
}
And then in the application route setupController do:
setupController: function(controller, model){
controller.set('someProp', this.get('someProp'));
controller.set('model', model);
}
Then everything should work.

Related

Emberjs: Resetting controller based on dynamic segment

I have this route structure in my app:
Profile.Router.map(function() {
this.resource('profile', { path: '/:user' }, function(){
this.route('followers');
});
});
My /:user/followers page is supposed to show the list of followers of :user. The controller for profile.followers is setup for infinite scroll - so it has properties like curPage, resultsPerPage.
Profile.ProfileFollowersController = Ember.ArrayController.extend(InfiniteScroll.ControllerMixin,{
curPage: 1,
resultsPerPage: 20,
//other code for infinite scroll which increments curPage as user scrolls down
})
Now, since controllers are singleton in emberjs, when I move from /tom/followers to /jin/followers, the properties for infinite scroll that were set for /tom/followers get preserved and applied for /jin/followers as well.
For eg. say I am on /tom/followers and scroll down 4 pages, curPage property of 'profile.followers' controller gets set as 4. Now when I move to /jin/followers, though the model hook of the route would return list of followers for jin, but would pick curPage as 4 since ember's controllers are singleton and I had scrolled down to 4th page on /tom/followers.
How is this supposed to be handled?
Here is my profile.followers route as well:
Profile.ProfileFollowersRoute = Ember.Route.extend({
model: function(params) {
console.log("fetching followers model");
return Ember.$.getJSON('/'+this.modelFor('profile').user+'/followers?new=1');
},
});
You can use the route's setupController hook for this. This hook is fired every time the route is entered.
App.ProfileFollowersRoute = Ember.Route.extend({
setupController: function(controller, model) {
// Call _super for default behavior
this._super(controller, model);
// Reset the desired controller properties
controller.setProperties({
curPage: null,
someOtherProp: null
});
}
});
I've made a jsbin demonstrating it:
http://emberjs.jsbin.com/fiyetefeno/6/
You can read the API documentation here:
http://emberjs.com/api/classes/Ember.Route.html#method_setupController

Ember.js how to get a model inside beforeModel/afterModel hooks and pass it to the controller?

I have a problem getting the models inside a controller of a route accessed using {{link-to}}
From my understanding (after reading http://emberjs.com/guides/routing/asynchronous-routing/) the model hook of a route doesn't get called when the route is accessed from a {{link-to 'route' model}}. The model is passed directly to the controller. This is a way that Ember ensures that no AJAX called will be made unnecessarily.
For example if I go to {{link-to 'post-review' post}} and I need to pass more than a post model to the PostReviewController.
App.Router.map(function () {
...
this.resource('post-review' , {path: '/post-review/:id'});
...
});
PostReviewRoute = Ember.Route.extend({
//method doesn't get called
model: function(params){
return Em.RSVP.hash({
post: this.store.find('post', params.id),
reviewTypes: this.store.find('reviewType')
});
}
});
The ReviewTypeis a model which has no relationship with Post so that I can access it directly using post.reviewType. A post has several reviews. A review has a reviewType. But I must show all the reviewTypes inside of a combobox.
Anyways, the model hook doesn't get called and I cannot access the this.get('reviewTypes') from PostReviewController. I understand that the beforeModel or afterModel hooks are used for this purpose: to pass additional models to a controller when the route it's accessed from a link-to and not directly from the browser URL. The documentation doesn't show how you can do that! Please enlighten me if you know how!
Thanks!
setupController to the rescue, in your route use the setupController hook to set the reviewTypes like so:
PostReviewRoute = Ember.Route.extend({
setupController: function(controller, model){
var postId = model.get('id');
this._super.apply(this, arguments);
this.store.find('reviewType').then((records)=> {
controller.set('reviewTypes', records);
});
this.store.find('post', postId).then(....)
},
// your code
});
You should now be able to call this.get('reviewTypes').
Let me know if this does it for you.

How to get reference to current route from controller?

I have a controller (KbRelatedGroupController) that is loaded via a {{render}} helper in a template.
In the controller's action, if I do this.get('target'), it returns a reference to the parent controller for the page (KbShowController).
If I call .target on that, I get a reference to Discourse.Router, which is no good to me.
What I want is a reference to a KbShowRoute, and that is what I expected since .target is supposed to produce the Route when called from a controller is it not?
Really confused here. Why is it so hard to get a reference to the current route from a controller?
The way I see it, you're not supposed to. You can let the action bubble up to the route:
App.KbShowRoute = Ember.Route.extend({
...
actions: {
something: function() {
console.log('called second');
}
}
});
App.KbShowController = Ember.Controller.extend({
...
actions: {
something: function() {
console.log('called first');
}
}
});
see docs
You could:
Handle one part of the action in the controller, and let it bubble to the route by not returning anything in the controller's action handler
Let the route handle the action (by not adding the action to your controller's action hash) and from the route use this.controllerFor(this.routeName).sendAction('..', ...) to call a different action (or part of the action) in the controller.
I hope this helps you!

Running Code in active Controller after transitionToRoute

I'm getting to know emberjs by building a simple pomodoro app. My problem is running code in the newly active controller after a transitionToRoute has occured.
Here's where I create a new Pomodoro record:
App.PomodorosNewController = Ember.ObjectController.extend({
createPomodoro: function() {
this.get('model.transaction').commit();
this.transitionToRoute('pomodoros.pomodoro', this.get('model'));
},
});
As you can see I create the record, then transition to the newly created record's view. Which is using this controller:
App.PomodorosPomodoroController = Ember.ObjectController.extend({});
My question is how do I run code in this controller after the transition has occured? This there a way I can detect a transitionToRoute in the receiving controller?
You can implement the setupController function in your PomodorosPomodoroRoute
This will be invoked every time you transition to that route and can be used to set up your controller and anything you need for the view.
App.PomodorosPomodoroRoute = Ember.Route.extend({
setupController: function(controller, model) {
this._super.apply(this, arguments);
//implement your code here
}
});

In Ember.js does setupController and model hooks work only for dynamic segments?

I am trying to understand the setupController and model hooks, will they be invoked only in case of dynamic segments?
This is my router configuration, I see the application is working fine,but I do not see these hooks getting executed:
// Router, this need to connect view and controller
App.Router.map(function(){
this.resource("login", {path : "/"});
this.resource("home" , {path : "home/:home_id"});
});
App.Router.IndexRoute = Ember.Route.extend({
setupController:function(controller,model){
console.log("in setupController hook for index route");
}
});
App.Router.LoginRoute = Ember.Route.extend({
setupController:function(controller,model){
console.log("in setupController hook for login route");
}
});
App.Router.HomeRoute = Ember.Route.extend({
setupController:function(controller,model){
console.log("in setupController hook for login route");
}
});
Assuming you are using the latest ember (1.0.0-RC.1) You should define your routes like this:
App.HomeRoute = Ember.Route.extend({
...
});
They are part of your App, and don't have the Router part.
Working JSBin example
As a note on model and setupController hook behavior:
In a route, model will only be called when navigating directly to a URL containing a dynamic segment. The parameters passed into model are used to retrieve the model for that route using the dynamic segment.
If the route is reached using a {{#linkTo route myObject}} or transitionTo(myObject) call then the passed object is used to call setupController directly and model is not called.
The setupController hook will be called every time the route enters the
Ember API docs for model
Ember API docs for setupController