Как получить экземпляр родительского шаблона (текущего шаблона)

Есть ли чистый способ получить родительский шаблон текущего шаблона? Ничто официально не задокументировано в API Метеора. Я говорю о Blaze.TemplateInstanceне контекст (т.е. не Template.parentData).

5 ответов

Решение

В конце я расширил экземпляры шаблона аналогично Meteor parentData, как это:

/**
 * Get the parent template instance
 * @param {Number} [levels] How many levels to go up. Default is 1
 * @returns {Blaze.TemplateInstance}
 */

Blaze.TemplateInstance.prototype.parentTemplate = function (levels) {
    var view = this.view;
    if (typeof levels === "undefined") {
        levels = 1;
    }
    while (view) {
        if (view.name.substring(0, 9) === "Template." && !(levels--)) {
            return view.templateInstance();
        }
        view = view.parentView;
    }
};

Пример использования: someTemplate.parentTemplate() чтобы получить непосредственный родитель

Есть ли чистый способ получить родительский шаблон текущего шаблона?

В настоящее время я ничего не знаю, но это должно произойти когда-нибудь в будущем как часть запланированного "лучшего API для разработки повторно используемых компонентов" (это обсуждается в дорожной карте Meteor post 1.0).

На данный момент вот обходной путь, который я использую в своих проектах:

// extend Blaze.View prototype to mimick jQuery's closest for views
_.extend(Blaze.View.prototype,{
    closest:function(viewName){
        var view=this;
        while(view){
            if(view.name=="Template."+viewName){
                return view;
            }
            view=view.parentView;
        }
        return null;
    }
});

// extend Blaze.TemplateInstance to expose added Blaze.View functionalities
_.extend(Blaze.TemplateInstance.prototype,{
    closestInstance:function(viewName){
        var view=this.view.closest(viewName);
        return view?view.templateInstance():null;
    }
});

Обратите внимание, что он поддерживает только именованные родительские шаблоны и должен работать так же, как jQuery. closest перебирать узлы родительских представлений от дочернего до самого верхнего шаблона (тела), ища шаблон с соответствующим именем.

Как только эти расширения для Blaze зарегистрированы где-то в вашем клиентском коде, вы можете делать что-то вроде этого:

HTML

<template name="parent">
  <div style="background-color:{{backgroundColor}};">
    {{> child}}
  </div>
</template>

<template name="child">
  <button type="button">Click me to change parent color !</button>
</template>

JS

Template.parent.created=function(){
  this.backgroundColor=new ReactiveVar("green");
};

Template.parent.helpers({
  backgroundColor:function(){
    return Template.instance().backgroundColor.get();
  }
});

Template.child.events({
  "click button":function(event,template){
    var parent=template.closestInstance("parent");
    var backgroundColor=parent.backgroundColor.get();
    switch(backgroundColor){
      case "green":
        parent.backgroundColor.set("red");
        break;
      case "red":
        parent.backgroundColor.set("green");
        break;
    }
  }
});

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

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

Template.parentTemplate.onCreated(function () {
  var parentInstance = this;
  parentInstance.count = new ReactiveVar(1);
});

Template.parentTemplate.helpers({
  incrementHandler: function () {
    var parentInstance = Template.instance();
    var count = parentInstance.count.get();

    return function () {
      var newCount = count + 1;
      parentInstance.count.set(newCount);
    };
  }
});

Затем включите мой дочерний шаблон:

{{> childTemplate handler=loadMoreHandler}}

И настроить мое событие:

Template.childTemplate.events({
  'click .increment-button': function (event, childInstance) {
    event.preventDefault();
    childInstance.data.handler();
  }
});

Если вы не хотите расширять Blaze.TemplateInstance вы можете получить доступ к родительскому экземпляру следующим образом:

Template.exampleTemplate.onRendered(function () {
  const instance = this;
  const parentInstance = instance.view.parentView.templateInstance();
});

Проверено только в Meteor 1.4.x

Вы можете использовать пакет как расширение шаблона Aldeed

Здесь доступен следующий метод:

templateInstance.parent(numLevels, includeBlockHelpers)
Другие вопросы по тегам