Search code examples
ruby-on-railsrubyruby-on-rails-4ujs

Rails UJS: abort previously triggered but still active ajax requests when triggering a new ajax request


I have a Ruby on Rails 4.2 app.

I have 3 buttons that trigger ajax requests with Rails UJS

<section id="buttons"> 
  <%= link_to image_tag(image),
        button1_modal_path,
        remote: true, 
        id:"icon1",
        data: { disable_with: '' } %>
  <%= link_to image_tag(image),
        button2_modal_path,
        remote: true, 
        id:"icon2",
        data: { disable_with: '' } %>
  <%= link_to image_tag(image),
        button3_modal_path,
        remote: true, 
        id:"icon3",
        data: { disable_with: '' } %>
</section>

I wish to implement the following pattern:

  • user clicks on button 1 launching a ajx xhr request (let(s call it ajaxRequest1)

  • the ajax is still being processed (and whatever state it is on : sent, already dealt with by server, on itw way back...) but has not arrived (200) and user clicks on button 2 triggering another xhr ajax request (ajaxRequest2)

  • I would like in that case that all other active ajax requests (that is to say in this case ajaxRequest1) are canceled. If there was more than only one more requests, it would cancel them all except the last ajax request (that is to say ajaxRequest2)

I tried this using Rails UJS ajax events but it does not work (it actually cancels ANY ajax request to be triggered:(:

on('ajax:beforeSend',function(event, xhr, settings){
  xhr.onreadystatechange = null;
  xhr.abort();
}

NOTE: I would like in the best case that I don't only cancel the fact the browser is waiting the ajax request return and display its content but ALSO that if the request has been launched but not yet hit the server, it is canceled before it does hit the server, in order not to overload the server with useless ajax request.


Solution

  • If only one rails remote call should run at any time, you can remember the current XHR and abort it when a new one starts, i.e.

    var currentXhr;
    currentXhr = null;
    
    $(document).on('ajax:send', function(_event, xhr) {
      if (currentXhr) {
        currentXhr.abort();
      }
      currentXhr = xhr;
      return true;
    });
    $(document).on('ajax:complete', function(_event, _xhr, _status) {
      currentXhr = null;
    });