使用Ember.js模板实现Bootstrap Popovers

7

我正在尝试在EmberJS中使用Bootstrap Popover,以便弹出窗口的内容是一个带有绑定等的ember/handlebars模板。如何实现?(Ember 1.0.0-rc2)

5个回答

12

这里有一个可以工作的 Ember Bootstrap Popover 示例(请参见http://jsfiddle.net/72fSd/):

App.Popover = Ember.View.extend({
        parentSelector: '',
        contentSelector: '',
        didInsertElement: function () {
            var self = this;
            $(self.parentSelector).popover({
                html: true,
                content: function() {
                    var $content = $(self.contentSelector);
                    return $content.html();
                }
            });
        }

实例化视图:

{{view App.Popover templateName="my-popover-content" parentSelector=".popoverButton" contentSelector="#popovercontent"}}

在这里,parentSelector 可以选择一个按钮等。请确保在my-popover-content模板中有一个id为#popovercontent的div容器,以便 contentSelector 正常工作。当然,在视图初始化之前您需要加载该模板。

使用此解决方案应该可以实现双向绑定。


你能把这个放到 JSFiddle 上吗? - Ben
1
完美。胜利者获得鸡肉晚宴。 - Ben
1
最近,我遇到了這個解決方案的問題:返回 $content.html() 不總是起作用。特別是如果您的內容變得更複雜,您應該考慮使用 http://api.jquery.com/remove/ 代替,它會真正地取 DOM 元素,並將其移動到彈出框中。不幸的是,我無法相應地調整 fiddle。希望對您有所幫助。 - Robert
1
不确定为什么需要 parentSelectorcontentSelector。最简单的解决方案如 http://cowbell-labs.com/2013-10-20-using-twitter-bootstrap-js-widgets-with-ember.html 中所述。 - morgoth
抓取一个未显示标签的HTML内容似乎不是最佳实践,但这很简单,对我很有效。我见过的其他选项是将一个模板化的弹出框内容直接重写整个Bootstrap代码到Ember组件中,这可能很痛苦。 - cwarny
答案中的JSFiddle“可能”有问题。检查代码,我发现模板中的input标签具有相同的ID,最终成为实际弹出内容的input标签。在页面上多次使用相同的ID是无效的。有没有避免这种情况的方法? - Terry Roe

7
我将Terry的答案进一步扩展,认为我已经想出了一个简单通用的解决方案。
我创建了一个bootstrap-popover组件,如下所示:
App.BootstrapPopoverComponent = Ember.Component.extend({
  tagName: 'div',      //whatever default you want... div is default anyway here
  classNames: '',      //whatever default you want
  placement: 'bottom', //whatever default you want
  didInsertElement: function () {
    var component = this,
        contents = this.$('.popoverJs');
    component.$().popover({
      animation: false,
      placement: component.get('placement'),
      html: true,
      content: contents
    }).on('show.bs.popover', function () {
      contents.removeClass('hide');
    });
  },
  willDestroyElement: function () {
    this.$().popover('destroy');
  }
});

以下是相关的模板:
<script type="text/x-handlebars" id="components/bootstrap-popover">
  {{title}}
  <div class="popoverJs hide">
    {{yield}}
  </div>
</script>

请注意使用“hide”类来初始隐藏生成的内容。该类只是“display: none”。如果没有这个类,事情就不会如你所希望的那样工作。
有了这个,每当你想要一个弹出框时,你可以简单地执行以下操作:
  {{#bootstrap-popover title="My Fancy Popover" tagName="button"}}
    <ul>
      <li>my</li>
      <li>awesome</li>
      <li>popover</li>
      <li>contents</li>
      <li>example</li>
    </ul>
  {{/bootstrap-popover}}

内容可以是任何你想要的-任意HTML,渲染组件或部分等。当然,你可以根据需要指定其他标记名称、类名、标题、位置等。

我希望这个解决方案能帮到你。


1
这真的很棒。谢谢!虽然它肯定比被接受的答案更复杂,但我认为它的可重用性使其成为最好的选择。 - xcskier56
这种方法存在问题,在某些不常见的情况下会出现问题:如果呈现弹出窗口内容的模板具有应用{{action ...}}助手的元素,则这些元素将丢失,因为组件所做的是从模板呈现的元素中克隆弹出窗口html到实际呈现的新元素中。在该过程中,操作处理程序会丢失。我仍在努力解决如何克服这个问题。但是,答案本身没有任何问题。我知道我的用例非常罕见。 - Ernesto
这个完美运作!有一个问题!如何关闭除了点击的弹出框以外的其他已打开的弹出框? - Thilina Dinith Fonseka

2

例如,如果您想要弹出图像,请在视图中执行以下操作:

imgTag: '<img src="smiley.gif" alt="Smiley face" height="42" width="42">',

didInsertElement: function () {
    var self = this;
    Ember.run.schedule('actions', this, function () {
        self.$().popover({
            title: 'Smile!!!',
            html: true,
            content: self.get('imgTag'),
            placement: 'bottom',
            trigger: 'hover'
        });
    });
},

willDestroyElement: function () {
    this.$().popover('destroy');
}

这让我可以在内容中使用静态HTML,但如何在其中呈现模板? - Ori Shavit
Ember.Handlebars.compile("我的Handlebar {{handlebarProperty}}") - pjlammertyn
1
'<div id="myPopupContentId"></div>'将其翻译为中文: '<div id="myPopupContentId"></div>'然后在代码中创建视图: var popupContentView = APP.PopUpContentView.create({ controller: popupContentController });并将其添加到您的内容 div 中 popupContentView.appendTo($('#myPopupContentId')); - pjlammertyn

2
我也遇到了这个问题,并且与Robert提到的相同问题,在更复杂的情况下可接受的解决方案无法很好地扩展。我找到了一个非常优雅的解决方法,但不确定它在未来是否友好。我正在利用函数renderToBuffer - 请参见下面:
//make your popover view to be created later
App.PopoverView = Ember.View.extend({
  templateName : 'name-of-your-template-with-content'
});

//then you make your link that will trigger the popover
App.PopoverLinkView = Ember.View.extend({

  tagName : 'a',

  didInsertElement : function(){

  var that = this;

  this.$().popover({
    'html' : true,
    'content' : function(el){
    var detailView = App.PopoverView.create();
    var html = detailView.renderToBuffer().buffer;
    return html;
    }
  });

  }

});

这里的优点是可以传入模型并使事情变得动态。虽然没有进行全面测试,但希望发布这篇文章能够帮助其他人。

1
我将Robert的回答进一步扩展了。我创建了一个组件,也只是使用jQuery元素作为内容,而不是调用.html()。(这解决了页面中重复ID的问题。)
App.CustomPopoverComponent = Ember.Component.extend({
  tagName: 'button',
  classNames: 'btn btn-default',
  type: 'button',
  popoverContentSelector: '',
  didInsertElement: function () {
    var component = this,
        contents = $(component.get('popoverContentSelector'));

    component.$().popover({
      placement: 'bottom',
      html: true,
      content: contents
    }).on('show.bs.popover', function () {
      contents.removeClass('hide');
    });
  },
  willDestroyElement: function () {
    this.$().popover('destroy');
  }
});

我使用了Bootstrap的“hide”类来最初隐藏内容。然后,第一次显示弹出框时,我删除了“hide”类。从那时起,事情就按预期进行。
以下是在handlebars模板中使用该组件的方法:
  {{#custom-popover popoverContentSelector='.popoverContents'}}
    Popover Button
  {{/custom-popover}}

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