Как получить экземпляр родительского шаблона (текущего шаблона)
Есть ли чистый способ получить родительский шаблон текущего шаблона? Ничто официально не задокументировано в 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)