Подтвердить что ты не робот

Доступ к родительскому контексту в шаблонах Meteor и шаблонных помощниках

Я столкнулся с ситуацией с шаблоном, с которой мне трудно найти способ.


Вот шаблон, о котором идет речь:

{{#each votes}}
    <h3>{{question}}</h3>

    <ul>
        {{#each participants}}
            <li>
                <p>{{email}}</p>
                <select name="option-select">
                    {{#each ../options}}
                    <option value="{{option}}" class="{{is_selected_option}}">{{option}}</option>
                    {{/each}}
                </select>
            </li>
        {{/each}}
    </ul>
</div>
{{/each}}


И вот пример документа для голосования:

{
    _id: '32093ufsdj90j234',
    question: 'What is the best food of all time?'
    options: [
        'Pizza',
        'Tacos',
        'Salad',
        'Thai'
    ],
    participants: [
        {
            id: '2f537a74-3ce0-47b3-80fc-97a4189b2c15'
            vote: 0
        },
        {
            id: '8bffafa7-8736-4c4b-968e-82900b82c266'
            vote: 1
        }
    ]
}


И вот проблема...

Когда шаблон падает на #each для участников, он больше не имеет доступа к контексту vote и, следовательно, не имеет доступа к доступным параметрам для каждого голосования.

Я могу немного обойти это, используя путь ../options handlebars, чтобы вернуться в родительский контекст, но это не влияет на контекст помощника шаблона, поэтому this в Template.vote.is_selected_option относится к текущему participant, а не текущим vote или option, и не знает, с какими option мы в настоящее время выполняем итерацию.

Любые предложения о том, как обойти это, не прибегая к манипуляциям с DOM и shenanigans jQuery?

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

4b9b3361

Ответ 1

Это не очень красиво, но я сделал что-то вроде этого:

<template name='forLoop'>
{{#each augmentedParticipants}}
{{> participant }}
{{/each}}
</template>

<template name='participant'>
...
Question: {{this.parent.question}}
...
</template>


// and in the js:
Template.forLoop.helpers({
    augmentedParticipants: function() {
        var self = this;
        return _.map(self.participants,function(p) {
            p.parent = self;
            return p;
        });
    }
});

Это похоже на подход, предложенный AVGP, но увеличивающий данные на уровне помощника вместо уровня db, который, как мне кажется, немного легче.

Если вам интересно, вы можете попытаться написать хелпер-блок Handlebars eachWithParent, который бы абстрагировал эту функциональность. Метрические расширения для рулей описаны здесь: https://github.com/meteor/meteor/wiki/Handlebars

Ответ 3

Я не знаю формального способа (если есть), но чтобы решить вашу проблему, я бы связал участников с родительским ID следующим образом:

{
    _id: "1234",
    question: "Whats up?",
    ...
    participants: [
      {
        _id: "abcd",
        parent_id: "1234",
        vote: 0
      }
    ]
}

и используйте этот parent_id в помощниках, событиях и т.д., чтобы вернуться к родительскому элементу с помощью findOne. Это, очевидно, очень оптимальная вещь, но это самый простой способ, который приходит мне на ум, пока нет способа ссылки на родительский контекст. Возможно, есть способ, но он очень хорошо скрыт во внутренней работе Meteor без упоминания в документах, если да: обновите этот вопрос, если найдете его.

Ответ 4

Это длинный выстрел, но, возможно, это может сработать:

{{#with ../}}
  {{#each options}}
    {{this}}
  {{/each}}
{{/with}}

Ответ 5

Это облегчит жизнь.

// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent.
Handlebars.registerHelper('eachWithParent', function(context, options) {

    var self = this;
    var contextWithParent = _.map(context,function(p) {
        p.parent = self._id;
        return p;
    });

    var ret = "";

    for(var i=0, j=contextWithParent.length; i<j; i++) {
        ret = ret + options.fn( contextWithParent[i] );
    }
    return ret;
});

Идем дальше и меняем

p.parent = self._id;

к тому, что вы хотите получить в родительском контексте.

Исправлено:

// https://github.com/meteor/handlebars.js/blob/master/lib/handlebars/base.js

// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent.
Handlebars.registerHelper('eachWithParent', function(context, options) {
    var self = this;
    var contextWithParent = _.map(context,function(p) {
        p.parent = self._id;
        return p;
    });

    return Handlebars._default_helpers.each(contextWithParent, options);
});

Это работает:) без ошибок

Ответ 6

Просто зарегистрируйте глобальный помощник шаблона:

Template.registerHelper('parentData',
    function () {
        return Template.parentData(1);
    }
);

и использовать его в ваших HTML-шаблонах как:

{{#each someRecords}}
  {{parentData.someValue}}
{{/each}}

======= EDIT

Для Meteor 1.2+ вы можете использовать:

UI.registerHelper('parentData', function() {
  return Template.parentData(1);
});

Ответ 7

Я был застрял подобным образом и обнаружил, что метод Template.parentData(), предложенный в других ответах, в настоящее время не работает в обработчиках событий (см. https://github.com/meteor/meteor/issues/5491). Пользователь Lirbank опубликовал это простейшее решение:

Передайте данные из внешнего контекста в элемент html во внутреннем контексте в том же шаблоне:

{{#each companies}}
  {{#each employees}}
    <a href="" companyId="{{../id}}">Do something</a>
  {{/each}}
{{/each}}

Теперь идентификатор компании можно получить из обработчика событий с чем-то вроде

$(event.currentTarget).attr('companyId')

Ответ 8

"click .selected":function(e){
    var parent_id = $(e.currentTarget).parent().attr("uid");
    return parent_id
  },
<td id="" class="staff_docs" uid="{{_id}}">
                                        {{#each all_req_doc}}
                                                <div class="icheckbox selected "></div>
  {{/each}}
  </td>

Ответ 9

{{#each parent}}

{{#each child}}

<input type="hidden" name="child_id" value="{{_id}}" />

<input type="hidden" name="parent_id" value="{{../_id}}" />

{{/each}}

{{/each}}

_id НЕ является _did вещи, это id родителя!