I want to prevent multiple form submissions using angular.js. The question is related to this question.
When the user clicks on a form submit button the value / labe
Just add a new property in your controller
$scope.processing = false;
In your method
$scope.processData = function(){
$scope.processing = true;
$http.post('').then(function(){
$scope.processing = false;
});
});
In your html bind ng-disabled attribute to the $scope.processing property to disable the button and show text while the method is processing.
Here is a general way to do it for all AJAX requests using $http interceptors. If you have all of your REST routes starting from /api/ then:
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');
}]);
Using interceptor you won't have to put $scope.isLoading in each controller. The downside is that any button with ng-disabled="loading" will be blocked during request.
The easiest and most common way of doing it is to rely on $submitted
property of form object like so:
<form name="formName" ng-submit="submit()">
...
<button type="submit" ng-disabled="formName.$submitted">Submit</button>
</form>
I have a standard form and just use angular in the front-end, so if you just need to prevent a button being clicked twice while the server is responding then you can use this simple directive which is re-usable and requires no controller or ngModel.
http://plnkr.co/edit/2aZWQSLS8s6EhO5rKnRh?p=preview
app.directive('clickOnce', function($timeout) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var replacementText = attrs.clickOnce;
element.bind('click', function() {
$timeout(function() {
if (replacementText) {
element.html(replacementText);
}
element.attr('disabled', true);
}, 0);
});
}
};
});
It will disable the button and optionally change the text of the button. Use like so:
<button click-once>Button just disables</button>
<button click-once="Loading...">Text changes and button disables</button>
In its current form this will only work if you are doing standard form submissions and not ajax submission.
here is the simple way to do similar stuff with simple logical checks, text change can also be done in similar fashion.
<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');
}
An addition to spenthil answer, a variant in coffee script + you can enable a button back if you need (e.g. when a form validation has failed and you want to try again)
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]