I'm trying to access an instance of a controller that has been wired automatically using App.initialize();
I've tried the below but it returns a Class not an instance.
Ember.get('App.router.invitesController')
I have a quick post about this exact subject on my Blog. It's a little big of a different method, but seems to work well for Ember.js RC1.
Check it out at: http://emersonlackey.com/article/emberjs-instance-of-controller-and-views
The basic idea is to do something like:
var myController = window.App.__container__.lookup('controller:Posts');
This answer works with RC1/RC2.
Now you can use the needs declaration in order to make the desired controller accessible. Here's an example:
Suppose I want to get something from my SettingsController from within my ApplicationController. I can do the following:
App.SettingsController = Ember.Controller.extend({
isPublic: true
});
App.ApplicationController = Ember.Controller.extend({
needs: 'settings',
isPublicBinding: 'controllers.settings.isPublic'
});
Now in the context of my ApplicationController, I can just do this.get('isPublic')
You can access a controller instance inside an action in the router via router.get('invitesController'), see http://jsfiddle.net/pangratz666/Pk4k2/:
App.InvitesController = Ember.ArrayController.extend();
App.Router = Ember.Router.extend({
root: Ember.Route.extend({
route: '/',
index: Ember.Route.extend({
route: '/',
connectOutlets: function(router, context) {
var invitesController = router.get('invitesController');
},
anAction: function(router) {
var invitesController = router.get('invitesController');
}
})
})
});
You can access any controller instance by name using lookup method of Application instance.
To get Application instance you can use getOwner from any route or controller.
const controllerName = 'invites';
Ember.getOwner(this).lookup(`controller:${controllerName}`));
Works for me in Ember 2.4 - 3.4.
Related
Suppose I have a variable title that runs an observer like below.
Ember.Route.reopenClass({
title: 'Ember Application',
_titleDidChange: function(){
console.log('Title Updated');
}.observes('title')
});
So whenever now a route is created and a new title is set i am expecting its observer to run. But its not happening.
App.IndexRoute = Ember.Route.extend({
title: 'index Route',
model: function() {
return ['red', 'yellow', 'blue'];
}
});
What should be done to make this functionality work like i wanted?
Here is the jsbin link
http://emberjs.jsbin.com/neges/1/edit
UPDATE: ok..i found something from EmberJS github. They are already trying to implement title same way but need to do changes in ember.js which is not an option for me. Any Simple way to do same https://github.com/emberjs/ember.js/pull/3689/files#r9367594
How about this:
App = Ember.Application.create();
Ember.Route.reopen({
title: 'Ember Application',
_titleDidChange: function(){
console.log('Title Updated: ' + this.get("title"));
}.observes('title').on("init")
});
App.IndexRoute = Ember.Route.extend({
title: 'index Route'
});
Two crucial changes were needed to make your code to work:
Switched from reopenClass to reopen. reopenClass is used to add static properties to the class itself, not its instances.
Added on("init"), which will ensure property change events will trigger during object initialization, which is what you need.
Updated jsbin is here.
What is the new way to get from a controller the value of an instance variable of an other controller.
For instance, I was using before I was using before
App.router.get("applicationController.isLoopingEnabled") to access the value and App.router.set("applicationController.isLoopingEnabled") to set the value of isLoopingEnabled variable from my PlaybarController instance.
I just want to know what is the best practice right now on Ember RC3. I'm experiencing a lot of problems to upgrade from the pre-version.
There isn't "one way" to access properties of different controllers anymore. It depends on where you want to access it from.
To access a controller from another controller:
Use the Controller's needs depedency
Example:
App.PostsController = Em.ArrayController.extend({
someValue: 1
});
App.CommentsController = Em.ArrayController.extend({
needs: ['posts'],
postsValuePlusOne: function() {
return this.get('controllers.posts.someValue') + 1;
}).property('controllers.posts.someValue')
});
To access a controller from a route:
App.PostsController = Em.ArrayController.extend({
someValue: 1
});
App.CommentsRoute = Em.Route.extend({
renderTemplate: function() {
var someValue = this.controllerFor('posts').get('someValue');
}
});
To access a controller from a view:
App.PostsController = Em.ArrayController.extend({
someValue: 1
});
App.PostsView = Em.View.extend({
someValueBinding: 'controller.someValue'
});
If you want to access a value of a controller other than the view's controller (for example CommentsController, use the controller's needs: controller.controllers.comments.someValue
Finally,
There is a global method to access any controller, but use this only for debugging and testing, never in production:
var postsController = App.__container__.lookup('controller:posts')
From this [EDIT] [ToDo's sample]1, [/EDIT] I can connect a View via the connectOutlet. Is there an updated example for this using RC1?
index: Ember.Route.extend({
route: '/',
connectOutlets: function( router ) {
var controller = router.get( 'applicationController' );
var context = controller.namespace.entriesController;
context.set( 'filterBy', '' );
// This require was left here exclusively for design purposes
// Loads decoupled controller/view based on current route
require([ 'app/controllers/todos', 'app/views/items' ],
function( TodosController, ItemsView ) {
controller.connectOutlet({
viewClass: ItemsView,
controller: TodosController.create(),
context: context
});
}
);
}
}),
Actually the example you are linking should work. As you might know the Router API has changed and the code based on pre4 should still work. I am not aware of the requirements for the Todos App, so i cannot 100% tell, if it still works:
Todos.Router.map(function() {
this.resource('todos', { path: '/' }, function() {
this.route('active');
this.route('completed');
});
});
Todos.TodosRoute = Ember.Route.extend({
model: function() {
return Todos.Todo.find();
}
});
Todos.TodosIndexRoute = Ember.Route.extend({
setupController: function() {
var todos = Todos.Todo.find();
this.controllerFor('todos').set('filteredTodos', todos);
}
});
Here a little summary of the changes to the old router API:
You don't extend the Ember.Router Class anymore.
The URL Mappings don't reside in the Routes anymore. This is done via Todos.Router.map.
There is no connectOutlets event anymore in your routes. Instead there are 3 events you can implement: model(), setupController() & renderTemplate().
A little explanation on the hooks:
model(): Is called once when your route is entered via URL. This should return your model, which should become the content of your controller.
setupController(): Here you can get your controller and set its content how you may like. The default implementation sets the controller, that is name matching your route to the result of model().
renderTemplate(): Inside this hook you should use the new render method of routes to do the rendering. The render method is somehow the method that matches the old connectOutlets the most. There is also default implementation. Therefore it is also not implemented in the pre4 version of todomvc.
As Milkyway stated, you realy have to read the guides, but i hope this gets you started a little bit better.
i run into the following problem when building a router based app with emberjs. My app is simplified structured as following:
var App = Em.Application.create({});
App.ApplicationController = Em.Controller.extend({});
App.ApplicationView = Em.View.extend({
template : Em.Handlebars.compile('APPLICATION TEMPLATE')
});
App.RootState = Em.Route.extend({
index : Em.Route.extend({
route : "/"
})
})
App.Router = Em.Router.extend({
root : App.RootState
});
// initialize the app here
App.initialize();
// extend the RootState from anywhere. eg. from a plugged widget
App.RootState.reopen({
login : Em.Route.extend({
route : "/state1"
})
});
//App.initialize(); //init the app a second time forces unexpected behaviour
App.RootState.reopen({
alarms : Em.Route.extend({
route : "/state2"
})
});
//App.initialize();
Like my app demonstrates, i try to extend the router with new routes at runtime. I know that there exists another thread with similar question exists, but the discussed example do not work for me.
How can i extend my router at runtime with additional routes, without calling initialize() after every ...reopen({ }).
The background for doing this is to decide at runtime how the application is look like, for example to plug in different wigets with their own routes.
Regards,
T
I implemented the following using latest ember.js (0.9.8.1) by referring to Ember Router not updating url in Chrome and Safari. When I try switch b/w routes via router.transitionTo('route path') method (last 3 lines of the attached snippet), browser url is not updated correctly, but I do see the view markup being updated confirming that state change do happen. Could some help in identifying whether am I missing something here?
BTW: I tested this in Chrome 20.0.1132.27 beta-m
App = Ember.Application.create({});
App.IndexView = Ember.View.extend({
template: Ember.Handlebars.compile(
'hello world from index'
)
});
App.ShowView = Ember.View.extend({
template: Ember.Handlebars.compile(
'hello world from show'
)
});
App.Router = Ember.Router.extend({
location: 'hash',
enableLogging: true,
root: Ember.State.extend({
index: Ember.State.extend({
route: '/',
redirectsTo: 'tasks'
}),
tasks: Ember.State.extend({
route: '/tasks',
index: Ember.ViewState.extend({
route: '/',
view: App.IndexView
}),
show: Ember.ViewState.extend({
route: '/show',
view: App.ShowView
})
})
})
});
var router = App.Router.create({});
App.initialize(router);
router.transitionTo('root');
router.transitionTo('root.tasks');
router.transitionTo('root.tasks.show');
I ran your code, and in the console, I have the following error "Object hash has no method 'setURL'". By debugging a bit, I found that you have to define the location of the Router with:
location = Ember.Location.create({ style: 'hash' })
or
location = Ember.Location.create({implementation: 'hash'})
I don't know why exactly, but it seems to work. Perhaps it's only due to ember version.
You are mixing up 2 initialization methods.
When you define App.Router all you need to do is call App.initialize(). It automatically creates an instance of Ember.Router and assigns it to the variable App.stateManager. You can then use App.stateManager to call transitionTo.
You can define the variable router to extend Ember.Router then call App.initialize(router). This method also creates an instance of Ember.router and assigns it to App.stateManager. You can then use App.stateManager to call transitionTo.
Either of the methods will work but I prefer method 1. To manipulate the route we always use App.stateManager.