Is there a clean way to get the parent template of the current template? Nothing is officially documented in Meteor's API.
I'm talking about the Blaze.TemplateInstance
, not the context (i.e. not Template.parentData
).
In the end, I've extended the template instances similarly with Meteor's parentData
, like this:
/**
* 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;
}
};
Example usage: someTemplate.parentTemplate()
to get the immediate parent
view
was available in TemplateInstance
back then), but I took your word for it and edited the answer. Cheers –
Cartload view.name.substring(0, 9) === "Template."
to view.hasOwnProperty('template')
–
Private view.template
more, but I won't change the answer myself, because I haven't used blaze in more than a year –
Cartload Is there a clean way to get the parent template of the current template?
Currently, none that I know of, but this is supposed to happen sometime in the future as part of a planned "better API for designing reusable components" (this is discussed in the Meteor post 1.0 roadmap).
For the moment, here is a workaround I'm using in my projects :
// 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;
}
});
Note that this is only supporting named parent templates and supposed to work in the same fashion as jQuery closest
to traverse parent views nodes from a child to the top-most template (body), searching for the appropriately named template.
Once this extensions to Blaze have been registered somewhere in your client code, you can do stuff like this :
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;
}
}
});
parentData
, but I'm upvoting your answer, because closest
is also a useful pattern –
Cartload What I've been doing so far is that if I need to access the parent instance in a child template's function, I try to instead refactor this function to declare it on the parent template, and then pass it as argument to the child, who can then execute it.
As an example, let's say I want to increment a template variable on the parent template from within the child template. I could write something like this:
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);
};
}
});
Then include my child template:
{{> childTemplate handler=loadMoreHandler}}
And set up my event:
Template.childTemplate.events({
'click .increment-button': function (event, childInstance) {
event.preventDefault();
childInstance.data.handler();
}
});
If you don't want to extend Blaze.TemplateInstance
you can access the parent instance like this:
Template.exampleTemplate.onRendered(function () {
const instance = this;
const parentInstance = instance.view.parentView.templateInstance();
});
Only tested in Meteor 1.4.x
You can use a package like Aldeed's template-extension
The following method is available there:
templateInstance.parent(numLevels, includeBlockHelpers)
© 2022 - 2024 — McMap. All rights reserved.