如何使Meteor模板助手在另一个模板渲染后重新运行/渲染?

6

我在模板Nav中有一个名为{{renderNav}}的模板助手。

例如:

Template.Nav.renderNav

在那个帮助函数中,我希望解析不同模板中另一个帮助器的渲染输出。例如,该帮助器可以是:
Template.contentWindow.content

它提供了HTML的代码。
{{content}}

我的renderNav助手希望将替换{{content}}的html分开,以生成

的html。
{{renderNav}}

我该怎么做?现在{{renderNav}}助手执行或运行得更快,因此无法解析替换{{content}}的html。
@Hugo - 我按照你的建议在我的代码中进行了以下操作。
Template.contentWindow.rendered = function() {
    debugger;  
    return Session.set('entryRendered', true);
};

Template.Nav.renderNav = function() {
    debugger;
    var forceDependency;
    return forceDependency = Session.get('entryRendered');
};

当我运行它时,调试器首先在执行renderNav助手时停止。(考虑到我在竞争条件方面看到的情况,这是有道理的)。然后contentWindow被渲染,我触发了Session.set('entryRendered', true)上方的断点。但是,正如你建议的那样,renderNav没有再次运行。我是否误解或错误实现了你的建议?

不确定你想做什么。假设 contentrenderNav 之前结束。你如何从 renderNav 中访问 content 的 HTML? - Xyand
你可能是对的,我没有用一种非常流畅的方式来做这件事...在这种情况下,代码片段不会很具描述性,但解释可以... {{content}} 帮助程序渲染为一个带有任意数量标题(H1,H2,H3 等)的页面;renderNav 帮助程序是侧边栏模板的一部分,它解析内容中的这些标题并有效地构建目录 --- 所以我不知道如何将 content 帮助程序生成的 HTML 传递给 renderNav 帮助程序。 - funkyeah
看一下我回答的更新。有帮助吗? - Hubert OG
快速的方法是依赖原始数据而不是渲染结果。在 content 中,您可以使用一些逻辑来生成标题文本。将此逻辑制作为一个函数,并在 contentrenderNav 中使用它。只需确保在两者中使用相同的上下文。 - Xyand
@HubertOG 我现在正在工作,但我回家后会尝试一下,这很有道理,所以我认为它应该可以工作。 - funkyeah
显示剩余2条评论
2个回答

4
你需要在想要重新运行的模板中设置依赖项。根据你想要获取的数据,有几种可能性。
例如,你可以在"content"模板中设置一个反应标记,通知"renderNav"它已完成绘制。
Template.contentWidnow.rendered = function() {
    ...

    // Set this on the very end of rendered callback.
    Session.set('contentWindowRenderMark', '' +
        new Date().getTime() +
        Math.floor(Math.random() * 1000000) );
}


Template.renderNav.contentData = function() {
    // You don't have to actually use the mark value,
    // but you need to obtain it so that the dependency
    // is registered for this helper.
    var mark = Session.get('contentWindowRenderMark');

    // Get the data you need and prepare for displaying
    ...
}

根据您提供的更多信息,我们可以创建以下代码: content.js
Content = {};
Content._dep = new Deps.Dependency;

contentWindow.js

Template.contentWidnow.rendered = function() {
    Content.headers = this.findAll(':header');
    Content._dep.changed();
}

renderNav.js

Template.renderNav.contentData = function() {
    Content._dep.depend();
    // use Content.headers here
    ...
}

设置 true 不应该起作用。因为它只在第一次改变值。使用 Random 或者更好的 Deps.Dependency - Xyand
是的,在我的示例中,我使用了 Date(),甚至添加了一些 random() 来确保值发生了变化。自定义 Deps.Dependency 是另一种有效的方法,甚至比 Session 更好(更低级别)- 前提是您有一种良好的方式在模板文件之间共享依赖项。 - Hubert OG
我实现了这个功能,但现在出现了控制台异常:Exception from Deps recompute: TypeError: Cannot read property 'nodeType' of null。 - funkyeah
3
顺便提一下,我的名字是Hubert,不是Hugo :) - Hubert OG
空值错误是由于页面在Meteor中的渲染方式导致的,您的页面可能会在数据上下文准备好之前渲染多次,因此第一次渲染时可能会出现空值,另一个则是发布函数完成渲染时。我知道这篇文章已经有些年头了,但供您参考。 - MrMowgli
显示剩余3条评论

3
如果你想要在contentWindow渲染时自动重���导航,就像Hubert OG建议的那样,你也可以使用一种更简洁、更低级别的方式来使上下文失效:
var navDep = new Deps.Dependency;

Template.contentWindow.rendered = function() {
    ...
    navDep.changed();
}

Template.renderNav.contentData = function() {
    navDep.depend();

    // Get the data you need and prepare for displaying
    ...
}

请查看http://docs.meteor.com/#deps以获取更多信息。

另一方面,如果您想手动呈现另一个模板,则可以将其作为函数调用:

var html = Template.contentWindow();

返回的 HTML 不会是响应式的。如果需要响应式,请使用以下方法:
var reactiveFragment = Meteor.render(Template.contentWindow);

请参阅位于http://www.eventedmind.com/的Spark和反应性screencasts,了解详细信息。

更新

要将渲染片段添加到您的DOM中:

document.body.appendChild(Meteor.render(function () {
    return '<h1>hello</h1><b>hello world</b>';
}));

您还可以使用DOM API直接访问呈现的节点:
console.log(reactiveFragment.childNodes[0]);

我认为这是正确的,但对我没有用,所以我会继续挖掘...使用Deps.Dependency方法,contentData助手按预期首先执行,然后contentWindow.rendered调用navDep.changed(),这将触发contentData助手再次运行(这正是我想要的!),不幸的是,虽然contentData助手似乎返回了正确的html,但没有渲染到DOM中,也没有再次执行任何一个助手(之前我得到的是渲染到DOM中的东西,只是上一页的内容而不是当前页的内容)。 - funkyeah
你是否在renderNav中使用了reactiveFragment?那么你就创建了一个依赖循环,其中contentWindow依赖于renderNav,而renderNav又依赖于contentWindow。 - konrad
不,我只是按照你在帖子的前半部分展示的navDep代码进行了插入,同时保持其他所有内容不变。对于我来说,还不太清楚我应该如何在这种情况下使用reactiveFragment代码。我的理解是,我会从renderNav助手中调用Meteor.render(Template.contentWindow); 然后在返回的HTML上执行我的Nav解析,而不是在DOM HTML上执行。 - funkyeah
我更新了我的答案,以更详细地解释 reactiveFragments。 - konrad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接