ajax:success and ajax:complete callback doesn't work when using UJS in Rails
Asked Answered
S

4

5

I have a link that when i click on it will trigger an ajax call then replace this link by another link, says for example the original link is "add friend", when i click this link it will send an ajax request to add_friend action then if the friend is added the link above will be replaced by another link "cancel request", i use ujs for that :

$("#link_for_friend").html("<%= escape_javascript(render('users/cancel_link')) %>")

when i try to add callback (:success and :complete) it doesn't works, i tried with :beforeSend like the following it works :

$(document).ready ->
  $("#my_link").on "ajax:beforeSend", ->
    alert("hello")

there is a solution for success and complete callback ?

note : my idea is to show an loader.gif when ajaxStart is triggered then hide it when ajax:complete callback is triggered at least , also if there is some error i want to show it when ajax:error is triggered

Update

I tried to solve this by moving the code inside action.js.erb to js file like this :

  $(document).ready ->
  $(document).on("ajax:success", "a.invitation-box", ->
    $("#link_for_friend").html("<%= escape_javascript(render('users/cancel_link')) %>")
  ).on "ajax:error", "a.invitation-box", ->
    alert "error"

but this way its not possible to put render('users/cancel_link') inside a JS file

Sculpin answered 15/10, 2013 at 15:8 Comment(4)
if the ajax request isn't being sent by jQuery, global ajax handlers will not be triggered by it.Camber
do you means that there is no way to do this with ujsSculpin
Not with jQuery's gobal methods, if ujs isn't using jquery to do the ajax request. I don't know what ujs is, but i'm assuming it doesn't use jquery to do anything, as that would add a dependancy that isn't needed for what ujs does. Have you looked into ujs to see if it has any hooks that you can use to perform an action before and after it happens?Camber
@KevinB ujs == Unobtrusive JavaScript, rails use jquery-rails and ujs to make ajax request very easy, the problem here, using ajax with jquery work fineSculpin
T
8

I had the same issue, and the problem is not with ajax:success or ajax:complete callback. The problem is that when displaying the loading gif image, you replace the content of the container, including the link itself. So the element on which you apply the success, complete callback is not part of the DOM anymore, that's why the callback is not fired.

One solution would be to hide the element and append the loading image, like following:

$('#my_link').on "ajax:send", (event, xhr, settings) ->
        $('#my_link').hide()
        $("#my_link_container").append("<image src = 'img.gif' />")

Then the success and complete callback will be fired. Hope it helps somebody :)

Thermel answered 22/3, 2014 at 12:25 Comment(2)
hi @Thermel you are right in what you say, but i solved this problem with another (clean) method, i don't remember how exactly but if you want i can do some research then i tell u, i accept your answer ^^ thank you for the answerSculpin
This was such a life saver!Fairman
E
3

I believe your problem is down to JS not being able to bind to your object, as it's been changed. The way JS works is to "bind" / "attach" itself to elements in the DOM (Document Object Model). The DOM is basically a huge list of elements JS uses to call certain functions, and thus allows you to allocate various functions to those elements. That's how you can call "click" functions on different elements.

You're basically replacing the object that you've called the Ajax from, so when 'ajax:success' happens, JS has no way to know which object to associate it with, thus preventing the function from firing

The way to get around this is to bind to the document, and then delegate the bind to your div, like this:

$(document).on 'ajax:success' , '#my_link', ->
  //do stuff here

This means that even if this element changes dynamically, it will still have the function bound to it, thus giving you what you need :)

Eldoraeldorado answered 15/10, 2013 at 15:48 Comment(6)
'ajax:success' won't works, if i do 'ajaxSuccess' instead it works (but without '#my_link' as second argument), if i add '#my_link' as second argument doesn't workSculpin
even if you change to #link_for_friend?Eldoraeldorado
I still feel that my answer holds at least some merit, but I guess there may be some other parts which would be cool to know about :) A great resource on this is here: alfajango.com/blog/rails-3-remote-links-and-formsEldoraeldorado
#link_for_friend is the div parent of the link, also if i changed this it doesn't work :(Sculpin
lol the plot thickens!!!! Do you want to jump into chat? It would be good to talk it throughEldoraeldorado
let us continue this discussion in chatEldoraeldorado
U
2

Try this in your action.js.erb:

setTimeout(function () {
  ("#link_for_friend").html("<%= escape_javascript(render('users/cancel_link')) %>")
});

This will put the html replacement to the next timer tick that happens after the ajax:* events being triggered.

Uziel answered 9/7, 2014 at 7:36 Comment(0)
I
1

I met this problem before, UJS's ajax:success and ajax:complete won't be fired. But other callbacks work, such as ajax:beforeSend

My fix is to use jQuery's global event callback to handle it

$("#my_link").on('ajaxComplete', (evt, data, status, xhr) ->
  alert('This is a jQuery ajax complete event!')

P.S. UJS use jQuery's ajax to send Ajax, so jQuery's callback will surely be fired.

# https://github.com/rails/jquery-ujs/blob/master/src/rails.js
ajax: function(options) {
  return $.ajax(options);
},
Inflection answered 15/10, 2013 at 15:19 Comment(5)
Try watching on higher level div.Inflection
do you means the parent div of #my_link, if so i tried with $("#parent-div").on "ajaxComplete"... but still not workSculpin
It seems you need to add arguments, check my update. Also, I remember it may only be fired at document level but not sure now. So if still not working, try $(document).on....Inflection
i added arguments but doesn't works , i tried with $(document).. and it works like a charm :) but what is the reason (is this a good practice) ? i found here the same issue github.com/rails/jquery-ujs/issues/223 but can't understand well the solution thereSculpin
The limitation is you can't do specific things on this element sending ajax request, but I had not went on to figure out more. Check Rich Peck's answer, if that works it's better.Inflection

© 2022 - 2024 — McMap. All rights reserved.