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