Uviews are not getting connected to controller - ember.js

Ember has a Application which has ApplicationView, ApplicationController and 'application' named template and 'main' named outlet and all these connect automatically.
eg.
App.ApplicationView = Ember.View.extend();
and
App.ApplicationController = Ember.Controller.extend();
so whenever my application template renders its default controller is an automatic instance of
App.ApplicationController
whose properties i can access in the template. But why does it not works with other views and controllers, i.e. if I have
App.SongView = Em.View.extend()
and
App.SongController = Em.Controller.extend()
these two do not connect. I can use any property of
App.SongController
in my song template.
I can use like :
{{view App.SongView}}
and in the template:
<script type='text/x-handlebars' data-template-name='song'>
{{name}}
</script>
and if i have a name property in App.SongController then it wont get picked up because its not connected to the View.
although i can do it like this
{{view App.SongView controllerBinding='App.songController'}}
but this requires the instance of App.songController in my js file and also using this approach we are hard-coding the controller to the template.
What is the best way for this?
Update
I am also attaching a js fiddle for my problem here:
http://jsfiddle.net/anshulguleria/K6KPJ/

If you want to render a template and its associated controller and view, you can use the {{render}} template. It works similarly to this.render in the router.
{{render "song" song}}
This example will render the song template with an instance of App.SongController and App.SongView. It will set the song controller's model to the value of song in the current context.
Here is a working JSBin that illustrates how this works.

Related

In Ember can the render helper get its model from the route instead of from its parameter?

On a template you can use the {{render 'route' model}} helper to embed a template and controller into another template, but this will set the model passed as an argument as the model. Is there a way to embed a route into a template but have the model come from the ebeded route's model hook? The reason why I can't use the parameter method is that the route's model is an RSVP hash and it depends on a dynamic segment.
If you need a template backed by the route, you shouldn't try to embed it somehow, just define new nested route in your router, create a tempalte and put {{outlet}} instead of {{render}}. It will do absolutely the same - resolve the route, fetch the model, setup controller and render given template.
If you still need to embed async data via {{render}} helper in some reason, you can use conditionals:
{{#if model.length}}
{{render 'template' model}}
{{/if}}

Restoring content in outlet set on the ApplicationRoute

I have an application route that is rendering a template into an outlet named 'sidebar', this should be viewable across the whole of the app. I have set up a quick example here.
When I go into one of the routes (in my example, the color route) this outlet will render a different template and when you navigate to another route in the app it should show the sidebar that was there originally.
This doesn't happen automatically and I understand it is because once the ApplciationRoute has been entered which is when the app is first loaded the renderTemplate is called and not called again until page refresh. This makes sense to me, but I'm unsure how to get around this.
I have tried re-calling the Route#render method again under the willTransition action of the ColorRoute but it doesn't work.
...
actions: {
willTransition: function() {
this.render('color.sidebar', {
into: 'application',
outlet: 'sidebar'
});
}
}
...
I just came up with another "workaround" for this using a component instead of a named outlet.
Instead of {{ outlet "sidebar" }} in your application template just use {{ x-sidebar }}
Then, define the x-sidebar component template as follows:
<script type="text/x-handlebars" id="components/x-sidebar">
{{partial sidebar }}
</script>
So, now your newly created component is expecting a sidebar property to tell it which template to display.
You can pass that property when you use the component like so:
{{ x-sidebar sidebar=sidebar }}
Then, you can use activate/deactivate hooks in your routes to set the sidebar property on the application controller, for example:
App.ColorRoute = Ember.Route.extend({
model: function(params) {
return params.color;
},
activate: function(){
this.controllerFor('application').set('sidebar', 'color/sidebar');
},
deactivate: function(){
this.controllerFor('application').set('sidebar', 'sidebar');
}
});
Working solution here
Someone apparently wrote an ember-cli addon to address this
See the following SO answer Ember sidebar - returning from "admin" sidebar to "normal"

How to get current Ember app route from template

I'm trying to set element class attributes based on current route. This is inside a navigation handlebars partial included in the Application handlebars template.
In my ApplicationController I can do something like:
isUsers: ( ->
#get('currentPath') == 'users.index'
).property('currentPath')
In the navigation template I want to do something like:
<a {{bind-attr class="isUsers:active:inactive"}} href="users"></a>
This doesn't work - inactive class is always set, even when in correct app path.
Any suggestions?
If you are defining the isUsers property in the ApplicationController, then are you sure you are using it in the application.handlebars or whatever template used by the ApplicationController? If you are using in a template which has a different Controller, make sure you use the following in your controller.
App.MyController = App.Controller.extend
needs: ['application']
In the template,
controllers.application.isUsers

Ember.js controller needs and child controller

I'm having trouble targeting a child controller from the parent controller.
Having this:
<script type="text/x-handlebars" data-template-name="parent">
<h1>Parent controller</h1>
{{control "child"}}
</script>
<script type="text/x-handlebars" data-template-name="child">
<h2>Child controller</h2>
{{controller}}
</script>
App.ParentController = Ember.Controller.extend({
needs: ["child"],
applyActionOnChild:function(){
this.get('controllers.child').someAction();
}
});
App.ParentView = Ember.View.extend({});
App.ChildController = Ember.Controller.extend({
someAction:function(){
//Called but not the right instance
};
});
App.ChildView = Ember.View.extend({});
The needs feature of ember seems to work when a child controller calls the parent controller but not for the other way around...
If I place a breakpoint in the someAction method, I can see I have a different object reference than the one displayed on the child view...
Anyone knows how this could work?
Thanks in advance
In your example you specify {{controller "child"}}, did you mean {{control "child"}}? If not hard to tell what you're trying to do.
The needs feature is for wiring together controller singletons, but The control helper renders template in context of a new controller/view pair. You can't use needs to access these controllers, since there'd be no way for needs to know which instance you meant.
Sounds like instead you want to render "child" template in context of the one true childController singleton. In that case use the render helper: {{render "child"}}

Pass context to a controller from the view in Ember

Template controlled by someParentController
{{#each post in content}}
{{view App.PostView postBinding="post"}}
{{/each}}
Setting an instance of the controller on the view
App.PostView = Ember.View.extend
post: null # set when the view is created
controller: App.PostController.create()
templateName: 'post.handlebars'
Now my view instance has the context instead of my controller instance. Is there a cleverer way to handle this? I would use an {{outlet}} if I was routing to a particular post, but the main template is displaying all posts. I want each to post to have its own controller though. It doesn't seem right to create an outlet for every post since you cannot namespace a dynamic number of outlets.
You can bypass the view entirely by using the following syntax on your action helpers in post.handlebars.
{{action someMethodOnController context="post" target="controller"}}