Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

ember.js

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/

like image 630
hekevintran Avatar asked May 19 '12 04:05

hekevintran


People also ask

What is an ember template?

Ember uses the Handlebars templating library to power your app's user interface. Handlebars templates contain static HTML and dynamic content inside Handlebars expressions, which are invoked with double curly braces: {{}} . Dynamic content inside a Handlebars expression is rendered with data-binding.

How does Ember js work?

Ember. js uses Handlebars, a lightweight templating engine also maintained by the Ember team. It has the usual templating logic, like if and else , loops and formatting helpers , that kind of stuff. Templates may be precompiled (if you want to cleanly organize them as separate .

What is component in Ember js?

Ember components are used to turn markup text and styles into reusable content. Components consist of two parts: a JavaScript component file that defines behavior, and its accompanying Handlebars template that defines the markup for the component's UI. Components must have at least one dash in their name.

Is Ember js a JavaScript framework?

Ember. js is a productive, battle-tested JavaScript framework for building modern web applications.


3 Answers

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/

like image 63
hekevintran Avatar answered Oct 03 '22 05:10

hekevintran


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.

like image 36
Jonathan Tran Avatar answered Oct 03 '22 06:10

Jonathan Tran


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}
like image 34
Mike Dorsey Avatar answered Oct 03 '22 04:10

Mike Dorsey