Calling function from handling click event issue
Hi Everyone
Using the UJS approach Chis showed in the NavBar notifications screencasts, I'm trying to implement something similar, and having very strange issue that I can't even imagine what's the reason of.
Here is the thing. When loading page I'm doing setup to get json data from controller and put it in the content:
setup: -> (
$.ajax(
url: "/show_proposals"
dataType: "JSON"
method: "GET"
success: @showProposals
);
);
Then in @showProposals I'm generating elements and references to listen them:
showProposals: (data) => (
proposers = $.map data.proposers, (proposer) ->
"<li><a href='#' data-url='#{proposer.url}' data-behavior='proposal-link'>#{proposer.name}</a></li>"
$("[data-behavior='show-proposers']").append(proposers)
);
So now I need to handle 'proposal-link' click to send ajax request to the same controller, but with some different options, render new json file and perform @showProposals again. This is how I do that (as well in the "setup" function):
$(document).on 'click', "[data-behavior='proposal-link']", (event) -> (
event.preventDefault()
link = $(this).data("url")
$.ajax(
url: link
dataType: "JSON"
method: "GET"
success: @showProposals
)
);
And this is where the strange things happening. The link is generated correctly, request sent, right json file rendered and ajax return success (checked with placing alert on ajax success). But however I try, it DOES NOT call @showProposals again. And I can't find any reasonable explanation why is it happening.
One more strange thing. When I'm placing alert to ajax success, first it's showing alert, and only after rendering json file. But maybe this is fine.
Do you have any ideas? Thank you in advance!
Hmmm, not quite sure I'm following so let's see if this describes your problem: are you having trouble getting your on click function to fire because you're dynamically inserting those and the jQuery function isn't firing them?
Not exactly. On click function seems to be working, it is sending alerts and successful ajax requests. The function (@showProposals) that should be called from handling click isn't being fired from ajax:success, despite that it worked the same way in setup function.
But I assume that you are right about origin of the problem: that I'm handling click on dynamically rendered element, and trying to call the function to re-render this elements.
Oh, actually what it might be then, is that your scopes are a bit different in the second case.
While in the first one, you're inside the object and you have showProposals in the same scope, the second one is executing inside a click callback, so it may not actually have access to showProposals. You might try changing the on click handler to also use the thick arrow there =>
if it's also defined inside the object.
Could be the problem, also very possible it's not either. :)
Good! It seems to have the problem solved!
Only one issue appeared, probably I just miss something in syntax. Now I'm not succeeding in getting data-url from the element (although url is inserted in element's data-url correctly). I'm doing it this way. Is something wrong here?
$(document).on 'click', "[data-behavior='proposal-link']", (event) => (
event.preventDefault()
link = $(this).data("url")
alert link
$.ajax(
url: link
dataType: "JSON"
method: "GET"
success: @showProposals
)
);
Right, and that would be because now that you changed scopes, the this
variable references the JS object now instead of the element in the callback. Scopes in JS are quite tricky huh?
Solution now would be to use the event.target
from the argument the callback receives. That'll be the link that was clicked, and you can then replace this
with that in order to accomplish the same thing.
Can you please help me implement this approach into my code? I barely understood half of your proposal. :))
My bad :) Should have given an example.
link = $(event.target).data("url")
Replacing that line with the above code should do it. The event
argument contains all the data about the event, including the link that was clicked. That's the target
attribute. You can then just access that like the above and everything is nicely scoped.
Thank you, Chris, it is working! And thank you for pointing me that it is necessary to find out what is JS scopes, which appeared to be very useful information. :)