Метеор: существует ли реактивная область для каждого шаблона? - программирование
Подтвердить что ты не робот

Метеор: существует ли реактивная область для каждого шаблона?

Я показываю тот же шаблон Handlebars в нескольких (сколь угодно многих) местах на той же странице. Внутри каждого шаблона я хочу, чтобы кнопка переключала видимость div. Когда я сохраняю это состояние с помощью Session.set, нажатие одной кнопки, очевидно, переключает все div во всех экземплярах шаблонов, которые нежелательны.

Я мог бы сохранить состояние в контексте данных экземпляра шаблона (который привязан к this.data в обратных вызовах Template.myTemplate.rendered и Template.myTemplate.created), но есть две проблемы с этим.

  • this.data не является реактивным источником данных, поэтому не будет распространяться на div
  • У меня нет доступа к экземпляру шаблона в Template.myTemplate.events (как обсуждалось в meteor-core)

Наконец, я мог бы как-то сохранить его в коллекции. Но как бы я однозначно идентифицировал состояние для каждого созданного шаблона? Также может быть хакерский способ с jQuery, но это не так, как я хочу разрабатывать приложения Meteor, которые должны работать с реактивными шаблонами. Особенно, когда этот шаблон становится более сложным.

Я что-то пропустил или действительно не эквивалентен контроллерам AngularJS, которые передают $scope для каждого экземпляра шаблона?

Обновление: Я думал о чем-то подобном.

template.html:

<template name="jsonObject">
    <input type="button" />
    <div class="{{hidden}}">content</div>
</template>

client.js:

Template.jsonObject.hidden = function(){
    var ret = "";
    if (this._hidden) {
        ret = "hidden";
    }
    return ret;
};

Template.jsonObject.events({
    'click input' : function(event, template){
        template.data._hidden = true;
    }
});
4b9b3361

Ответ 1

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

Объект экземпляра шаблона представляет собой появление шаблона в документе. Его можно использовать для доступа к DOM, и ему могут быть назначены свойства, которые сохраняются при обновлении шаблона. [...] вы можете назначить дополнительные свойства по вашему выбору объекту.

Реактивные переменные предоставляются reactive-var базовым пакетом:

A ReactiveVar содержит одно значение, которое можно получить и установить, так что вызов set приведет к аннулированию любых вычислений, которые вызвали get, в соответствии с обычным контрактом для источников реактивных данных.

Ваш код будет выглядеть следующим образом:

Template.jsonObject.onCreated = function () {
  this.hidden = new ReactiveVar(false);
};

Template.jsonObject.helpers({
  hidden: function () {
    return Template.instance().hidden.get() ? 'hidden' : '';
  }
});

Template.jsonObject.events({
  'click input': function (event, template) {
    template.hidden.set(true);
  }
});

HTML такой же, как вы ожидали:

<template name="jsonObject">
  <button>Click Me</button>
  <p>Hidden is {{hidden}}.</p>
</template>

Ответ 2

Вот как я получил экземпляр реактивного источника для каждого экземпляра

Я только хочу спросить у пользователя причину исчезновения динозавра, когда его статус исчезновения установлен на вымерший.

