bigpotato
bigpotato

Reputation: 27517

Rails 3 + Ajax: Ajax only fires if I add an alert after code?

I am working on an E Commerce website. In the checkout, in the middle of filling out your billing address you can decide to sign in. When you press "Log in", it should save whatever you already typed into the form before proceeding to the sign in page.

However, my AJAX doesn't seem to be firing on staging. In development, when I click on the link everything works perfectly fine.

The link in my view:

<%= link_to "log in", guest_login_path, class: "automatically_save_billing_info" %>.

jQuery:

    $('.automatically_save_billing_info').on("click", function(e) {
        console.log("here"); // <-- notice console
        var data = new Object();
        $('form.billing_info_form input[type=text], form.billing_info_form select').each(function(){
            var param = $(this).attr("name");
            var value = $(this).val();
            data[param] = value;
        });
        console.log(data);
        jQuery.ajax({
            url: '/checkout/save_billing_address',
            type: 'POST',
            data: data,
            dataType: 'script'
        });
        console.log("!!!"); // <-- notice console
    });

In my development log, I can see it making the request:

    Started POST "/checkout/save_billing_address" for 127.0.0.1 at 2014-04-10 12:21:27 -0400
    Processing by CheckoutController#save_billing_address as JS
    ...
    Started GET "/checkout/guest_login" for 127.0.0.1 at 2014-04-10 12:21:27 -0400
    Processing by CheckoutController#guest_login as HTML

However, in my staging log it goes straight to the sign in page and skips the save_billing_address action:

    Started GET "/checkout/guest_login" for 127.0.0.1 at 2014-04-10 12:21:27 -0400
    Processing by CheckoutController#guest_login as HTML

The thing is, on staging when I check the console.log that I printed in my jQuery to make sure my code is being run, I see here and !!!.

Now the weird thing is that if I change those console.logs into alert("here") and alert("!!!");, my code works... what is going on???

Upvotes: 0

Views: 74

Answers (2)

atmaish
atmaish

Reputation: 2613

There are chances that the default action for the link is being triggered before the ajax is complete. The reason it works with alert also makes me believe so.

Try this:

$('.automatically_save_billing_info').on("click", function(e) {
    console.log("here"); // <-- notice console
    var data = new Object();
    $('form.billing_info_form input[type=text], form.billing_info_form select').each(function(){
        var param = $(this).attr("name");
        var value = $(this).val();
        data[param] = value;
    });
    console.log(data);
    jQuery.ajax({
        url: '/checkout/save_billing_address',
        type: 'POST',
        data: data,
        dataType: 'script',
        complete: function(){
            window.location = $('.automatically_save_billing_info').attr("href");
        }
    });
    console.log("!!!"); // <-- notice console
    return false; // this will prevent the anchor redirect.
});

Upvotes: 1

Mark Meyer
Mark Meyer

Reputation: 3723

It would appear you have a race condition. When the user clicks on the link you are trying to make an ajax call and then redirect them. Because the ajax call is an asynchronous event there is no guarantee it will finish before the user is redirected. By inserting the alert, this is causing the browser to wait, which will allow the ajax call to complete.

My recommendation is to not use an ajax call for this, but to store the data in local or session storage. This is data that does not need to be stored on your server anyways as it will be transmitted once they actually complete the order.

$('.automatically_save_billing_info').on("click", function(e) {
    var data = {};
    $('form.billing_info_form input[type=text], form.billing_info_form select').each(function(){
        var param = $(this).attr("name");
        var value = $(this).val();
        data[param] = value;
    });
    if(window.sessionStorage){
        sessionStorage.setItem('site.checkout.billingAddress',data);
    } //else save to a cookie
});

When the page reloads then you can just pull it from sessionStorage using

sessionStorage.getItem('site.checkout.billingAddress')

Keeping it on the client will save unnecessary work for the server and fix the issue you are seeing.

You can use a library like localForace to ease the fall back also.

Upvotes: 1

Related Questions