Javascript 使用angular.js阻止多个表单提交-禁用表单按钮

Javascript 使用angular.js阻止多个表单提交-禁用表单按钮,javascript,angularjs,form-submit,angularjs-directive,Javascript,Angularjs,Form Submit,Angularjs Directive,我想防止使用angular.js提交多个表单。问题与此有关 当用户单击表单提交按钮时,提交按钮的值/标签应更改为“loading..”,按钮的状态将设置为disabled,提交事件应以正常方式触发,从而导致对服务器的提交调用。这样,用户将看到以下效果: 立即:提交按钮值更改为“加载…”并被禁用 一旦服务器响应:用户就会收到服务器请求的结果(而服务器响应是在没有角度干预的情况下处理的) 我创造这个来说明我的意思。我的问题与这一行有关:elm.attr('disabled',true)。这不仅会禁用

我想防止使用angular.js提交多个表单。问题与此有关

当用户单击表单提交按钮时,提交按钮的值/标签应更改为“loading..”,按钮的状态将设置为disabled,提交事件应以正常方式触发,从而导致对服务器的提交调用。这样,用户将看到以下效果:

  • 立即:提交按钮值更改为“加载…”并被禁用

  • 一旦服务器响应:用户就会收到服务器请求的结果(而服务器响应是在没有角度干预的情况下处理的)

  • 我创造这个来说明我的意思。我的问题与这一行有关:
    elm.attr('disabled',true)。这不仅会禁用按钮,而且会阻止传播submit事件。因此,我得到了一个禁用的按钮(期望的结果),但表单没有被提交(期望的结果)

    如果注释/取消注释这一行,您可以看到变化的行为:
    elm.attr('disabled',true)

    知道如何更改吗?

    试试$timeout(angularjs函数)


    我有一个标准的表单,只在前端使用angular,所以如果您只需要在服务器响应时防止按钮被点击两次,那么您可以使用这个简单的指令,它是可重用的,不需要控制器或ngModel

    它将禁用按钮,并可选择更改按钮的文本。像这样使用:

    <button click-once>Button just disables</button>
    <button click-once="Loading...">Text changes and button disables</button>
    
    按钮只会禁用
    文本更改和按钮禁用
    

    在当前的表单中,只有在进行标准表单提交而不是ajax提交的情况下,这才有效。

    我最终也采用了指令路线。使用以下命令代替ng click,并期望传入的函数返回一个承诺(restanglar会这样做)。承诺得到解决(回复)后,将允许后续提交。还可以对此进行调整,以添加/删除禁用的ng

    //从ngClick复制并修改为仅提供单击行为
    //期望函数返回承诺
    app.directive('srMutexClick',function($parse){
    返回{
    编译:函数($element,attr){
    var fn=$parse(attr['srMutexClick']);
    返回函数srEventHandler(范围、元素){
    var=false;
    元素上('click',函数(事件){
    作用域:$apply(函数(){
    如果(提交){
    返回
    }
    提交=真;
    //承诺解决后,“提交”将重置
    fn(作用域,{$event:event}).finally(函数(){submitting=false});
    });
    });
    };
    }
    };
    });
    
    备选(灵活且简单)解决方案():围绕提交代码的包装函数,用于设置范围变量。看

    控制器中的用法:

    $scope.submit = mutexAction($scope, 'sending', submit);
    
    鉴于:

    <form ng-submit="submit()">
      ...
      <button ng-disabled="sending">
        {{sending ? "Sending..." : "Send"}}
      </button>
    </form>
    

    只需在控制器中添加一个新属性

    $scope.processing = false;
    
    用你的方法

    $scope.processData = function(){
        $scope.processing = true;
        $http.post('').then(function(){
            $scope.processing = false;
        });
    });
    
    在html中,将ng disabled属性绑定到$scope.processing属性,以禁用按钮并在方法处理时显示文本。

    作为答案的一个补充,是coffee脚本中的一个变体+如果需要,您可以启用按钮返回(例如,当表单验证失败并且您想重试时)


    这里有一个简单的方法可以通过简单的逻辑检查完成类似的工作,文本更改也可以通过类似的方式完成

    <button type="submit" class="btn btn-success btn-lg btn-block"  ng-disabled="!userForm.$valid || isValid">Submit!</button>
    
    
     $scope.isValid = false;
        $scope.submitForm = function () {
            $scope.isValid = true;
            console.log('submit');
        }
    
    提交!
    $scope.isValid=false;
    $scope.submitForm=函数(){
    $scope.isValid=true;
    console.log('submit');
    }
    
    以下是使用$http拦截器对所有AJAX请求执行此操作的一般方法。 如果您的所有REST路由都从/api/开始,那么:

         angular.module('yourapp').factory('loadingInterceptor',['$q','$rootScope',function($q,$rootScope) {
             var apiRe = /^\/api\//;
        return {
            request: function(config) {
                if (config.url.match(apiRe)) {
                    $rootScope.loading = true;
                }
                config.headers = config.headers || {};
    
                return config;
            },
            response: function(res) {
                $rootScope.loading = false;
                return $q.resolve(res);
            },
    
            'responseError': function(rejection) {
                $rootScope.loading = false;
                return $q.reject(rejection);
            }
        };
    }]);
    
    
    angular.module('yourapp').config(['$httpProvider', function($httpProvider) {
        $httpProvider.interceptors.push('loadingInterceptor');
    }]);
    

    使用拦截器,您不必在每个控制器中放入$scope.isLoading。缺点是,在请求期间,任何带有ng disabled=“loading”的按钮都将被阻止

    最简单也是最常见的方法是依赖表单对象的
    $submitted
    属性,如下所示:

    <form name="formName" ng-submit="submit()">
      ...
      <button type="submit" ng-disabled="formName.$submitted">Submit</button>
    </form>
    
    
    ...
    提交
    
    谢谢,这似乎很管用:)。。你能解释一下原因吗。。为什么超时为零?超时是为了允许浏览器先提交,然后禁用按钮。
    setTimeout
    调用中的函数放置在浏览器的事件循环中,并在表单提交后立即执行。如果没有它,按钮会过早禁用。可能应该使用
    $timeout
    ?i、 e.将$timeout参数添加到指令函数中,然后使用
    $timeout(function(){elm.attr('disabled',true);},0)几乎完美,但bumber它不适用于ajax。对ajax提交有什么建议吗?是的,对于我的案例来说,这是有意简化的,因为我的案例是与标准表单提交集成的。对于AJAX请求,有许多解决方案,从重新启用响应按钮到通用钩子。例如,此处有一篇博文:。正如我所说,我特意为标准表单提交选择了一个简化版本,易于测试,等等。@MattByrne这太棒了,我已经在表单中实现了它。但它不允许人们更正无效字段并重新提交。“提交”按钮将永久禁用。有没有关于如何解决这个问题的想法?谢谢我已经有一段时间没看这个了。我现在通常使用ajax请求——这是我为之做的一个遗留应用程序。如果要有条件地禁用按钮,可以传递一个
    函数
    ,该函数将
    布尔值
    作为参数返回指令。如果(!conditionFunction | | conditionFunction()){
    刚好在
    $timeout
    之前,您可以执行
    操作。您需要定义一个名为
    conditionFunction
    范围
    参数,该参数是可选的。当您调用它时,您将传递参数
    condition function=“myControllerFunction”
    class ClickOnceDirective
    
        constructor: (@$timeout) ->
            link = (scope, element, attrs) =>
    
                originalText = element.html()
                replacementText = attrs.clickOnce
    
                element.bind('click', =>
                    @$timeout ->
    
                        if (replacementText)
                            element.html(replacementText)
    
                        element.attr('disabled', true)
    
                        # enable back
                        @$timeout ->
                             element.attr('disabled', false)
                            if (replacementText)
                                 element.html(originalText)
                        , 500
    
                    , 0)
    
             return {
             link
             restrict: 'A'
            }
    
    directivesModule.directive 'clickOnce', ['$timeout', ClickOnceDirective]
    
    <button type="submit" class="btn btn-success btn-lg btn-block"  ng-disabled="!userForm.$valid || isValid">Submit!</button>
    
    
     $scope.isValid = false;
        $scope.submitForm = function () {
            $scope.isValid = true;
            console.log('submit');
        }
    
         angular.module('yourapp').factory('loadingInterceptor',['$q','$rootScope',function($q,$rootScope) {
             var apiRe = /^\/api\//;
        return {
            request: function(config) {
                if (config.url.match(apiRe)) {
                    $rootScope.loading = true;
                }
                config.headers = config.headers || {};
    
                return config;
            },
            response: function(res) {
                $rootScope.loading = false;
                return $q.resolve(res);
            },
    
            'responseError': function(rejection) {
                $rootScope.loading = false;
                return $q.reject(rejection);
            }
        };
    }]);
    
    
    angular.module('yourapp').config(['$httpProvider', function($httpProvider) {
        $httpProvider.interceptors.push('loadingInterceptor');
    }]);
    
    <form name="formName" ng-submit="submit()">
      ...
      <button type="submit" ng-disabled="formName.$submitted">Submit</button>
    </form>