2

In the WordPress theme my client is using the contact form is submitted via Ajax.

Form Markup

<form action="#" method="post" id="contactform">

    <input type="text" class="required" name="name" id="name" />
    <button name="send" type="submit" id="submit">Send</button>

    <div id="success"></div>
    <div id="failure"></div>

</form>

contact_form.js

(function ($) {

    function themeContactForm() {

        function start() {
            //binds the form elements here
        }


        function submit(e) {
            //check for form validation
            return false;
        }

        function send(data) {
            jQuery.post(
                ajaxurl,
                {
                    action : 'themeContactForm',
                    data : data
                },
                result
            );
        }

        function result(response) {
             if(response.success) {
                  //show success message
             } else {
                 //show failure message
             }    
        }

        start();
    }


    $.fn.themeContactForm = function() {

    };

}(jQuery));

app.js

$("#contactform").themeContactForm();

Issue : After clicking submit, response of success or failure takes around 3-4 secs to appear. During that time users probably think nothing is happening and they click submit again. As a result multiple copies of the same form data is received.

Question : Without touching any of the above mentioned files, is it possible to show a "spinner" when submit is clicked and hide it when the success or failure messages comes from the script, so the user know that the form is being processed.

I can modify contact_form.js and get my job done, but on theme update modifications will be lost.

I have tried binding to ajaxComplete event, but somehow can't get it to work.

$( document ).ajaxComplete(function( event, xhr, settings ) {
         alert("Global event called");  
         console.log( xhr.responseText );
});

But the alert isn't firing at all.

Anand Shah
  • 14,575
  • 16
  • 72
  • 110
  • 1
    Why is there a requirement not to touch any of the files? Typically you would include your AJAX spinner as part of the 'beforeSend' and 'complete' functions that you can attach to the jQuery AJAX request. – Mark Jan 30 '15 at 17:06
  • @Mark : As I mentioned in my post, the changes I make to those files will be lost on next theme update. – Anand Shah Jan 30 '15 at 17:07
  • 1
    Can you show how you tried to bind to the ajaxComplete event? That should be the correct method and maybe someone can point out a mistake. – DanielST Jan 30 '15 at 17:08
  • Yes, @Anand show the attempt at binding. You should be able to do this with Global AJAX Event Handlers. – Mark Jan 30 '15 at 17:10
  • Can you change `jQuery.post` to `jQuery.ajax()` http://api.jquery.com/jQuery.Ajax/ ? That is causing the problem I imagine. – DanielST Jan 30 '15 at 17:17
  • @slicedtoad, the form submits fine, so I doubt that would be the issue. Infact the client is getting multiple copies of the same form data. Impatient users :) – Anand Shah Jan 30 '15 at 17:19
  • No, I mean it isn't firing a global complete event. `$.ajax` is special in that it fires an event. – DanielST Jan 30 '15 at 17:20
  • ah ok, I understand. Will give it a try. But even if that works, I am still doomed :) as that would require changing the theme file. – Anand Shah Jan 30 '15 at 17:23
  • 2
    Wouldn't it be possible to just overwrite the existing methods in a new file? See: http://stackoverflow.com/questions/5007279/extending-an-existing-jquery-function – movabo Jan 30 '15 at 17:25
  • @movabo I like that approach. You should submit that as an answer. – Mark Jan 30 '15 at 17:27
  • @movabo , the link looks promising. I'll give it a try. – Anand Shah Jan 30 '15 at 17:27
  • 2
    @movabo wouldn't you have to overwrite the _whole_ `themeContactForm` function? All it's contained functions are essentially "private". – DanielST Jan 30 '15 at 17:40
  • @slicedtoad Yep, i guess you're right. Didn't see that. – movabo Jan 30 '15 at 19:34

1 Answers1

1

Method: Ajax complete

Edit: I removed the bit about post vs ajax, they both do the same thing.

This should work. Make sure that the listener is being attached to document directly. If it still doesn't work, post your jQuery version.

$(document).ajaxComplete( function(event,jqXHR,ajaxOptions){
    alert('!'); //add the spinner here
});

Method 2: Listen for changes

When the request finishes, something happens to the DOM in result, yes? Listen for it and kill the spinner then.

So: edit: This likely won't work since changing the text doesn't fire an event

$("#success, #failure").one("change",function(){
    alert(!); //kill the spinner
});

If you can't listen for it, use a 100ms timer that check for the existence of some DOM change.

Here is a working example of a timer:

http://jsfiddle.net/slicedtoad/3t3b9q3k/2/

$("#form").on("submit",function(e){ //simulates your ajax request
    window.setTimeout(function(){
        $("#success").text("success");
    },1000)
    return false;
});

$("#form").on("submit",function(){
    $("body").append("<div id='loading'>loading...</div>");
    var intervalID = window.setInterval(function(){
        if( $("#success").text() != "" ){
            $("#loading").remove();
            window.clearInterval(intervalID)
        }
    },100);
    return false;
});
DanielST
  • 13,783
  • 7
  • 42
  • 65
  • It didn't seem quite right so I tested it and `$.post` does indeed fire the global ajax complete event. There doesn't seem to be any note of your information on the documentation page for `$.post` either. `$.post` is just a shortcut to `$.ajax({ type : 'POST' })`. – Jasper Jan 30 '15 at 17:54
  • @Jasper you're correct, sorry. Not sure why it isn't firing though... You are attaching the listener to `document` right? – DanielST Jan 30 '15 at 18:11
  • Yeah, I copied the `.ajaxComplete` code you had posted, then pasted it into the JS console, then ran `$.post('/')` and I got the alert. It seems possible the OP is getting a JS error they don't notice or their binding code isn't running. – Jasper Jan 30 '15 at 18:12