Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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 / label of the submit button should change to "loading..", status of the button will be set to disabled AND the submit event should be triggered in the normal way, leading to a submit call to the server. This way the user would see the following effect:

  1. Immediately: The submit button value changes to "loading.." and gets disabled

  2. As soon as the server responds: user gets presented the result of the server request (whereas server responds are handled without angular intervention)

I created this plunk to show what I mean. My issue relates to this line: elm.attr('disabled',true); . This does not only disable the button, but also prevent to propagate the submit event. Thus I get a disabled button (desired result), but the form does not get submitted (undesired result).

You can see the changing behavior if you comment / uncomment this line : elm.attr('disabled',true);

Any idea how to change this?

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

Try a timeout

setTimeout(function(){
    elm.attr('disabled',true);
}, 0)
share|improve this answer
    
Thanks, this seems to do the trick :) plnkr.co/edit/pl7d7uCuA4tRbproT5PP?p=preview .. can you explain why!? ..and why a timeout of zero? –  Thomas Kremmel Apr 4 '13 at 9:53
    
The timeout is there to allow the browser to first submit, then disable the button. The function in the setTimeout call is placed in the browser's event loop and executed immediately after the form has been submitted. Without it, the button is disabled too early. –  Daniel Lidström Apr 18 '13 at 13:55
1  
Probably should use $timeout instead? i.e. add the $timeout param to your directive function then use $timeout(function(){ elm.attr('disabled',true); }, 0); –  Matt Byrne Nov 6 '13 at 21:49
add comment

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.

share|improve this answer
    
almost perfect, but bumber it doesn't work with ajax. any recomendation for ajax submits? –  JasonS Nov 18 '13 at 9:08
    
Yea it's deliberately simplified for my case which was to integrate with a standard form submission. There are a number of solutions for AJAX request from re-enabling the button on response, to generic hooks. For example there is a blog post here: blog.codebrag.com/post/57412530001/…. Like I said, I deliberately chose a dumbed-down version for standard form submissions, easy to test, etc. –  Matt Byrne Nov 21 '13 at 23:06
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.