<template name="dinosaur">
   <label for="extinction-status">Extinction status</label>
   <select name="extinction-status">
     <option value="not-extinct">Not extinct</option>
     <option value="extinct">Extinct</option>
   </select>
   {{#if isExtinct extinctStatus newExtinctStatus extinctStatusDep}}
   <label for="extinction-reason">Reason for extinction</label>
   <input name="extinction-reason" type="text" placeholder="Why is it extinct?"/>
   {{/if}}
</template>

Чтобы наглядно отобразить поле причины, мы добавим Deps.Dependency в this.data в функцию шаблона created

Template.dinosaur.created = function() {
  this.data.newExtinctStatus = null;
  this.data.extinctStatusDep = new Deps.Dependency;
};

Мы слушаем, когда пользователь изменяет выбор состояния экстинкции и обновляет newExtinctStatus и называется changed на нашем extinctStatusDep.

Template.dinosaur.events({
  'change [name="extinction-status"]': function(event, template) {
    var extinctStatus = $(event.target).val();
    template.data.newExtinctStatus = extinctStatus;
    template.data.extinctStatusDep.changed();
  }
});

В помощнике мы говорим, что мы зависим от Deps.Dependency, мы пройдем

Template.dinosaur.helpers({
  isExtinct: function(status, newStatus, statusDep) {
    if (statusDep) {
      statusDep.depend();
    }
    if (newStatus) {
      if (newStatus == 'extinct') {
        return true;
      }
    else if (status == 'extinct') {
        // No new status is set, so use the original.
        return true;
    }
  }
});

Это немного взломать, добавляя к this.data, но он позволяет реагировать на каждый шаблон, полезный, когда вы полагаетесь на данные, которые еще не были сохранены в чем-либо в Collection.

Ответ 3

ОБНОВЛЕННЫЙ ОТВЕТ - МЕТЕОР 0.8.3

Теперь Meteor предоставляет функцию UI._templateInstance(), которая предоставляет доступ к экземпляру шаблона в помощниках шаблонов. Это позволяет значительно упростить реализацию:

1. В приведенном ниже HTML-коде удалите {{#with templateInstanceId=getTemplateInstanceId}}

2. Замените JS-код на этот:

var templateInstanceId = 0;

Template.divWithToggleButton.created= function() 
    { 
    this.templateInstanceId = ++templateInstanceId;
    };

Template.divWithToggleButton.events(
    {
    'click button': function(event, template) 
        {
        Session.set("visible", template.templateInstanceId);
        },
    });

Template.divWithToggleButton.visible= function() 
    { 
    return Session.equals("visible", UI._templateInstance().templateInstanceId);
    };

БЫВШИЙ ОТВЕТ У меня было такое же требование в моем проекте: уникальная идентификация экземпляра шаблона для использования с Session.set.

Вот мой простой взлом, используя замену контекста и "скользящий" уникальный идентификатор экземпляра (подробнее об этом позже):

Где угодно в клиентском коде, поставьте:

var templateInstanceId = 0;

UI.registerHelper('getTemplateInstanceId', function()
{
    return templateInstanceId++;
});

Затем используйте {{#with templateInstanceId=getTemplateInstanceId }} в шаблонах, которые вы хотите уникально идентифицировать экземпляры. В вашем примере это может быть что-то вроде этого (не проверено):

HTML:

<!-- Div with a toggle visibility button. Use as a Block Helpers (with # instead of >) -->
<template name="divWithToggleButton">
    {{#with templateInstanceId=getTemplateInstanceId }}
    <div>
        <!-- The 'toggle visibility' button -->
        <button type="button">Toggle Visibility</button>

        <!-- The div content -->
        {{#if visible}}
            {{> UI.contentBlock}}
        {{/if}}
    </div>
    {{/with}}
</template>

JS (код клиента):

Template.divWithToggleButton.events(
{
    'click button': function(event, template) 
    {
        Session.set("visible", this.templateInstanceId);
    },
});

Template.divWithToggleButton.visible= function() 
{ 
    return Session.equals("visible", this.templateInstanceId);
};

Теперь об этом странном "скользящем" уникальном экземпляре id:

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

Ответ 4

Я думаю, что дискуссия о метеорном ядре устарела (хотя она и есть последнее). В документах (цитируется ниже) это должно быть возможно:

Template.myTemplate.events({
   foo: function(event, template) {
      var _div = template.find('...');
   }
});

Функция обработчика получает два аргумента: событие, объект с информацией о событии и шаблон, экземпляр шаблона для шаблона, в котором определяется обработчик. Обработчик также получает некоторые дополнительные данные контекста в этом, в зависимости от контекста текущего элемента, обрабатывающего событие. В шаблоне Handlebars контекст элемента - это контекст данных Handlebars, где этот элемент встречается, который задается с помощью вспомогательных блоков, таких как #with и #each.

Обновление

Предполагая, что у каждого скрываемого div есть уникальный идентификатор, что делать, если вы попробовали что-то подобное? Я не тестировал его.

Template.jsonObject.hidden = function(){
    var _id = $(".classOfPossibleHiddenDiv").prop("id");
    return Session.get(_id) || false;
};

Template.jsonObject.events({
    'click input' : function(event, template){
        Session.set($(template.find(".classOfPossibleHiddenDiv")).prop("id"), true);
    }
});