I am migrating my project from older version of EmberJS. In some places i used to get controller instance which is not related to the view, by using following in any view's init() method:
var controller = App.get('router').get('firstController');
But now this throws following error.
Uncaught TypeError: Cannot call method 'get' of undefined
This may be because it is not able to get the Router object. Now how to get controller instance which is not related to the view? or how to get the Router Object
The 'needs' feature allows a controller to access to other controllers, which allows a controller's view to access other controllers. (a good explanation of needs in Ember: http://darthdeus.github.com/blog/2013/01/27/controllers-needs-explained/)
As explained in Cannot access Controller in init function of View in 1.0.0rc, the controller property of a view is not yet set when init() is called, so you will need to access controller at a later time in the view's life cycle. This could be the willInsertElement() or didInsertElement() hooks, for example.
Here is an example demonstrating using needs access another controller from a view:
http://jsbin.com/ixupad/186/edit
App = Ember.Application.create({});
App.ApplicationController = Ember.Controller.extend({
doSomething: function(message) {
console.log(message);
}
});
App.IndexView = Ember.View.extend({
templateName: 'index',
init: function() {
this._super();
// doesn't work, controller is not set for this view yet see:
// https://stackoverflow.com/questions/15272318/cannot-access-controller-in-init-function-of-view-in-1-0-0rc
//this.get('controller.controllers.application').doSomething("from view init");
},
willInsertElement: function() {
this.get('controller.controllers.application').doSomething("from view willInsertElement");
},
clickMe: function() {
this.get('controller.controllers.application').doSomething("from clickMe");
}
});
App.IndexController = Ember.Controller.extend({
needs: ['application']
});
Related
I have written a view:
export default Ember.View.extend({
select: null,
modify: null,
createSelect: function() {
return new ol.interaction.Select();
},
onMapCreated: function() {
this.select = this.createSelect();
this.modify = this.createModify();
},
init: function() {
this._super();
this.get('controller').addObserver('olMap', this.onMapCreated);
},
});
The view is added in a template related to a controller which has an olMap property.
I need to wait for the olMap property to be instantiated before doing some work in my view.
The code above is kind of working, except that the this referenced in the onMapCreated function is the controller's instance and not the view's instance.
I'm quite sure I am doing something wrong in my application's design. I would like to separate the concerns and get the drawing part outside of the main controller. Should I use a component? Not sure because it's not going to be reusable...
I would love to have some directions here.
After reading the manual in the API section, I came up with the solution. I post it here is someone needs it someday. Actually, all I had to do is add a parameter this to the addObserver method in order to change the context.
export default Ember.View.extend({
select: null,
modify: null,
createSelect: function() {
return new ol.interaction.Select();
},
onMapCreated: function() {
this.select = this.createSelect();
this.modify = this.createModify();
},
init: function() {
this._super();
this.get('controller').addObserver('olMap', this, this.onMapCreated);
},
});
Here is what I've ended up with:
My setup:
Ember : 1.10.0
Ember Data : 1.0.0-beta.16
jQuery : 1.11.2
Directory structure:
controllers:
map.js
map-draw.js
templates
map.hbs
map-draw.hbs
views
map.js
map-draw.js
in the template templates/map.js I use a render helper like this:
{{render "mapDraw" mapDraw}}
the renderer uses the controller controllers/map-draw.js and the view views/map-draw.js
content of the view map-draw.js:
export default Ember.View.extend({
templateName: "mapDraw",
classNames: ["map-draw"]
});
in the controller map-draw.js I am binding the map.js controller.
export default Ember.Controller.extend({
needs: ['map'],
olMap: null,
//...//
init: function() {
this._super();
this.get('controllers.map').addObserver('olMap', this, function(sender) {
this.set('olMap', sender.get('olMap'));
});
}
//...//
});
I'm trying to load the current user into the data store but am having some difficulty. The server uses PassportJS and visiting /api/users/me returns a JSON object similar to this:
{"user":{"_id":"53a4d9c4b18d19631d766980","email":"ashtonwar#gmail.com",
"last_name":"War","first_name":"Ashton","location":"Reading, England",
"birthday":"12/24/1993","gender":"male","fb_id":"615454635195582","__v":0}}
My store is just defined by App.store = DS.Store.create();
The controller to retrieve the current user is:
App.UsersCurrentController = Ember.ObjectController.extend({
content: null,
retrieveCurrentUser: function() {
var controller = this;
Ember.$.getJSON('api/users/me', function(data) {
App.store.createRecord('user', data.user);
var currentUser = App.store.find(data.user._id);
controller.set('content', currentUser);
});
}.call()
});
It is called by my application controller:
App.ApplicationController = Ember.Controller.extend({
needs: "UsersCurrent",
user: Ember.computed.alias("controllers.UsersCurrent")
});
I suspect the line App.store.createRecord('user', data.user); is causing issues but I don't have any idea how to fix it.
The console logs TypeError: this.container is undefined while the Ember debugger shows every promise is fulfilled and the users.current controller has no content. Thankyou for any help you can provide.
Are you defining the store on the App namespace, because Ember Data doesn't do that by default. Either way, you're failing to define the type you want to find after you create the record.
var currentUser = controller.store.find('user', data.user._id);
createRecord returns the record, so there is no point in finding it afterward
var currentUser = controller.store.createRecord('user', data.user);
Also in your example, you are trying to call the function immediately on the type, and not on the instance. You should add that as a method to run on init.
App.UsersCurrentController = Ember.ObjectController.extend({
retrieveCurrentUser: function() {
console.log('hello')
var controller = this;
Ember.$.getJSON('api/users/me', function(data) {
var user = controller.store.createRecord('user', data.user);
controller.set('model', user);
});
}.on('init')
});
http://emberjs.jsbin.com/OxIDiVU/693/edit
I am using a radialProgress as a jQuery plugins (homemade), and I need to implement it for ember but I have some issue to do that.
Quick explanation for the plugins :
var chart = $(yourElement).pieChart(options); // initialise the object to an element
chart.setCompleteProgress( complete, false ); // set how many item you have to complete the task
chart.incrementProgress(); // increment + 1 every time you call it
It's a very simple progress pie.
In my case my task are located inside my controller, but the chart as to select a dom element so I need to initialise it inside my view.
My task in the controller are called from the router from the setupController to reload the model over time.
Here is a small sample of what I would like to do :
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
var promise = controller.getModel();
this._super(controller, promise);
}
})
App.ApplicationController = Ember.ArrayController.extend({
getModel: function() {
// chart.setcompleteProgress();
// A lot of code are here to get some data
// chart.incrementProgress();
return newModel;
}
})
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
var chart = $(element).pieChart(opts);
}
})
I don't know how to pass the chart object from the view to the controller to be able to have access to my plugin function.
Che chart won't be inserted into the DOM until the didInsertElement therefore you can't attempt to manipulate it in the route during setupController etc. I'd suggest creating a method in the controller setupChart and calling that on didInsertElement.
App.ApplicationView = Ember.View.extend({
prepPieChart: function() {
var chart = $(element).pieChart(opts);
this.get('controller').setupPieChart(chart);
}.on('didInsertElement')
})
App.ApplicationController = Ember.ArrayController.extend({
setupPieChart: function(chart) {
chart.setcompleteProgress();
// A lot of code are here to get some data
chart.incrementProgress();
}
})
All that being said, maybe it belongs in the view, but I'm not sure of what you're completely doing.
How to access application controller from another controller?
Or
How to access another controller from controller?
Application Controller:
App.ApplicationController = Ember.ObjectController.extend({
findPersonById: function(id) {
.....
....
}
});
Below is the way to access application controller function inside comments controller.
Comments Controller
App.CommentsController = Ember.ArrayController.extend({
needs: ["application"],
getComments: function() {
var person = this.get("controllers.application").findPersonById(id);
....
....
}
});
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')