确认 - 按钮事件触发两次

时间:2017-04-07 20:01:23

标签: javascript jquery angularjs

所以我有一个确认按钮:

<confirm-button class-name="btn-primary" 
                text="Save"
                body="A customer with the same Last Name is already associated with this Company. Do you want to create this customer anyway?"
                action="vm.save(false)"
                place="bottom"></confirm-button>

这是一个自定义指令:

.directive('confirmButton', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            text: '@',
            className: '@',
            action: '&'
        },
        controller: function ($scope, $element, $attrs) {
            var content = $attrs.body ? '<p>' + $attrs.body + '</p>' : '';
            var place = $attrs.place ? $attrs.place : 'top';

            var rndEleId = 'BtnId' + Math.random().toString(36).slice(2);

            var popoverOpts = {
                title: $attrs.title || 'Are you sure?',
                placement: place,
                html: true,
                content: content +
                    '<div class="centered">' +
                    '<button id="yes' + rndEleId + '" name="yes' + rndEleId + '" type="button" class="btn btn-primary btn-small" data-result="yes"><i class="icon-ok"></i> Yes</button>' +
                    '&nbsp;' +
                    '<button id="no' + rndEleId + '" name="no' + rndEleId + '" type="button" class="btn btn-warning btn-small" data-result="no"><i class="icon-ban-circle"></i> No</button>' +
                    '</div>'
            };

            $element.popover(popoverOpts)
                .parent()
                .delegate('button',
                    'click',
                    function(e) {
                        e.preventDefault();

                        var el = $(e.currentTarget);
                        var result = el.data('result');

                        $element.popover('hide');

                        if (result === 'yes') {
                            $scope.$apply($scope.action);
                        }
                    }
                );
        },
        template: '<a href="" class="btn {{className}}">{{text}}</a>'
    };
})

我在页面上有这个按钮两次:一次在页面顶部,一次在底部。无论您单击哪一个,当单击是或否按钮时,它们会触发两次。这意味着按钮Action属性中的Save方法被调用两次。如果您正在更新记录,那不是一件可怕的事情,但如果您正在创建记录......它会被创建两次。

我使用了Chrome的开发人员工具,并在指令的e.preventDefault();行放置了一个断点,当然,它会被击中两次。

但是,只有在页面上使用了多个指令时才会发生这种情况。如果我只有一个按钮(在页面的顶部或底部),e.preventDefault();断点只会被击中一次。此外,它似乎是多线程的。我把一个计数器变量放在一个点上,旧学校的理论是“将它设置为0,然后将其设置为++,并检查它是否现在为1.如果它大于1,则不要执行操作如果等于1,则执行操作。“并且变量...每次都是新创建的,因此永远不会超过1。

我受到了阻碍。

1 个答案:

答案 0 :(得分:1)

您还没有真正问过直接问题,但似乎您想知道为什么正在发生这种情况。

之所以发生这种情况,是因为您每次指令加载时都会向指令的父级添加一个click事件监听器。因此,当您在同一页面上有两个这样的指令时,您单击了按钮并且事件被触发两次,因为已注册了2个事件侦听器。下面是使用delegate方法注册事件监听器的地方:

$element.popover(popoverOpts)
  .parent()
  .delegate('button',
    'click',
      function(e) {
        ...

首先,您需要确保自行清理并在指令被销毁时取消绑定您的事件监听器(请查看文档中的life-cycle hooks) 。下面是一个快速示例,说明如何在指令被销毁时取消绑定事件监听器:

// ...

// register your popover here
$element.popover(popoverOpts);

// reference your parent
var parent = $element.parent();

// reference your click function
var handleClick = function(e) {
    e.preventDefault();

    var el = $(e.currentTarget);
    var result = el.data('result');

    $element.popover('hide');

    if (result === 'yes') {
        $scope.$apply($scope.action);
    }
}

// register your event listener
parent.on('click', handleClick);

// when your directive get's destroyed you need to unbind the `handleClick` function
$scope.$on('$destroy', function(e) {
    parent.off('click', handleClick);
});

// ...

要解决您的问题,您需要确保注册事件监听器以满足您的需求。您可以阅读有关事件监听器here的更多信息。

虽然说实话,看看你的代码,你应该试试ui-bootstrap