【问题标题】:how to make a meteor template helper re-run/render after another template has rendered?如何在另一个模板渲染后让流星模板助手重新运行/渲染?
【发布时间】:2013-07-12 11:47:00
【问题描述】:

我在模板导航中有一个名为 {{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?
  • 我正在尝试访问内容助手从 renderNav 助手中呈现的 html。这导致了一种竞争条件,其中 renderNav 首先执行并且无法访问内容助手输出的 DOM HTML。
  • 虽然你可以破解它,但听起来你做错了事。为什么需要自己渲染的模板的 DOM?您应该在renderNav 上下文中拥有所需的所有数据。也许你可以添加一些renderNav 代码来解释它如何使用content DOM 段。
  • 你可能是对的,我没有以一种非常迅速的方式来做这件事......在这种情况下,代码片段不会很有描述性,但解释是...... {{content}}助手呈现为一个页面,其中包含任意数量的标题(H1、H2、H3 等......); renderNav 助手是侧边栏模板的一部分,它解析这些标题的内容并有效地构建目录 --- 所以我不知道如何将内容助手生成的 html 传递给 renderNav 助手
  • 查看我的答案的更新。有帮助吗?

标签: javascript meteor handlebars.js


【解决方案1】:

您需要在要重新运行的模板中添加一个依赖项。可能性很小,具体取决于您想要获取的数据。

例如,您可以在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
  • 是的,在我的示例中,我使用Date(),甚至添加了一些random() 以确保值已更改。自定义Deps.Dependency 是另一种有效的方法,甚至比Session 更好(更低级别) - 前提是您有一种在模板文件之间共享依赖关系的好方法。
  • 我保证最后一个问题!我实现了这一点,但现在得到控制台异常:来自 Deps 的异常重新计算:TypeError:无法读取 null 的属性“nodeType”
  • 顺便说一句,是休伯特,不是雨果 :)
【解决方案2】:

如果您希望在 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 和反应性的截屏视频,了解其工作原理的详细信息。

更新

要将渲染的片段添加到您的 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 之前,它只是以前的页面内容而不是当前页面)
  • 你在 renderNav 中使用了 reactiveFragment 吗?然后你正在创建一个依赖循环,其中 contentWindow 依赖于 renderNav,renderNav 依赖于 contentWindow。
  • 不,我只是插入了您在帖子前半部分显示的 navDep 代码,同时保持其他所有内容不变。我并不完全清楚在这种情况下如何使用 reactiveFragment 代码。我会调用 Meteor.render(Template.contentWindow); 的想法吗?从 renderNav 帮助器中,然后在返回的 html 上而不是在 DOM html 上进行我的 Nav 解析?
  • 我更新了我的答案以更详细地解释反应片段。
猜你喜欢
  • 2012-06-16
  • 2013-11-16
  • 2017-11-30
  • 2013-09-26
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 2016-05-18
相关资源
最近更新 更多