Preventing / dealing with double button clicks in angular

前端 未结 13 1183
我寻月下人不归
我寻月下人不归 2020-11-27 19:53

In angular we can set up a button to send ajax requests like this in view:

... ng-click=\"button-click\"

and in controller:



        
13条回答
  •  迷失自我
    2020-11-27 20:43

    I recently had to do this, and I've brought a couple of solutions together. This works for me, it is a directive that is an alternative to ng-click that can only ever be clicked once.

    This solution throws errors, which made it super easy to test.

    .directive('oneClickOnly', [
        '$parse', '$compile', function($parse, $compile) {
            return {
                restrict: 'A',
                compile: function(tElement, tAttrs) {
    
                    if (tAttrs.ngClick)
                        throw "Cannot have both ng-click and one-click-only on an element";
    
                    tElement.attr('ng-click', 'oneClick($event)');
                    tElement.attr('ng-dblclick', 'dblClickStopper($event)');
    
                    tElement.removeAttr('one-click-only');
                    var fn = $parse(tAttrs['oneClickOnly']);
    
                    return {
                        pre: function(scope, iElement, iAttrs, controller) {
                            console.log(scope, controller);
                            var run = false;
                            scope.oneClick = function(event) {
                                if (run) {
                                    throw "Already clicked";
                                }
                                run = true;
                                $(event.toElement).attr('disabled', 'disabled');
    
                                fn(scope, { $event: event });
    
                                return true;
                            };
                            scope.dblClickStopper = function(event) {
                                event.preventDefault();
                                 throw "Double click not allowed!";
                                return false;
                            };
    
                            $compile(iElement)(scope);
                        }
                    };
                },
                scope: true
            };
        }
    ])
    

    Here are my tests (in case anybody is interested)

    'use strict';
    describe("The One click button directive", function() {
    var $scope, testButton, $compile, clickedEvent;
    var counter = 0;
    
    beforeEach(function () {
        counter = 0;
    
        module('shared.form.validation');
    
        inject(function ($rootScope, _$compile_) {
    
            $compile = _$compile_;
            $scope = $rootScope.$new();
    
            $scope.clickEvent = function (event) {
                counter++;
            };
        });
    });
    
    it("prevents a button from being clicked multiple times", function () {
    
        var html = "test button";
        testButton = $compile(html)($scope);
    
        $scope.$digest();
    
        testButton.click();
        expect(function () { testButton.click(); }).toThrow("Already clicked");
    
        expect(counter).toBe(1);
    });
    
    it("doesn't allow ng-click on the same tag", function() {
        var html = "test button";
        expect(function () { $compile(html)($scope); }).toThrow("Cannot have both ng-click and one-click-only on an element");
    });
    
    it("works for multiple buttons on the same scope", function () {
    
        var counter2 = 0;
        $scope.clickEvent2 = function (event) {
            counter2++;
        };
    
        var html = "test button";
        var html2 = "test button";
        testButton = $compile(html)($scope);
        var testButton2 = $compile(html2)($scope);
    
        $scope.$digest();
    
        testButton.click();
        expect(function () { testButton2.click(); }).not.toThrow("Already clicked");
    
        expect(counter).toBe(1);
        expect(counter2).toBe(1);
    });
    });
    

提交回复
热议问题