How to make linkTo dynamic in ember? - ember.js

<script type="text/x-handlebars" data-template-name="patient">
<ul class="nav">
{{#each menuItem in menuItems}}
<li>{{#linkTo "dashboard.summary" menuItem}}{{menuItem.name}}{{/linkTo}}</li>
{{/each}}
</ul>
{{outlet}}
</script>
In the above code, how do I make linkTo a dynamic link instead of the hardcoded "dashboard.summary"? For example, "dashboard."+menuItem.name.

In the current Ember (1.10 as of this post), helpers now accept both quoted arguments or arguments that will be looked up as attributes in the current context. I believe this was changed in Ember 1.2 ( change log ).
If quoted, the argument will be used as a string:
{{#link-to 'post'}}Posts{{/link-to}}
If not quoted, the argument will be looked up in the current context:
{{#link-to routeName}}Go To '{{routeName}}'{{/link-to}}
This will be a link-to that points to whatever the routeName property currently is set to. This can be updated dynamically.
Here is an example JSBin showing this in action: http://emberjs.jsbin.com/nelafep/1/edit?html,css,js,output

You could register a simple Handlebars helper that wraps the linkTo helper.
var linkTo = Ember.Handlebars.helpers.linkTo;
Ember.Handlebars.registerHelper('myLinkTo', function(name, suffixPath) {
var suffix = Ember.Handlebars.get(this, suffixPath);
arguments = [].slice.call(arguments, 2);
arguments.unshift(name + '.' + suffix);
return linkTo.apply(this, arguments);
});
Then in your template you could write:
{{#each menuItems}}
<li>{{#myLinkTo "dashboard" name this}}{{name}}{{/myLinkTo}}</li>
{{/each}}
The helper will resolve the second argument and append it to the first, preceded by a dot.
Edit: this behaviour can now be achieved without a custom helper. See c4p's answer for the contemporary solution to this problem. The solution above was last tested with Ember 1.0.0-rc.1.

Related

Using variable in partial name

I have a list of "summaries" in a loop:
{{#each formSummaries}}
{{/each}}
For each one I want to output a template that is named by each formSummary.name:
{{#each formSummaries}}
{{partial 'forms/summaries/' + name}}
{{/each}}
or like this:
Controller:
summaryPath: 'forms/summaries' + name
Template:
{{#each formSummaries}}
{{partial summaryPath}}
{{/each}}
Is it possible to do something like this with a partial? Is there a more "Ember" way of solving this problem? Thank you in advance.
The handlebars looks good to me, except that I would specify an itemController. This will let you get fancy-pants with each rendered model through the use of computed properties and other powerful controller mechanisms.
{{#each formSummaries itemController='summary'}}
{{partial summaryPath}}
{{/each}}
Now, summaryPath should be computed within that item controller. How about:
App.SummaryController = Ember.ObjectController.extend({
summaryPath: function () {
return 'templateName_' + this.get('name'); // You can tailor this part to suit your needs.
}.property('name')
)};
Hope that helps!

link-to action parameters are not working in ember js

Hi i am very new to ember js. i pass action parameters(id ) on link-to action in template but i did not get the values in my controller.
My Template code as follows:
index.html:
<script type="text/x-handlebars" data-template-name="search">
{{#each model.results}}
// here i pass id value along with action
{{#link-to 'profile' id action="profileinfo"}}
</script>
app.js:
App.SearchController = Ember.ObjectController.extend({
id: '',
actions:{
profileinfo: function(id){
// Here i access id value like this
console.log(id);
var id = this.get('id');})
when i click on the link action goes to Searchcontroller, but i get id value is empty.I follow some solutions in stack overflow but unfortunately i did not get anything. Please provide some solution
I don't get why you're using the {{#link-to}} helper for triggering an action on your controller. Maybe you could simply use the {{action}} helper ?
If you try doing it that way, would it work ?
<button type="button" {{action "profileinfo" id}}>Click me !</button>
From there, your console.log(id); should get your value.
EDIT
Would also work for a <a> tag
<a href="#" {{action "profileinfo" id}}>Click me !</a>
I've created popular addon for doing just that:
{{#link-to 'profile' id invokeAction='profileinfo'}}
Simply install it:
ember installember-link-action
Please leave a star if you enjoy it or leave feedback if you feel anything is missing. :) It works with Ember 1.13 and 2.X (tested on Travis CI).

Calling a handlebars block helper from another helper

How can I call a handlebars block helper from another helper in ember.
I am interested in converting the following in a bound helper.
{{#each link in sideMenuLinks}}
<li class="navigation page">
{{#linkTo ROUTE_VARIABLE link.linkToRouteContext}}
{{{link.iconTag}}}<i class="icon-right-open"></i>{{link.linkText}}</a>
{{/linkTo}}
</li>
{{/each}}
Note that I will have to call a {{#linkTo}} block inside the helper and also change ROUTE_VARIABLE with a value from the property link.linkToRoute.
The Ember handlebars helpers are placed at Ember.Handlebars.helpers. You can call them with Ember.Handlebars.helpers.{helperName}.call.
However, The above looks like a dynamic partial/view style helper. I would suggest creating a Handlebars View helper for it. The syntax is similar but you pass in a View class to the helper.
Ember.Handlebars.helper('sideMenuLinks', App.SideMenuLinksView);
The corresponding view can use a template similar to yours by giving a templateName
App.SideMenuLinksView = Ember.View.extend({
templateName: 'sideMenuLinksTemplate'
});
You template would be something like,
<script type='text/x-handlebars' data-template-name='sideMenuLinksTemplate'>
{{#each link in view.links}}
<li class="navigation page">
{{#linkFor parentView.routeVariable link.linkToRouteContext}}
{{{link.iconTag}}}<i class="icon-right-open"></i>{{link.linkText}}</a>
{{/linkFor}}
</li>
{{/each}}
</script>
The default Ember linkTo is static, In that you cannot pass the named route from a variable. You will need a dynamic linkTo helper like the linkFor that looks up the variable path before
applying linkTo internally.
Ember.Handlebars.registerHelper('linkFor', function(path, params, options) {
var view = options.data.view;
var name = view.get(path);
var args = [name, params, options];
return Ember.Handlebars.helpers.linkTo.apply(this, args);
});
Finally you can use this helper like below. The links property will be bound to the content of the controller in this example.
<script type='text/x-handlebars' data-template-name='application'>
{{sideMenuLinks links=content routeVariable='page'}}
</script>
Here's a working jsbin.

Creating a dynamic string with bindAttr

I'd like to create a dynamic classname on an object with a value I'm getting from my model. One of the keys is named provider which contains either "twitter" or "facebook". What I'd like to do is to prepend the string "icon-" to the provider so that the resulting class is icon-twitter or icon-facebook.
This is the code that I've got now.
<i {{bindAttr class=":avatar-icon account.provider"}}></i>
Ember offers a way to include a static string within the attribute by prepending : to it. You can see that I'm also adding a class called avatar-icon in this example. I've already tried :icon-account.provider which simply resulted in the literal string "icon-account.provider".
RESPONSE
Nice one. I'm working on a solution similar to your answer right now. Question though: this view will be used within the context of an each loop. How would I pass in the current item to be used within the view? I have this right now:
{{#each account in controller}}
{{#view "Social.AccountButtonView"}}
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
Is it possible to just do this:
{{#view "Social.AccountButtonView" account="account"}}
?
I have previously stated that attributeBindings would be a suitable solution for this, but I was mistaken. When binding the class attribute of a given View, as pointed out, you should use classNames or classNameBindings. Please refer to the sample below:
App.ApplicationView = Em.View.extend({
provider: 'Facebook',
classNameBindings: 'providerClass',
providerClass: function() {
return 'icon-avatar icon-%#'.fmt(this.get('provider').toLowerCase());
}.property('provider')
});
This will render the following HTML:
<div id="ember212" class="ember-view icon-avatar icon-facebook">
<h1>App</h1>
</div>
Here's a fiddle: http://jsfiddle.net/schawaska/HH9Sk/
(Note: The fiddle is linking to a version of Ember.js earlier than RC)

In templates in Ember.js, how do you refer to a value in the parent context when you are inside an #each block?

I have a situation in a template where I want to use an if block on a value in the parent context while inside an each block.
The code:
App = Ember.Application.create({});
App.view = Ember.View.extend({
foo: [1, 2, 3],
bar: true
});
The template:
<script type="text/x-handlebars">
{{#view App.view}}
{{#each foo}}
{{#if bar}}
{{this}}
{{/if}}
{{/each}}
{{/view}}
</script>
This does not work because names referenced inside an each loop are scoped to the element of iteration. How do you refer to things in the parent context?
Demo: http://jsfiddle.net/hekevintran/sMeyC/1/
I found a better solution.
From the Ember.js View Layer guide (http://emberjs.com/guides/understanding-ember/the-view-layer/):
Handlebars helpers in Ember may also specify variables. For example, the {{#with controller.person as tom}} form specifies a tom variable that descendent scopes can access. Even if a child context has a tom property, the tom variable will supersede it.
This form has one major benefit: it allows you to shorten long paths without losing access to the parent scope.
It is especially important in the {{#each}} helper, which provides a {{#each person in people}} form. In this form, descendent context have access to the person variable, but remain in the same scope as where the template invoked the each.
The template:
<script type="text/x-handlebars" >
{{#view App.view}}
{{#each number in view.foo}}
{{#if view.bar}}
{{number}}
{{/if}}
{{/each}}
{{/view}}
</script>​
Demo: http://jsfiddle.net/hekevintran/hpcJv/1/
What hekevintran's answer means is that you can rename any variable using #with. We have a similar problem in JavaScript with this. In JavaScript, sometimes you'll see code like this to work around it.
var self = this;
doSomething(function() {
// Here, `this` has changed.
if (self.bar) {
console.log(this);
}
});
In Ember flavored Handlebars, something similar is happening with view. Say you have App.MyOuterView and another view inside it. You can work around it like this.
{{#with view as myOuterView}}
{{#each foo}}
{{#if myOuterView.bar}}
{{this}}
{{/if}}
{{/each}}
{{/with}}
Similar to the JavaScript, you can essentially rename view to something else so it doesn't get shadowed by the inner view. {{#each person in people}} is just a special case of that. But renaming using {{#with view as myView}} is the more general solution/workaround to this problem that also works with nested calls to the view helper.
I was also stumped on this. This thread and this other thread (Using a container view in ember.js - how to access parent variables from child view) helped me with the solution. I used Jonathan's suggestion to do {#with} and also figured out that I should access my variable by calling the controller. Mine worked like this:
// I use the #which command to preserve access to the outer context once inside the #each
{{#with view as myOuterView}}
{{#each myInnerArray}}
//here, i get my 'name' property from the *controller* of myOuterView
{{myOuterView.controller.name}}
// stuff i did in inner array
{{/each}
{{/with}
No need to place the if inside each in the first place:
<script type="text/x-handlebars">
{{#view App.view}}
{{#if view.bar}}
{{#each view.foo}}
{{this}}
{{/each}}
{{/if}}
{{/view}}
</script>
Demo: http://jsfiddle.net/ppanagi/NQKvy/35/