Bootstrap 弹出窗口 - 将事件动态附加到弹出窗口的按钮

Bootstrap Popup - Attach event to button for popover dynamically

我打算使用 Bootstrap Popover 模块作为删除事件的确认,这样当 <button> 被点击时,它不会简单地触发一个函数,而是打开一个弹出窗口,让我们用户确认取消 操作。

上下文需要注意的是环境是self-built,one-page~mvc webapp,里面的元素是动态添加的(所以不知道多少预先定义元素,我也不能对每个元素的操作进行硬编码)


在目前的情况下(没有弹出窗口)我做了类似的事情来触发直接(non-conformation)动作:

$view.on('click', '.deleteButton', function () {
    var id = $(this).attr('data-id');
    api.delete('someUrl' + id, successFunction);
}):

按钮的标记与此类似:

<button class="deleteButton" data-id="2">Delete me!</button>

但是,现在我想添加一个确认步骤(例如"Are you sure you want to delete this magnificent button? (Y/N)"),并想到使用bootstrap popover。

经过一番头脑风暴,我想到了如下策略。这不是最佳解决方案(最佳解决方案是扩展 popover 模块,以便我能够将 confirmationFunction 和 cancelFunction 传递给 popover)。

首先,我必须启动弹出窗口。

$view.find('.deleteButton').popover({
  title: 'Are you sure?', //Example title
  html: true, //Essential for the html to work as expected
  selector: '.deleteButton', //Allow ajaxing in of new elements
  container: '.viewName', //So that the popovers reside w/in the current view and thus can be bound to $view (a jQuery object for the view)
  content: [...], //Two <button>s with a specified class, e.g. .viewName__deleteButton--popover
});

其次,我会将事件绑定到弹出框内的按钮

$view.on('click', '.viewName__deleteButton--popover', function () {
    var id = ??; // Here comes the troubling part - how do I get the ID of the clicked button? How can I target the original button? If I can do that, I think it would solve everything.
    api.delete('someUrl' + id, successFunction);
});

出现的问题是如何定位最初点击的按钮?

我能想出的唯一解决方案,一点也不整洁,就是做这样的事情:

var popoverId = $(this).parents('.popover').attr('id'); //returns popoverXXXXXX
var parentElement = $view.find('[aria-describedBy="' + popoverId + '"]');

它有效,但它是一个非常肮脏的解决方案,根本感觉不到 'nice'。

有什么方法可以更简洁地完成这项工作吗?最好我能够定义一个通用函数,例如 $element.confirmationPopover({popoverSettings...}, confirmationFunction, declineFunction);,它可以在多种情况下使用。

(PS: 我想不出这个问题的简洁标题,一如既往地感谢您的建议!)

我通过创建 jQuery 的扩展来解决它,这样:

$.fn.confirmationPopover = function (passedInOptions) {
  var $view = this;

  var defaultOptions = {
    confirmationLabel: 'Yes',
    container: '.' + this.attr('class'),
    declineLabel: 'No',
    html: true,
    placement: 'left',  //top | left | right | bottom
    rowClasses: false
  };

  if (!passedInOptions.declineClass) {
    passedInOptions.declineClass = passedInOptions.selector + '__popover__decline';
  }

  var obj = {}; //Merged options
  $.extend(true, obj, defaultOptions, passedInOptions);

  var popoverContent = '<div class="row ' + (obj.rowClasses ? obj.rowClasses : 'tac') + '">' +
                        '<button class="button button--small ' + obj.confirmationClass + '">' + obj.confirmationLabel + '</button>' +
                        '<button class="button button--small button--outline ' + obj.declineClass + '">' + obj.declineLabel + '</button>' +
                      '</div>';

  if (!obj.content) {
    obj.content = popoverContent;
  }

  /* Initiate Popover */
  $view.popover(obj);

  /**
   * Bind confirmation Button
   */
  $view.on('click', '.' + obj.confirmationClass, function () {
    var popoverId = $(this).parents('.popover').attr('id');
    var $this = $view.find('[aria-describedBy="' + popoverId + '"]');
    obj.confirmationFunction($this);
  });

  /**
   * Bind decline button
   */
  $view.on('click', '.' + obj.declineClass, function () {
    var popoverId = $(this).parents('.popover').attr('id');
    var $this = $view.find('[aria-describedBy="' + popoverId + '"]');
    if (typeof obj.declineFunction === 'function') {
      obj.declineFunction($this);
    } else {
      $this.popover('hide');
    }
  });

  return this;
};

你也可以用popoverX! .它是 bootstrap 弹出框的模态版本。