So, I am trying to get a simple propertyBinding to work with emberjs. Specifically, I have a controller with a content property, that gets updated under certain circumstances and a view, which needs that content array to draw some chart.
I have made the most basic example and it doesn't seem to work. My simple example is the following:
Appname.IndexController = Ember.Controller.extend({
value: 'bla'
});
Appname.IndexView = Ember.View.extend({
templateName: 'Index',
propertyBinding: 'Appname.IndexController.value',
didInsertElement: function() {
console.log('Indexview');
console.log(this.get('property'));
}
});
It is as simple as that, and it just does not work. What is really odd though, if I create another testcontroller (rather then extending it) e.g.
Appname.TestController = Ember.Controller.create({
value: 'jpopo'
});
the property binding works all of the sudden. But I just can not get it to work with the IndexController
(And in case the information is necessary, in the Applicaton.hbs I have an outlet)
Thanks for any help
Bindings work for instantiated objects, not for object definitions.
Appname.IndexController is the controller definition, not an instance. It is not what you want to bind to. The Ember.js app will create an instance of IndexController, and it's that created instance that you want to bind to:
To access the actual controller instance from its view, use controller.
Appname.IndexView = Ember.View.extend({
templateName: 'index',
propertyBinding: 'controller.value',
didInsertElement: function() {
console.log(this.get('property'));
}
});
Of course, that is if you follow Ember.js conventions.
Related
I'm trying to change a controller's property from a component as follows(JSBIN example http://jsbin.com/gevuhu):
App.CategoryManagerController = Ember.Controller.extend({
selectedCategory: null,
});
App.BlogPostComponent = Ember.Component.extend({
needs: ['categoryManager'],
selectedCategory: Ember.computed.alias('controllers.categoryManager.selectedCategory'),
actions:{
selectedCategory: function (){
this.set('selectedCategory',1);
}
}
});
but getting the error Property set failed: object in path "controllers.categoryManager" could not be found or was destroyed.
Is it that we cannot use "needs" in components ?
Ember Components are completely isolated from surrounding context including controllers (see here). That's the bad news. The good news is that if you pass selectedCategory into the component, it will become 2-way bound, so any change to it in the component will be known by your controller.
So, your controller could be something like:
App.ApplicationController = Ember.ObjectController.extend({
needs: ['categoryManager'],
selectedCategory: Ember.computed.alias('controllers.categoryManager.selectedCategory'),
selectedCategoryChanged: function(){
alert("NEW CATEGORY: " + this.get('selectedCategory'));
}.observes('selectedCategory')
});
and then in your application template, you can say
{{ blog-post selectedCategory=selectedCategory }}
See a working example here
In later version like 2.2. We'll be writing this as:
App.ApplicationController = Ember.Controller.extend({
categoryManager: Ember.inject.controller("categoryManager")
});
and now, categoryManager will now have the controller named categoryManager.
Uncaught Error: Assertion Failed: `<(subclass of Ember.ObjectController):ember947> specifies `needs`, but does not have a container. Please ensure this controller was instantiated with a container.
If for some reason a controller doesn't have a container, how can I provide it with one? Context is below, but that is essentially the question being asked.
The context is that there apparently is not a straightforward way of providing controllers for the individual items in Ember.CollectionView, a problem which is outlined at ember.js/issues/4137.
It seems the only way to get item controllers is to declare the them inline in the init method for an inline itemViewClass declaration of the CollectionView (as confirmed by the originator of that ticket):
var someCollectionView = Ember.CollectionView.extend({
itemViewClass: Ember.ListItemView.extend({
templateName: "foo-item",
init: function(){
var content = this.get('content');
var controller = Ember.ObjectController.extend({
// controller for individual items in the collection
actions: {
// actions specific to those items
}
}
}).create({
content: content,
});
this.set('controller', controller);
this._super();
}
})
});
So this works, however if you add a "needs" property to this controller, it gives the error about no container. These item controllers will be observing a property on an external controller, so I need the "needs". So how do I instantiate the controller with the container... or hack it in after instantiation?
Accessing App.__container__ is generally adviced against. All core objects like views, controllers, routes, should have been instantiated by the container. In that case they will also have a container property (plain JS property, not an Ember property), that you can use to instantiate other objects, which in turn will have access to the container.
So instead of
Ember.ObjectController.create(...)
try
this.container.lookupFactory('controller:object').create(...)
If container is undefined you'll have to go up the chain, and make sure whatever object you're calling this from is also coming out of the container.
It looks like you can do
...
}).create({
content: content,
container: App.__container__
});
this.set('controller', controller);
this._super();
}
})
});
Working hard on my Ember app here, and it's going along fine. However, I've run into an issue of unexpected behaviour and I'm not sure regarding the best approach to this problem.
The problem is that in a specific route, I want to render another route into another outlet. However, the other route that I render into the other outlet doesn't retain it's own model.
If I do this:
App.TestRoute = Ember.Route.extend({
model: function() {
return {
heading: "Test",
testContent: "This is test."
}
}
});
App.IndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render("test", {
outlet: "left"
});
this.render({
outlet: "right"
});
},
model: function() {
return {
heading: "Index",
indexContent: "This is index."
}
}
});
... and access the IndexRoute, I would expect the TestRoute's model to be rendered into the TestRoute's template, but only the IndexRoute's model is relayed to both templates.
Fiddle here:
http://jsfiddle.net/3TtGD/1/
How do I allow Ember to use the default model for a route without having to expressively merge them? It seems tedious.
Also, having the same name of some model properties, like {{heading}} is desirable, but not necessary.
What's the best approach for solving this issue?
Thank you for your time.
Best regards,
dimhoLt
In the renderTemplate method you're telling Ember to render a template inside an outlet but it will just default the controller to the one managing the route. Given it's the controller handling the route it makes sense that it manages all the templates within that route.
Of course you can specify a different controller using:
this.render("test", {
outlet: "left",
controller: 'test'
});
it can in turn be a controller you already instantiated (and maybe set its content):
var testController = this.controllerFor('test');
testController.set(....)
this.render("test", {
outlet: "left",
controller: testController
});
About using the model: You can call this.modelFor('test') inside the route and it will return the model of the test route (it even knows if it has already been resolved). I usually do this when I need to access the model of one of the parent routes.
I believe it makes sense to access the model of a parent route, but not so much if you're accessing the model of an unrelated route. Why don't you want to merge both models?
I'm trying to use the 'needs' feature to allow one controller to obtain a value from another. Here's a JSFiddle that shows a stripped-down version of my app before binding a value: http://jsfiddle.net/kevinwh/WRxnE/4/
App.ApplicationController = Ember.ObjectController.extend({
init: function() {
this._super();
},
dishClicked: function() {
console.log('clicked');
this.incrementProperty('clickCount');
}
});
App.DishController = Ember.ObjectController.extend({
needs: ['application'],
init: function() {
this._super();
},
//clickCountBinding: 'controllers.application.clickCount'
});
Basically, my ApplicationController has a clickCount property that is updated (by an action) whenever one of the Dish links is clicked. Clicking on a link also activates the DishRoute via linkTo.
Now I'd like the contained DishController to also have access to ApplicationController's clickCount. So I add the 'needs' property and a clickCountBinding property (which will have to be uncommented in the JSFiddle). Then, when I click on a link I get a complaint:
assertion failed: Cannot delegate set('clickCount', 0) to the 'content' property of object proxy : its 'content' is undefined.
Apparently the binding is being activated before the model content is set on the controller. Since the controller is being set up by the linkTo, my DishRoute.model() and DishRoute.setupController() methods are not invoked. Also, the DishController.init() method isn't even called before the binding error happens.
I considered the possibility that I should just stick a content member object into the class (commented out in the JSFiddle), but doing that gives a bizarre result: the click count is incremented separately for the different links. Interesting, but not what I'm after.
So - how do I share the clickCount value across these controllers? Is there some other way to set up the content in the DishController so that the binding will work?
You've just slightly misunderstood the error message.
The issue is that you've subclassed the ApplicationController from ObjectController even though it doesn't have an underlying content object to proxy to, you should just user Ember.Controller in this case.
That being said, if you have a counter you should probably default it to zero anyway.
App.ApplicationController = Ember.Controller.extend({
clickCount: 0,
dishClicked: function() {
console.log('clicked');
this.incrementProperty('clickCount');
}
});
App.DishController = Ember.ObjectController.extend({
needs: ['application'],
clickCountBinding: 'controllers.application.clickCount'
});
I have a property in my Ember controller which I wanted to bind to a property in application controller but since I have not created an instance of ApplicationController, thus I am not able to give the reference. Something like,
MyApp.ApplicationController = Em.Controller.extend({
userName: 'hohenhiem'
});
MyApp.SampleController = Em.Controller.extend({
nameBinding: 'application.userName'
});
i have a jsFiddle to show my problem here
You are looking for the needs property. In a controller you can specify dependencies and then use them as follows:
MyApp.SampleController = Em.Controller.extend({
needs: ['application'],
nameBinding: 'controllers.application.userName' });
http://jsfiddle.net/yCr4F/1/