【问题标题】:Bootboxjs: how to render a Meteor template as dialog bodyBootboxjs:如何将 Meteor 模板呈现为对话框体
【发布时间】:2014-03-15 01:51:49
【问题描述】:

我有以下模板:

<template name="modalTest">
    {{session "modalTestNumber"}} <button id="modalTestIncrement">Increment</button>
</template>

session 助手只是Session 对象的中间人。我将 modalTestNumber 初始化为 0

我希望将此模板连同其所有反应性一起呈现到引导箱模式对话框中。我为此模板声明了以下事件处理程序:

Template.modalTest.events({
    'click #modalTestIncrement': function(e, t) {
        console.log('click');
        Session.set('modalTestNumber', Session.get('modalTestNumber') + 1);
    }
});

以下是我尝试过的所有方法,以及它们的结果:

bootbox.dialog({
    message: Template.modalTest()
});

这会渲染模板,它看起来或多或少像0 Increment (in a button)。但是,当我从控制台更改 Session 变量时,它不会更改,并且当我单击按钮时不会调用事件处理程序(console.log 甚至不会发生)。

message: Meteor.render(Template.modalTest())

message: Meteor.render(function() { return Template.modalTest(); })

这两者的作用与 Template 调用本身的作用完全相同。

message: new Handlebars.SafeString(Template.modalTest())

这只是将模态体呈现为空。模态仍然会弹出。

message: Meteor.render(new Handlebars.SafeString(Template.modalTest()))

Template 和纯Meteor.render 调用完全相同;模板在那里,但它没有反应或事件响应。

是不是我使用的是this less packaging of bootstrap 而不是标准包?

我怎样才能让它以适当的反应 Meteor 风格呈现?

入侵 Bootbox?

我刚刚尝试入侵bootbox.js 文件本身,看看我是否可以接管。我改变了一些东西,以便在bootbox.dialog({}) 层我只需传递我想要渲染的模板的名称:

// in bootbox.js::exports.dialog
console.log(options.message); // I'm passing the template name now, so this yields 'modalTest'

body.find(".bootbox-body").html(Meteor.render(Template[options.message]));

body.find(".bootbox-body").html(Meteor.render(function() { return Template[options.message](); }));

这两个不同的版本(不要担心它们是两种不同的尝试,而不是同时)它们都以非反应性方式呈现模板,就像它们之前所做的那样。

入侵 bootbox 会有什么不同吗?

提前致谢!

【问题讨论】:

  • 虽然不是 bootbox,但Crater 具有旨在与 Meteor 一起使用的叠加层。
  • 这取决于您使用的 Meteor、Bootstrap 和 Bootbox 的版本。 Bootbox 4.0.0 及更高版本仅与 Bootstrap 3 兼容,并且 Meteor 0.8 及更高版本的渲染方式不同。

标签: meteor modal-dialog bootbox


【解决方案1】:

我正在使用当前 0.9.3.1 版本的 Meteor 给出答案。 如果你想渲染一个模板并保持反应性,你必须:

  • 在父节点中渲染模板
  • 让父级已经在 DOM 中

所以这个非常简短的函数就是这样做的答案:

    renderTmp = function (template, data) {
        var node = document.createElement("div");
        document.body.appendChild(node);
        UI.renderWithData(template, data, node);
        return node;
    };

在你的情况下,你会这样做:

    bootbox.dialog({
        message: renderTmp(Template.modalTest)
    });

