I'm using ember tools for my app. Now I want to add a TextField to trigger a search in my controller, like in this example. This is the controller and view:
ProductsController:
var ProductsController = Ember.ArrayController.extend({
search: function(query) {
console.log(query);
}
});
module.exports = ProductsController;
SearchFieldView:
var SearchFieldView = Ember.TextField.extend({
insertNewline: function() {
var query = this.get('value');
App.ProductsController.search(query);
}
});
module.exports = SearchFieldView;
But whenever the textfield is changing I've got the error that the App.ProductsController has no method search. So I've got the feeling it is not the one I have created but the generated one.
You can use this.get('controller') to get the current controller instance. or if u need a another controller instance you can use this.get('controller').get('controllers.anothercontroller').. JSBin
Hope it helps.
Ok, I've got it. App.ProductsController isn't the instance of the actual controller and as all views under route have the same controller its just this.get('controller')
var SearchFieldView = Ember.TextField.extend({
insertNewline: function() {
var query = this.get('value');
this.get('controller').search(query);
}
});
module.exports = SearchFieldView;
Related
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.
I'm trying to develop this single-module application with a master-detail relationship between two routes. The master is supposed to have a model which is initially loaded and subsequently updated with a single Server-Side-Events entry point. I have the following code so far:
var App = Ember.Application.create({
rootElement: '#content'
});
App.Router.map(function() {
this.resource('receptores', {path: '/'}, function() {
this.resource('receptor', {path: ':user_id'});
});
});
App.ReceptoresController = Ember.Controller.extend({
init: function() {
var sse = new EventSource('/push');
var controller = this;
sse.addEventListener('update-hhs', function(e) {
controller.set('model', JSON.parse(e.data).receptores);
});
}
});
App.ReceptorRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('receptores').findBy('id', params.user_id);
}
});
Loading the 'receptores' works and currently the data loads fine. Clicking on a link-to generated link as http://localhost:5003/#/skkkd, for example, will load the 'receptor' route and the detail data as well (the detail is just a subset of the same data loaded on the master).
If I try reloading at a detail url or entering http://localhost:5003/#/skkkd directly I'll get the following exception:
Error while loading route: TypeError: Cannot read property 'findBy' of undefined
at App.ReceptorRoute.Ember.Route.extend.model (http://localhost:5003/monitoreo/static/js/receptores.js:34:43)
at superWrapper [as model] (http://localhost:5003/static/js/ember-1.5.1.js:1292:16)
at Ember.Route.Ember.Object.extend.deserialize (http://localhost:5003/static/js/ember-1.5.1.js:36570:19)
at http://localhost:5003/static/js/ember-1.5.1.js:32972:57
at http://localhost:5003/static/js/ember-1.5.1.js:33464:19
at invokeResolver (http://localhost:5003/static/js/ember-1.5.1.js:9646:9)
at new Promise (http://localhost:5003/static/js/ember-1.5.1.js:9632:9)
at Router.async (http://localhost:5003/static/js/ember-1.5.1.js:33463:16)
at Object.HandlerInfo.runSharedModelHook (http://localhost:5003/static/js/ember-1.5.1.js:32971:16)
at Object.UnresolvedHandlerInfoByParam.getModel (http://localhost:5003/static/js/ember-1.5.1.js:33058:19)
I know the problem is the init hook isn't being called for ReceptoresController. I think what I should do is implement a model hook on either a ReceptoresRoute or the controller and load initial data through a jQuery.get() and have the server-side-events only update. But then where do I initialize the SSE?
Edit:
It turns out I misunderstood how the model hook works on child routes. In my case, I normally view the detail page through a link-to link, so Ember already provides the model for receptor. The model hook is never called in that case. It is only called when trying to access the detail page directly which is where it fails. So my problem remains.
My whole problem boils down to where I should place the SSE initialization so that both routes can have access to the same model regardless of which was loaded.
Alright, this is my solution. Pieced together from a couple questions here. Namely https://stackoverflow.com/a/21988143/410224 and https://stackoverflow.com/a/21752808/410224. Hope it helps someone out.
var App = Ember.Application.create({
rootElement: '#content'
});
App.Router.map(function() {
this.resource('receptores', {path: '/'}, function() {
this.resource('receptor', {path: ':user_id'});
});
});
App.ReceptoresRoute = Ember.Route.extend({
model: function() {
var deferredData = Ember.Deferred.create();
var data = [];
var sse = new EventSource('/push');
sse.addEventListener('update-hhs', function(e) {
var receptores = JSON.parse(e.data).receptores;
receptores.forEach(function(r) {
var item = data.findBy('id', r.id);
if (typeof(item) != 'undefined') {
data.replace(data.indexOf(item), 1, [r]);
} else {
data.pushObject(r);
data.sortBy('full_name');
}
});
deferredData.resolve(data);
});
return deferredData;
}
});
App.ReceptorRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('receptores').findBy('id', params.user_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')
I'm trying to learn more about the core of ember by reading the source and unit testing various components. Currently I'm trying to wire up a simple view/controller/template combination to see if I can assert against the view (actual html output) that gets rendered w/ a given model and template.
My first test that does work looks like this
it ("template will render given output", function(){
var view = Ember.View.create({
template: Ember.Handlebars.compile('bar')
});
Ember.run(function() {
view.appendTo("#body");
});
expect(Ember.$.trim(view.$().text())).toEqual("bar");
});
But this is not doing anything dynamic w/ a model or controller. My next attempt is currently failing because I can't seem to wire in the view (to a given controller).
it ("model property is output when view bound", function(){
var speaker = CodeCamp.Speaker.createRecord({id: 1, name: 'foobar'});
var view = Ember.View.create({
template: Ember.Handlebars.compile('{{#each foo in controller}}{{foo.name}}{{/each}}')
});
var controller = Ember.ArrayController.create({
content: []
});
get(controller, 'content').push(speaker);
var x = get(controller, 'content');
var len = get(get(controller, 'content'), 'length');
expect(len).toEqual(1);
set(controller, 'view', view);
Ember.run(function() {
view.appendTo("#body");
});
expect(Ember.$.trim(view.$().text())).toEqual("foobar");
});
But as it stands now the assertion fails
Expected '' to equal 'foobar'.
This is caused by this line:
set(controller, 'view', view);
It has to be:
set(view, 'controller', controller);
Summary: The view has to know about its controller. In your case the view does not have a context to lookup properties and therefore does not work. You accidentally did it the other way round.
Note: This applies to Ember-pre4. I tested this fix successfully against it. (I believe the approach to view setup has changed recently)