Pass context to a controller from the view in Ember - ember.js

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"}}

Related

How to set specific view in emberJS with itemcontroller

I have the following code:
{{#each categories.items itemController="item"}}
When I open the Ember inspector, it shows the view to be "virtual". I want to set the view to be "item" so that it follows the ember view I set out called itemView. I know we can set an itemController: is it possible to set an item view?
Yes it is possible using the optional 'itemViewClass' parameter.
{{#each categories.items itemController="item" itemViewClass="otherView"}}
Though I would recommend discontinuing using that and itemController as the latest Best Practice is to use a component within the each block.
So for your example:
// Ember 1.10+
{{#each categories.items as |item|}}
{{some-component item=item}}
{{/each}}
// Ember 1.9-
{{#each item in categories.items}}
{{some-component item=item}}
{{/each}}
Then you put your logic needed in the component object instead of the item controller.

Emberjs: Accessing parent route model which is a Promise (master-detail)

I've got master-detail page layout as on image. I access this page through #/masters/:master_id app url.
Routes a defined as follows:
App.Router.map(function() {
this.resource('masters', { path: '/masters' }, function() {
this.route('detail', { path: '/:master_id' });
});
});
App.MastersRoute = Ember.Route.extend({
model: function() {
return App.DataStore.getData('/api/masters'); //returns Promise!
},
setupController: function(controller, model) {
controller.set("content", model);
}
});
App.MastersDetailRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor("masters").find(function(item) {
return item.get("id") == params.master_id;
});
}
});
Templates:
<script type="text/x-handlebars-template" data-template-name="masters">
<div id="masters-grid">
{{#each master in model}}
<div {{action "show" master}}>
{{master.name}}
</div>
{{/each}}
</div>
<div id="detail">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars-template" data-template-name="masters/detail">
{{model.name}} <br />
{{model.age}} <br />
{{model.address}} <br />
</script>
When clicking through masters in the grid I want to show their details in Detail outlet and I do not want to reload all masters from API when changing the master selection.
I have a problem with MastersDetailRoute's model, because this.modelFor("masters") returns undefined. I think, it is caused by returning Promise in model hook. Any idea or workaround how to access one item from Masters model or controller in "child route" model hook?
I see a few things here.
when defining routes that have the same url as the route name theres no need to specify the path
the detail route should also be a resource as it is a route backed by a model
In the Masters route returning a promise is correct and supported natively by ember. The route wont be resolved until the promise is.
setup controller isn't required
its usually best to do the required api call to fetch the individual record in the detail route. This will only be used when loading the page for the first time (if f5 ing or coming from a bookmark)
in your masters template you can use id instead of typing data-template-name or better still look into use ember-cli/brocolli or grunt to precompile your templates
to prevent ember refetching your model when selecting a row use the handlebars helper link-to
{{#link-to 'masterDetail' master}}
{{master.name}}
{{/link-to}}
just to clarify, using link-to in this way passes the object specified in the second parameter as the model to the specified route (first parameter). In your case master will now be set as the model to the master detail route.
in masters detail theres no need to type "model" the default context (i.e. the value of "this") in your template is the controller, then if the property is not found on the controller it looks for it in the model.
Hope this helps

dynamic outlet name in ember js

Requirement: There will be few buttons, and on clicking every button the immediate outlet will be rendered with a view. (not the other outlets present in the page)
Suppose I'm creating outlets in #each.
{{#each item in model}}
<#link-to 'passenger' item.id>Open Corresponding Outlet </link-to>
{{outlet item.id}}
{{/each}}
and from back i'm rendering the outlet:
model: function (params) {
return [
{ id: params.passenger_id}
]
},
renderTemplate: function () {
this.render({ outlet: this.get('controller.model')[0].id });
},
This just doesn't work.
Can anyone help me to do that?
You can't create dynamic named outlets, and it would break the url representing the page you are viewing concept which the core members preach heavily.
You should just render in the template using the render helper, and use
{{#each item in model}}
{{render 'something' item}}
{{/each}}
And inside the something controller/template you can add additional logic for how you'd like it to interact.
Additionally you could just add another resource under your passenger route and ad an outlet which hosts that information when it's clicked.
Not sure if you're still looking for a solution, as #kinpin2k mentioned you can't use dynamic outlets, but perhaps a dynamic partial would help.
Like so:
{{partial someTemplateName}}
Where someTemplateName can be any computed property in your controller. If the property returns falsy then nothing will be displayed.
Here's the reference: http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#toc_bound-template-names

Uviews are not getting connected to controller

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.

Binding a controller using ember view helper, or, conditional outlet usage

I am trying to accomplish something like this, in an ember view:
{{#if loggedIn}}
<p> I'm Logged In! </p>
{{else}}
{{view App.LoginView contentBinding="App.UserInfo"}}
{{/if}}
This doesn't work out of the box because the context for LoginView ought to be loginController, and *that controller's content" ought the be App.UserInfo.
This discussion has some related notes, and suggests outlets:
Instantiate a controller class using the {{view}} helper?
Outlets provide a clean solution to this - for example, I could do:
{{#if loggedIn}}
<p> I'm Logged In! </p>
{{else}}
{{outlet login}}
{{/if}}
and then have the router connect the controller for this view (call it homeController) to the login outlet with LoginView and some context.
However, using outlets, if the loggedIn property changes, the outlet isn't reconnected/redrawn, so if I log in and then log out again I get a blank page.
Is there a nice way to either bind the appropriate controller and controller content using the view helper, or set up the outlet in a way that makes it redraw appropriately if the loggedIn property changes?