Access Meteor Blaze Template.contentBlock inside Template.onCreated

I am writing a special Blaze block helper with children:

<template name="parent"> {{> Template.contentBlock ..}} </template> <template name="child"> {{> Template.contentBlock ..}} </template> 

The supposed use case should be to have a template with arbitrary child nodes, which I define in an html file.

 {{#parent}} {{#child id="child1" title="Child 1"}} <p>This is content of child 1</p> {{/child}} {{#child id="child2" title="Child 2"}} <p>This is content of child 2</p> {{/child}} {{#child id="childN" title="Child N"}} <p>This is content of child N</p> {{/child}} {{/parent}} 

There are no problems so far. However, in the parent onCreated / autorun template, I want to have access to the child templates. I want to use this data to dynamically create in parent elements of a template based on

 Template.parent.onCreated(function () { const instance = this; instance.state = new ReactiveDict(); instance.autorun(function () { const contentBlocks = // how? instance.state.set("children", contentBlocks); }); }); Template.parent.helpers({ children() { return Template.instance().state.get("children"); } }); 

Where children will be used in the parent template as follows:

 {{#parent}} {{#each children}} do something with {{this.value}} {{/each}} {{#child id="child1" title="Child 1"}} <p>This is content of child 1</p> {{/child}} {{#child id="child2" title="Child 2"}} <p>This is content of child 2</p> {{/child}} {{#child id="childN" title="Child N"}} <p>This is content of child N</p> {{/child}} {{/parent}} 

I do not want to access the contents of contentBlock ( <p> ), but rather to get a list of child templates added.

Is this possible with the current template API / Blaze? The documentation is a bit thin at this point.

This is basically the opposite of this post: How to get the parent template instance (of the current template)


Edit 1: Use parent view Renderfunction (only partially works)

I found a way to return the parent Template to the children, but not their data :

 // in Template.parant.onCreated -> autorun const children = instance.view.templateContentBlock.renderFunction() .filter(child => typeof child === 'object') .map(el => Blaze.getData(el._render())); console.log(children); // null, null, null because Blaze.getData(view) does return null 

Another approach I found is to use a generic ReactiveVar , but both seem to me not clean enough. I just want to get a list of Template instances in the parent js code.


Edit 2: use generic ReactiveVar (only partially working)

You can use the generic ReactiveVar if it is in the scope of both patterns:

 const _cache = new ReactiveVar({}); Template.parent.onCreated(function () { const instance = this; instance.state = new ReactiveDict(); instance.autorun(function () { const children = Object.values(_cache.get()); instance.state.set("children", children); }); }); Template.parent.helpers({ children() { return Template.instance().state.get("children"); } }); 

It works (but is displayed only once, but does not respond):

 Template.child.onCreated(function () { const instance = this; const data = Template.currentData(); const cache = _cache.get(); cache[data.id] = data; _cache.set(cache); }); 

Does not work (child autostart sets values, but new values ​​are not displayed):

 Template.child.onCreated(function () { const instance = this; instance.autorun(function() { const instance = this; const data = Template.currentData(); const cache = _cache.get(); cache[data.id] = data; _cache.set(cache); }); }); 
+7
javascript meteor spacebars meteor-blaze html-templates
source share
1 answer

that's what i came up with. Pls tell me if this is what you wanted or if I misunderstood.

main.html:

 <body> {{> content}} </body> <template name="content"> {{#parent}} {{#each children}} <p>do something with {{this.id}}</p> <p>data: {{this.tmpl.data.title}}</p> {{/each}} {{#child id="child1" title="Child 1" parentTemplate=this.parentTemplate}} <p>This is content of child 1</p> {{/child}} {{#child id="child2" title="Child 2" parentTemplate=this.parentTemplate }} <p>This is content of child 2</p> {{/child}} {{#child id="childN" title="Child N" parentTemplate=this.parentTemplate }} <p>This is content of child N</p> {{/child}} {{/parent}} </template> <template name="parent"> {{> Template.contentBlock parentTemplate=template}} </template> <template name="child"> {{> Template.contentBlock }} </template> 

main.js

 import { Template } from 'meteor/templating'; import { ReactiveVar } from 'meteor/reactive-var'; import './main.html'; Template.content.helpers({ children() { return this.parentTemplate.children.get(); }, }); Template.parent.onCreated(function () { this.children = new ReactiveVar([]); }); Template.parent.helpers({ template() { return Template.instance(); } }); Template.child.onRendered(function () { const children = this.data.parentTemplate.children.get(); children.push({ id: this.data.id, tmpl: this }); this.data.parentTemplate.children.set(children); }); 

Exit:

enter image description here

Although it uses ReactiveVar , which is not perfect, it does not rely on any global one, and you can put your code in different files without any problems.

+6
source share

All Articles