В шаблонах в Ember.js, как вы относитесь к значению в родительском контексте, когда находитесь внутри блока #each?

У меня есть ситуация в шаблоне, где я хочу использовать блок if в значении в родительском контексте, находясь внутри каждого блока.

Код:

App = Ember.Application.create({});

App.view = Ember.View.extend({
    foo: [1, 2, 3],
    bar: true
});

Шаблон:

<script type="text/x-handlebars">
{{#view App.view}}
    {{#each foo}}
        {{#if bar}}
            {{this}}
        {{/if}}
    {{/each}}
{{/view}}
</script>

Это не работает, потому что имена, указанные внутри каждого цикла, привязаны к элементу итерации. Как вы относитесь к вещам в родительском контексте?

Демо: http://jsfiddle.net/hekevintran/sMeyC/1/

Ответ 1

Я нашел лучшее решение.

Из руководства Embed.js View Layer (http://emberjs.com/guides/understanding-ember/the-view-layer/):

Помощники ручек в Ember могут также указывать переменные. Например, в форме {{#with controller.person as tom}} задается переменная tom, к которой могут обращаться потоки потомков. Даже если дочерний контекст имеет свойство tom, переменная tom заменит его.

Эта форма имеет одно важное преимущество: она позволяет сократить длинные пути, не теряя доступ к родительской области.

Это особенно важно в помощнике {{#each}}, который предоставляет форму {{#each person in people}}. В этой форме контекст потомков имеет доступ к переменной человека, но остается в той же области, где шаблон вызывается каждый.

Шаблон:

<script type="text/x-handlebars" >
    {{#view App.view}}
        {{#each number in view.foo}}
            {{#if view.bar}}
                {{number}}
            {{/if}}
        {{/each}}
    {{/view}}
</script>​

Демо: http://jsfiddle.net/hekevintran/hpcJv/1/

Ответ 2

Какой ответ hekevintran означает, что вы можете переименовать любую переменную с помощью #with. У нас аналогичная проблема с JavaScript с this. В JavaScript иногда вы увидите такой код, чтобы обойти его.

var self = this;
doSomething(function() {
  // Here, `this` has changed.
  if (self.bar) {
    console.log(this);
  }
});

В рулевых ручках, украшенных Ember, что-то подобное происходит с view. Скажем, у вас есть App.MyOuterView и еще один вид внутри него. Вы можете обойти это так.

{{#with view as myOuterView}}
  {{#each foo}}
    {{#if myOuterView.bar}}
      {{this}}
    {{/if}}
  {{/each}}
{{/with}}

Подобно JavaScript, вы можете по существу переименовать view в другое, чтобы он не затенял внутренний вид. {{#each person in people}} является лишь частным случаем этого. Но переименование с помощью {{#with view as myView}} является более общим решением/обходным решением этой проблемы, которое также работает с вложенными вызовами помощника view.

Ответ 3

Я тоже был в тупике. Этот поток и этот другой поток (Использование представления контейнера в ember.js - как получить доступ к родительским переменным из дочернего представления) помогли мне с решением. Я использовал предложение Джонатана сделать {#with}, а также выяснил, что я должен получить доступ к моей переменной, вызвав контроллер. Моя работала так:

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

Ответ 4

Не нужно размещать if внутри each в первую очередь:

<script type="text/x-handlebars">
  {{#view App.view}}
    {{#if view.bar}}
      {{#each view.foo}}
        {{this}}
      {{/each}}
    {{/if}}
  {{/view}}
</script>

Демо: http://jsfiddle.net/ppanagi/NQKvy/35/