Getting jQuery timeago plugin to recognize recently loaded DOM elements

I use jquery timeago in my Rails 3 application. I have a comment section about my posts # show view, which is automatically updated every 30 seconds by the AJAX used in Railscasts, episode # 229 "Poll for changes" , Partially part of the components downloaded by jQuery , contain the created_at comment time, which uses the timeago Rails helper method to create attr tags with the correct time format.

When a comment is submitted and ajax loads the comment, the new comment DOM element is not recognized by the jQuery timeago plugin. Therefore, instead of displaying the comment time as “about a minute ago”, “2010-11-21 23:08:36 UTC” is displayed.

I studied this problem, of course, and found suggestions regarding using .live (),. Delegate () or the livequery plugin.

comments / index.js.erb:

<% unless @comments.empty? %> $("#comments").append("<%=raw escape_javascript(render(@comments)) %>").timeago(); <% end %> 

comments / show.js.erb:

 $("#comments").append("<%=raw escape_javascript(render(@comments)) %>"); 

public / javascripts / application.js:

 $(function() { if ($("#comments").length > 0) { setTimeout(updateComments, 30000); } }); function updateComments () { var post_id = $("#post").attr("data-id"); if ($("#comments").length > 0) { var after = $(".comment:last-child").attr("data-time"); } else { var after = "0"; } $.getScript("/posts/" + post_id + "/comments?after=" + after) setTimeout(updateComments, 30000); } 

helpers / application_help.rb:

 module ApplicationHelper def timeago(time, options = {}) options[:class] ||= "timeago" content_tag(:abbr, time.to_s, options.merge(:title => time.getutc.iso8601)) if time end end 

Layouts / application.html.erb:

 <!DOCTYPE html> <html> <head> <%= stylesheet_link_tag 'style' %> <%= javascript_include_tag :defaults %> <%= javascript_include_tag 'jquery.timeago' %> <%= csrf_meta_tag %> </head> <body> <!-- ... --> <script type="text/javascript"> $("abbr.timeago").timeago(); </script> </body> </html> 

comments / _comment.html.erb:

 <div class="comment" data-time="<%= comment.created_at.to_i %>"> <%- if comment.commenter.empty? -%> <%- else -%> <span class="name"> <%- if comment.email.blank? -%> <%= comment.commenter %>: <%- else -%> <a href="mailto:<%= comment.email %>"><%= comment.commenter %>:</a> <%- end -%> </span> <%- end -%> <%= simple_format @comment.body %> <span class="time"> <%= timeago(comment.created_at) %> </span> </div> 

posts / show.html.erb:

 <div id="post" data-id="<%= @post.id %>"> <%= link_to @post.title, @post %> <%= simple_format @post.content %> <% unless @post.comments.empty? %> <div id="comments"> <%= render @post.comments %> </div> <% end %> </div> <div id="replyform"> <%= render "comments/form" %> </div> 

The functionality of the AJAX and timeago plugins works great everywhere only when I make a comment, and this comment appears with AJAX from another browser in which I encountered this problem. Any suggestions, resources or code will make my week. Thanks for reading my post.

+4
source share
2 answers

Your code calls $("abbr.timeago").timeago(); in the script block in the application template. This is done when the page loads for the first time and allows you to use the timeago function to match the elements that currently exist. Any matching nodes that are added dynamically later — for example, your AJAX partially — do not receive timeago functionality.

One option is to call $("abbr.timeago").timeago() after adding dynamic content. However, it can be difficult to track and remember to do when you add new features, so I use the livequery plugin . Include a livequery script in your page and replace $("abbr.timeago").timeago(); to the following:

 $("abbr.timeago").livequery(function () { $(this).timeago(); }); 

This allows you to use timeago for any matching nodes and dynamically add the corresponding nodes.

+13
source

Once load() completed its task, ajaxComplete() called. I would recommend creating a function called ready_or_not() :

 $(document).ready(function(){ ready_or_not(); }); $(document).ajaxComplete(function(){ ready_or_not(); }); function ready_or_not(){ $(".timeago").timeago(); } 

There may be certain code that you want to use only if the document is ready, or when Ajax is complete. But for both, enable it inside the ready_or_not() function.

+3
source

All Articles