【讨论】:

    【解决方案2】:

    Meteor 1.0+ 的答案:

    使用Blaze.renderBlaze.renderWithData 将模板渲染到引导箱对话框引导箱对话框创建之后。

        function openMyDialog(fs){ // this can be tied to an event handler in another template
          <! do some stuff here, like setting the data context !>
          bootbox.dialog({
            title: 'This will populate with content from the "myDialog" template',
            message: "<div id='dialogNode'></div>",
            buttons: {
              do: {
                label: "ok",
                className: "btn btn-primary",
                callback: function() {
                  <! take some actions !>
                }
              }
            }
          });
          Blaze.render(Template.myDialog,$("#dialogNode")[0]);
        };
    

    这假设您定义了一个模板:

        <template name="myDialog">
          Content for my dialog box
        </template>
    

    Template.myDialog 是为您使用的每个模板创建的。

    $("#dialogNode")[0] 选择您设置的 DOM 节点

        message: "<div id='dialogNode'></div>"
    

    或者,您可以将message 留空并使用$(".bootbox-body") 选择父节点。

    您可以想象,这还允许您动态更改引导框对话框的message 部分。

    【讨论】:

    • 这真的是最好的方法吗?它可以正常工作,但我想知道为什么没有办法直接在正文中显示模板而不是事后替换。
    • 我想您可以将模板放入 div 并切换其可见性。那将是一种非引导箱方法。它还会强制该模板始终被渲染,即使它从未被查看过。
    • 我的大问题是模板Template.myDialog 包含{{#autoform ...}{{&gt; afQuickField }}{{/autoform}},但我希望在我的模式中的其他按钮旁边提交按钮。这有可能吗?提交按钮必须在 {{#autoform}}{{/autoform}} 内。
    • 当然,您可以将自动表单放入模态。使用 bootbox,您可以定义没有默认按钮的完全自定义模式。见stackoverflow.com/a/31017212/2805154
    • 我有一个自定义的message 使用你的方法。但是自动表单在此消息(模态正文)内开始和结束,因此按钮位于自动表单之外(模态页脚)。您发送的链接显示如何替换消息(模态正文)
    【解决方案3】:

    使用最新版本的 Meteor,这是一种将文档渲染到引导箱中的简单方法

    let box = bootbox.dialog({title:'',message:''});
    box.find('.bootbox-body').remove();
    Blaze.renderWithData(template,MyCollection.findOne({_id}),box.find(".modal-body")[0]);
    

    如果您希望对话框是反应式的,请使用

    let box = bootbox.dialog({title:'',message:''});
    box.find('.bootbox-body').remove();
    Blaze.renderWithData(template,function() {return MyCollection.findOne({_id})},box.find(".modal-body")[0]);
    

    【讨论】:

      【解决方案4】:

      为了以编程方式呈现 Meteor 模板,同时保持其反应性,您需要使用 Meteor.render()。他们在templates 下的文档中解决了这个问题。

      所以为了让你的处理程序等工作你会使用:

      bootbox.dialog({
          message: Meteor.render(function() { return Template.modalTest(); })
      });
      

      这对我来说也是一个重大问题!

      我看到您与Meteor.render() 的关系非常密切。如果它仍然不起作用,请告诉我。

      【讨论】:

      • 查看我的编辑,我希望它也能工作,这就是为什么这是一个如此令人困惑的错误!
      • 嗯,我将您的代码复制到我的现有项目中(我已经在使用引导程序和引导箱),我在我的一个页面顶部放置了一个按钮,名为 bootbox.dialog()我包含在我的答案中并且一切正常,甚至更改了会话变量modalTestNumber。所以一定有其他东西破坏了反应。您是否尝试过将其从其余逻辑中抽象出来?也许在一个新的空白页上?
      • 刚刚尝试将其移至其他页面,没有任何变化。是不是我使用的是this less packaging of bootstrap 而不是标准包?
      • 我不这么认为,我使用的是同一个包,它对我有用。这很奇怪:/
      【解决方案5】:

      这适用于 Meteor 1.1.0.2

      假设我们有一个名为 changePassword 的模板,它有两个字段分别为 oldPassword 和 newPassword,下面是一些使用模板弹出对话框然后获取结果的代码。

      bootbox.dialog({
          title: 'Change Password',
          message: '<span/>', // Message can't be empty, but we're going to replace the contents
          buttons: {
            success: {
              label: 'Change',
              className: 'btn-primary',
              callback: function(event) {
                var oldPassword = this.find('input[name=oldPassword]').val();
                var newPassword = this.find('input[name=newPassword]').val();
                console.log("Change password from " + oldPassword + " to " + newPassword);
                return false; // Close the dialog
              }
            },
            'Cancel': {
              className: 'btn-default'
            }
          }
        });
        // .bootbox-body is the parent of the span, so we can replace the contents
        // with our template
        // Using UI.renderWithData means we can pass data in to the template too.
        UI.insert(UI.renderWithData(Template.changePassword, {
          name: "Harry"
        }), $('.bootbox-body')[0]);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-02
        • 2012-06-25
        • 2014-06-18
        • 2018-10-08
        • 2017-01-31
        • 1970-01-01
        • 2012-12-11
        • 2011-04-28
        相关资源
        最近更新 更多