防止/处理角度的双击按钮

Bre*_*ako 40 angularjs

在angular中我们可以设置一个按钮来发送像这样的ajax请求:

... ng-click="button-click"
Run Code Online (Sandbox Code Playgroud)

在控制器中:

...
$scope.buttonClicked = function() {
   ...
   ...
   // make ajax request 
   ...
   ...
}
Run Code Online (Sandbox Code Playgroud)

因此,为了防止双重提交,我可以在单击按钮时将buttonclicked设置为true,并在ajax回调完成时取消设置.但是,即使这样,控制也会被处理回角色,他们会更新Dom.这意味着在原始按钮单击完全100%完成之前,有一个小窗口可以再次单击按钮.

这是一个小窗口,但仍然可以发生.任何提示,以完全避免这种情况发生 - 客户端即没有对服务器进行任何更新.

谢谢

zs2*_*020 40

首先你最好添加ngDblclick,当它检测到双击时返回false:

<ANY ng-click="buttonClicked()" ng-dblclick="return false">
Run Code Online (Sandbox Code Playgroud)

如果要等待Ajax调用完成,则可以通过设置ng-disabled来禁用该按钮

<ANY ng-click="buttonClicked()" ng-dblclick="return false;" ng-disabled="flag">
Run Code Online (Sandbox Code Playgroud)

在你的控制器中,你可以做到

$scope.flag = false;
$scope.buttonClicked = function() {
    $scope.flag = true;
    Service.doService.then(function(){
        //this is the callback for success
        $scope.flag = false;
    }).error(function(){
        //this is the callback for the error
        $scope.flag = false;
    })
}
Run Code Online (Sandbox Code Playgroud)

当ajax调用成功或失败时,您需要处理这两种情况,因为如果它失败了,您不希望它显示为禁用混淆用户.

  • ng-dbclick似乎在1.3中没有这样工作:语法错误:令牌'false'是从[false]开始的表达式[return false]的第8列的意外标记. (11认同)
  • `ng-dblclick`无法在angularjs上测试> 1.4它给出了**语法错误:令牌'false'是一个意外的令牌** (10认同)
  • 如果AJAX请求的时间超过浏览器的双击时间/窗口,则无法使用.即,用户可以暂停并再次单击. (5认同)
  • `finally()`对promise的调用是否会更清楚地重置旗帜? (4认同)

Jon*_*mbo 35

ng-disabled在这个例子中使用工作正常.无论我多么疯狂地点击控制台消息只填充一次.

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.submitData = function() {
    $scope.buttonDisabled = true;
    console.log("button clicked");
  }

  function augment() {
    var name, fn;
    for (name in $scope) {
      fn = $scope[name];
      if (typeof fn === 'function') {
        if (name.indexOf("$") !== -1) {
          $scope[name] = (function(name, fn) {
            var args = arguments;
            return function() {
              console.log("calling " + name);
              console.time(name);
              fn.apply(this, arguments);
              console.timeEnd(name);
            }
          })(name, fn);
        }
      }
    }
  }

  augment();
});
Run Code Online (Sandbox Code Playgroud)
<!doctype html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="style.css">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <input type="button" ng-click="submitData()" ng-disabled="buttonDisabled" value="Submit" />
</body>

</html>
Run Code Online (Sandbox Code Playgroud)

我很好奇角度将更改应用到buttonDisabled标志需要多长时间.如果在plunker 示例中检查控制台,则会显示执行$eval$apply执行方法所需的时间.在我的机器上,它平均需要1-2毫秒.

  • FWIW,应用disabled属性需要多长时间并不重要.运行JavaScript代码会阻止您的环境(包括所有事件处理),因此如果您的设置在单击时被禁用,则在设置禁用后,将处理下一次单击_always_.TL; DR,这种方法非常可靠. (2认同)

小智 11

我只是扩展了zsong的代码,在标志的处理程序中添加一个检查.如果它是真的那么只返回因为已经处理了一个点击.这可以防止双击而不用担心角度定时或类似的事情.

$scope.flag = false;
$scope.buttonClicked = function() {
    if ($scope.flag) {
        return;
    }
    $scope.flag = true;
    Service.doService.then(function(){
        //this is the callback for success
        $scope.flag = false;
    }).error(function(){
        //this is the callback for the error
        $scope.flag = false;
    })
}
Run Code Online (Sandbox Code Playgroud)

  • 一个 `finally()` 会更清晰地重置 `$scope.flag` (3认同)

mat*_*ias 7

您可以使用我刚刚完成的指令来防止用户在执行异步操作时多次单击元素

https://github.com/mattiascaricato/angular-click-and-wait


您可以使用npmbower将其添加到项目中

npm install angular-click-and-wait
Run Code Online (Sandbox Code Playgroud)

要么

bower install angular-click-and-wait
Run Code Online (Sandbox Code Playgroud)

用法示例

const myApp = angular.module('myApp', ['clickAndWait']);

myApp.controller('myCtrl', ($scope, $timeout) => {
  $scope.asyncAction = () => {
    // The following code simulates an async action
    return $timeout(() => angular.noop, 3000);
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdn.rawgit.com/mattiascaricato/angular-click-and-wait/master/dist/click-and-wait.js"></script>

<section ng-app="myApp">
  <div ng-controller="myCtrl">
    <button click-and-wait="asyncAction()">Click Me!</button>
  </div>
</section>
Run Code Online (Sandbox Code Playgroud)

注意:作为参数传递的异步操作应该是Promise