$ jj/$ q调用上的angularjs禁用按钮

har*_*shr 12 angularjs angularjs-directive

在DRY主体之后,我想写一个按钮指令,它在$ http类的持续时间内保持按钮被禁用.

我想这样做是为了禁止用户多次单击按钮,但我无法考虑如何在指令中获取函数承诺状态,因为函数驻留在$ scope

该场景非常通用,按钮ng-click确实调用了一个函数,该函数又进行$ http调用.用户点击:按钮应该被禁用,只有在$ http调用解决后才能启用,无论是成功还是失败.

Art*_*ich 37

为什么不让它变得更容易.

<button ng-click="save()" ng-disabled="isProcessing">Save</button>


$scope.save = function(){
  $scope.isProcessing = true;
  $http.post('Api/Controller/Save', data).success(
    $scope.isProcessing = false;
  );
}
Run Code Online (Sandbox Code Playgroud)

当然,如果您在应用程序中的极少数地方需要此逻辑,则会出现这种情况.

如果你有这样的逻辑重复多次(如果你不是懒惰:)),那么为了遵循SOLID原则,它最好将这个功能包装成指令(查看这个问题的其他答案以查看这样的指令的例子) .

  • 我目前正在做你建议的,但如果那时我必须管理每个按钮一个布尔值...创建一个指令,将在整个项目中自动处理 (6认同)
  • 这是没有干的,因为你必须为每个按钮处理异步状态.接受的答案是一个更好的解决方案.这个对于简单的项目来说非常简单,但是当事情变得更加复杂时,这将成为沉重的负担. (2认同)

Mic*_*mza 29

虽然我会小心过度工程,但实现这一点的方法是使用自定义指令.这个指令

  • 接受必须返回promise的作用域中的函数传递的选项
  • 单击该按钮,调用此功能,并禁用该按钮
  • finally承诺上,它重新启用按钮

-

app.directive('clickAndDisable', function() {
  return {
    scope: {
      clickAndDisable: '&'
    },
    link: function(scope, iElement, iAttrs) {
      iElement.bind('click', function() {
        iElement.prop('disabled',true);
        scope.clickAndDisable().finally(function() {
          iElement.prop('disabled',false);
        })
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

这可以在按钮上使用,如下所示:

<button click-and-disable="functionThatReturnsPromise()">Click me</button>
Run Code Online (Sandbox Code Playgroud)

您可以在http://plnkr.co/edit/YsDVTlQ8TUxbKAEYNw7L?p=preview中看到此操作,其中返回promise的函数是:

$scope.functionThatReturnsPromise = function() {
  return $timeout(angular.noop, 1000);
} 
Run Code Online (Sandbox Code Playgroud)

但是你可以替换$timeout与一个呼叫$http,或从返回一个承诺任何服务的功能.


Alv*_*son 9

我喜欢@ codef0rmer的解决方案,因为它是集中式的 - 即每个HTTP请求都不需要额外的代码,您只需要检查progressHTML中的全局标志.但是,transformResponse用于确定请求何时完成是不可靠的,因为服务器可能不会返回任何内容; 在这种情况下,处理程序不会被调用,progress并且永远不会被设置回false.此外,如所写,答案不考虑多个同时请求(progress可能false在所有请求完成之前返回).

我提出了一个类似的解决方案,它使用拦截器来解决这些问题.你可以把它放在你的Angular应用程序的配置功能中:

.config(function ($httpProvider) {
    $httpProvider.interceptors.push(function($q, $rootScope) {
        var numberOfHttpRequests = 0;
        return {
            request: function (config) {
                numberOfHttpRequests += 1;
                $rootScope.waitingForHttp = true;
                return config;
            },
            requestError: function (error) {
                numberOfHttpRequests -= 1;
                $rootScope.waitingForHttp = (numberOfHttpRequests !== 0);
                return $q.reject(error);
            },
            response: function (response) {
                numberOfHttpRequests -= 1;
                $rootScope.waitingForHttp = (numberOfHttpRequests !== 0);
                return response;
            },
            responseError: function (error) {
                numberOfHttpRequests -= 1;
                $rootScope.waitingForHttp = (numberOfHttpRequests !== 0);
                return $q.reject(error);
            }
        };
    });
})
Run Code Online (Sandbox Code Playgroud)

现在您可以使用waitingForHttp禁用按钮(或显示"忙"页面).使用拦截器可以获得额外的好处,现在您可以使用错误函数将所有HTTP错误记录在一个地方(如果需要).


cod*_*mer 7

您可以在运行块中使用它.这将确保在有活动的XHR呼叫时将禁用所有按钮.

myApp.run(function($rootScope, $http) {
    $http.defaults.transformRequest.push(function (data) {
        $rootScope.progress = true;
        return data;
    });
    $http.defaults.transformResponse.push(function(data){ 
        $rootScope.progress = false;
        return data;
    }) 
});
Run Code Online (Sandbox Code Playgroud)

然后在任何地方使用相同的型号.

 <button ng-click="save()" ng-disabled="progress">Save</button>
Run Code Online (Sandbox Code Playgroud)