Log onclick events from dynamically created div array? Rails + jQuery?

After it was not possible to achieve this using link_to remote, I decided to try jQuery. Here is the jQuery loop and rails loop and how they interact. The problem is that I only get click registration on one of the divs from each loop, so the thing is not working. Here is the code:

<% @node.parent_relation.videos.each_with_index do |vid, idx| %> <%= image_tag("http://img.youtube.com/vi/#{vid.content}/1.jpg", :id => "img_div_#{idx}") %> <div id="vid_vid_<%=idx%>" style="display: none"> <%= vid.id %></div> <% end %> <script> var ids = "<%= @node.parent_relation.videos.length %>"; var div_arr = []; var img_arr = []; var vid_id = 0; for( i=0; i < parseInt(ids); i++){ var x = String("vid_vid_"+String(i)); var y = String("img_div_"+String(i)); div_arr.push(x); img_arr.push(y); } for ( i=0; i < parseInt(ids); i++){ var vst = '#'+String(img_arr[i]); var dst = '#'+String(div_arr[i]); $(function() { $(vst).click(function(){ var vid_id = $(dst).html(); console.log(vid_id); $.post("/nodes/iframize/", {video_id: vid_id}); }); }) } </script> 

And there is an iframize action in the node controller and js.erb that updates the div from response_to format.js in this action, this part works.

Thank you very much, any advice is greatly appreciated.

0
source share
2 answers

It seems like the problem is that all your handlers share the dst variable. You can use the http://api.jquery.com/event.data/ option so that you do not rely on shared closure variables. The option suggested by JasonWoof also works, you can choose what seems easier to you.

 for ( i=0; i < parseInt(ids); i++){ var vst = '#'+String(img_arr[i]); var dst = '#'+String(div_arr[i]); $(function() { $(vst).click({dst: dst}, function(event){ var vid_id = $(event.data.dst).html(); console.log(vid_id); $.post("/nodes/iframize/", {video_id: vid_id}); }); }) } 

Additional information for your code.

  • No need to end calls in $(function(){}) in a loop. At the top level, there should be only one call to $(function(){}) .
  • You do not need to use String() , it just clutters the code, JavaScript does the coercion for you.
  • Do not create global variables (your i variable in a loop)
  • You do not need two loops or two arrays you created, all this can be done much more clearly.

Here I suggest replacing the script with

 $(function() { var ids = "<%= @node.parent_relation.videos.length %>"; for( var i=0; i < ids; i++){ $("img_div_"+i).click({dst: $("vid_vid_" + i)}, function() { $.post("/nodes/iframize/", {video_id: event.data.dst.html()}); }); } }); 
+2
source

The problem is that dst and vst are changing in your loop. Therefore, when your click handler is running, it uses the final versions of dst and vst, not the values ​​that they had when creating the click handler.

You need a copy of dst and vst, which you can make by creating a new context. Example

 function make_handler(vst, dst) { $(vst).click(function(){ var vid_id = $(dst).html(); console.log(vid_id); $.post("/nodes/iframize/", {video_id: vid_id}); }); } $(function() { for ( i=0; i < parseInt(ids); i++){ var vst = '#'+String(img_arr[i]); var dst = '#'+String(div_arr[i]); make_handler(vst, dst); } }); 

You can do this inline, but you need a function that takes vst and dst as arguments because they are copied and the context is preserved when the callback occurs.

Edit: by "do inline" I mean replacing the call to make_handler () as follows:

  function(vst,dst) { ... } (vst, dst); 
0
source

Source: https://habr.com/ru/post/912266/


All Articles