Why can’t I browse to other pages after making an ajax call?

Loading...

Why can’t I browse to other pages after making an ajax call?

In a legacy MVC 5 web app I want the user to be able to continue browsing after clicking a button which makes an ajax call to a long running action.
(Note: The action returns void - I am not interested in the response)

When I click the button I am unable to make any other requests until the action completes.

Edit: Here is the ajax code:
$('#EmailReport') //
    .click(function() {
        $.ajax({
            type: "POST",
            url: '/Home/EmailReport',
            complete: function() {console.log("done")},
            async: true
        });
    });

Controller
[HttpPost]
public async Task EmailReport()
{
   // for testing - sleep for 10 seconds
   await Task.Delay(TimeSpan.FromSeconds(10));
}

Here is a screenshot in Chrome dev tools: 

EmailReport is the ajax call, the two requests at the bottom are me trying to browse to another page - as you can see the first request is pending and any subsequent requests are cancelled
Does anyone have any ideas how I can resolve or troubleshoot this issue? 

Solutions/Answers:

Answer 1:

The simplest way would be as follows :

Task t = new Task(() => TimeSpan.FromSeconds(10));
t.Start();

It is better to use Task as compared to thread for long running jobs to avoid core affinity and better CPU utilisation.

Answer 2:

The problem is that, your action waits for completion of the task. Don’t make it wait and return as soon as you start the task.

[HttpPost]
public void EmailReport()
{
   // for testing - sleep for 10 seconds
   var myTask = Task.Delay(TimeSpan.FromSeconds(10));
   myTask.Start();
}

Your request is cancelled because it is a page redirect request and old page redirect requests are cancelled when a new one is issued (e.g. when you click a link 2 times, first click is ignored). It is the way browsers implement it. It is not related with the root of your problem.

Answer 3:

Use background process

[HttpPost]
public JsonResult EmailReport()
{
    Thread email= new Thread(delegate ()
   {
          generatereports();
   });
   email.IsBackground = true;
   email.Start();
   return null; 
}

Answer 4:

it seems Navigator.sendBeacon() api will serve your purpose. it is used to asynchronously transfer a small amount of data over HTTP to a web server. though this is an experimental technology, supported in Chrome 39+, Firefox 31+, opera 26+, there is a polyfill for other browsers.

References

Loading...

Magento 2 – Reload totals cart after ajax change quantity

Loading...

Magento 2 – Reload totals cart after ajax change quantity

I want to use ajax to change the quantity of one item on the cart magento 2 cart page.
I have added this javascript:
$('.cart.item .qty').on({
    change: function() {
        var post_url = $(this).attr('data-post-url');

        $.post(post_url, $(this).serialize(), function(data) {
            $(".form-cart").replaceWith(data.cart_html);
            $("#cart-totals").replaceWith(data.totals_html);
            $("#cart-totals").trigger('contentUpdated');
        }, "json");
    }
});

The value of data.totals_html is 
When I change the quantity, the total component content is not refresh.. Anyone have an idea for dynamically update the total component after replace the html code?

Solutions/Answers:

Answer 1:

Reload totals cart after ajax change quantity

  1. Step

In your custom them create ( Magento_Theme/layout/checkout_cart_index.xml )

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
    <referenceContainer name="content">
        <block class="Magento\Framework\View\Element\Template" name="cart.ajax.qty.update"  template="Magento_Theme::js.phtml" after="-"/>
    </referenceContainer>
</body>

2.Step

creat js.phtml file ( Magento_Theme/templates/js.phtml )

<script>
require ([
        'jquery',
    ],
    function ($) {
       $(window).on("load", function () {
            require([
                'custom'
            ]);
        });
    });

