【问题标题】:Meteor Blaze access Template.contentBlock inside Template.onCreatedMeteor Blaze 访问 Template.onCreated 内的 Template.contentBlock
【发布时间】:2018-08-15 13:36:55
【问题描述】:

我正在编写一个带有孩子的自定义 Blaze 块助手:

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

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

我的预期用例是有一个带有任意子节点的模板,我在 html 文件中定义。

{{#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}}

目前没有问题。但是,在父模板的onCreated / autorun 中,我想访问child 模板。我想使用这些数据在父模板元素中动态创建,基于

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");
    }
});

children 将在parent 模板中使用如下:

{{#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}}

我不想访问 contentBlock 的内容(&lt;p&gt;),而是获取添加的child 模板列表。

当前的 Template / Blaze API 可以实现吗? documentation 在这一点上有点薄。

基本上和这个帖子相反:How to get the parent template instance (of the current template)


编辑 1:使用父视图的渲染功能(仅部分工作)

我找到了一种方法来获取 parent 模板的孩子,但不是他们的 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

我发现的另一种方法是使用共享的ReactiveVar,但在我看来两者都不够干净。我只想获取父级js代码中的Template实例列表。


编辑 2:使用共享的 ReactiveVar(仅部分工作)

可以使用共享的ReactiveVar,只要它在两个模板的范围内:

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");
    }
});

工作(但只渲染一次,不响应):

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

不工作(子自动运行正在设置值,但未呈现新值):

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);
    });
});

【问题讨论】:

    标签: javascript meteor meteor-blaze spacebars html-templates


    【解决方案1】:

    这就是我想出的。请让我知道这是您想要的还是我误解了。

    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);
    });
    

    输出:

    虽然它使用ReactiveVar 并不理想,但它不依赖任何全局,您可以将代码放在不同的文件中,没问题。

    【讨论】:

    • 我检查了您的解决方案。它运行良好,在 .但它也引入了第三个模板实例。为了公平起见,我会等到赏金期的日子。
    猜你喜欢
    • 2017-03-17
    • 2016-03-04
    • 2016-03-07
    • 2017-07-02
    • 1970-01-01
    • 2015-08-05
    • 2014-05-12
    • 2017-07-09
    • 2014-05-27
    相关资源
    最近更新 更多