3. Step
create custom.js file in theme web folder ( Namespace/Yourtheme/web/js/custom.js )

    define([
    'jquery',
    'Magento_Checkout/js/action/get-totals',
    'Magento_Customer/js/customer-data'
     ], function ($, getTotalsAction, customerData) {

    $(document).ready(function(){
    $(document).on('change', 'input[name$="[qty]"]', function(){
        var form = $('form#form-validate');
        $.ajax({
            url: form.attr('action'),
            data: form.serialize(),
            showLoader: true,
            success: function (res) {
                var parsedResponse = $.parseHTML(res);
                var result = $(parsedResponse).find("#form-validate");
                var sections = ['cart'];

                $("#form-validate").replaceWith(result);

                // The mini cart reloading
                customerData.reload(sections, true);

                // The totals summary block reloading
                var deferred = $.Deferred();
                getTotalsAction([], deferred);
            },
            error: function (xhr, status, error) {
                var err = eval("(" + xhr.responseText + ")");
                console.log(err.Message);
            }
        });
       });
      });
    });

4.Step ( map your js file )

Create requirejs-config.js on your theme root ( Namespace/yourtheme/requirejs-config.js)

var config = {
   map: {
    '*': {
        custom:'js/custom'
    }
  }
};

Now the qty update work using ajax
If have any issue ask in comment.

Answer 2:

You can consult this way to ajax re-load block totals in cart:

define([
    "jquery",
    'Magento_Checkout/js/action/get-payment-information',
    'Magento_Checkout/js/model/totals'
], function($, getPaymentInformationAction, totals) {
    $('.cart.item .qty').on({
        change: function() {
            var post_url = $(this).attr('data-post-url');
            $.post(post_url, $(this).serialize(), function(data) {
                //custom your update
                $(".form-cart").replaceWith(data.cart_html);
                $("#cart-totals").replaceWith(data.totals_html);
                //reload block total
                var deferred = $.Deferred();
                totals.isLoading(true);
                getPaymentInformationAction(deferred);
                $.when(deferred).done(function() {
                    totals.isLoading(false);
                });
                //end
            }, "json");
        }
    });
});

Answer 3:

Just run the following js code –

require(
[
   'Magento_Checkout/js/model/quote',
   'Magento_Checkout/js/model/cart/totals-processor/default'
],
function(
   quote,
   totalsDefaultProvider
) {
     totalsDefaultProvider.estimateTotals(quote.shippingAddress());
  }
);

For more information, please refer to this article.

Disclaimer: I am the CEO of MexBS (The company who published this article)

Answer 4:

Change the code in cartQtyUpdate.js to this one

define([
'jquery',
'Magento_Checkout/js/action/get-totals',
'Magento_Customer/js/customer-data'
], function ($, getTotalsAction, customerData) {

$(document).ready(function(){
    $(document).on('change', 'input[name$="[qty]"]', function(){
        var form = $('form#form-validate');
        $.ajax({
            url: form.attr('action'),
            data: form.serialize(),
            showLoader: true,
            success: function (res) {
                var parsedResponse = $.parseHTML(res);
                var result = $(parsedResponse).find("#form-validate");
                var sections = ['cart'];

                $("#form-validate").replaceWith(result);

                /* Minicart reloading */
                customerData.reload(sections, true);

                /* Totals summary reloading */
                var deferred = $.Deferred();
                getTotalsAction([], deferred);
            },
            error: function (xhr, status, error) {
                var err = eval("(" + xhr.responseText + ")");
                console.log(err.Message);
            }
        });
    });
    $(document).on('click', '.alo_qty', function() {
        var form = $('form#form-validate');
        $.ajax({
            url: form.attr('action'),
            data: form.serialize(),
            showLoader: true,
            success: function (res) {
                var parsedResponse = $.parseHTML(res);
                var result = $(parsedResponse).find("#form-validate");
                var sections = ['cart'];

                $("#form-validate").replaceWith(result);

                /* Minicart reloading */
                customerData.reload(sections, true);

                /* Totals summary reloading */
                var deferred = $.Deferred();
                getTotalsAction([], deferred);
            },
            error: function (xhr, status, error) {
                var err = eval("(" + xhr.responseText + ")");
                console.log(err.Message);
            }
        });
    });
});
});

now it works well

References

Loading...