views:

102

answers:

5

I like the idea of separating functionality and this seems like the way of the future.

But I'm used to integrating javascript inside loops in an embedded language like Rails ERB or PHP, where I can use the ID of a particular object as a reference in the javascript.

Rails example:

<% @comments.each do |comment| %>
  <div id="comment_<%= comment.id %>">
    <%= comment.text %>
    <% link_to_function "Reply", "$('comment_#{comment.id}').insert(\"#{escape_javascript(render :partial => "_form", :locals => {:comment => comment})}\", {position: 'bottom'});" %>
  </div>
<% end %>

This isn't the only time I've ended up wanting to use Ruby methods inside javascript either. I may want to use constants, or call other ruby methods on an object inside a loop user.enabled? or user.full_name, or render partials with those objects, etc.

So how is this supposed to be accomplished if all the javascript is in another file or outside the loop? I get that you can iterate through a bunch of divs in javascript using CSS selectors, but this doesn't allow me to call ruby methods on objects.

What am I missing? Thanks!

+2  A: 

I think it shold be done with "data-id" parameter as shown in this screencast http://railscasts.com/episodes/229-polling-for-changes

grigio
Love this answer.
jessegavin
Yep this is what I was looking for, HTML 5 data- attributes. Thanks! Something about this strategy still bugs me a little bit (it adds another step between rails and javascript parameters, one more place to mess up). Also, does it make sense to place an entire rendered partial in a data- attribute? I guess you could, just seems strange.
Brian Armstrong
A: 

Pardon me for using jquery, but web development really sucks without it or similar library

For your first complaint (get current comment), javascript this works fine for me.

onclick="my_function(this);"

and in js file

my_function = function(target) {
    // clicked element passed in
    // now, let's get comment element by class
    var comment = $(target).parents('.comment');
}

As for second complaint... I never needed it often, but sometimes I include pieces of data in html for use by javascript. Extending previous example:

<div class="comment" comment_id="<%= comment.id %>"></div>

And in my_function

var comment_id = comment.attr('comment_id');
Nikita Rybak
+1  A: 

For your particular example you already have the comment ID encoded within the markup because you set the ID attribute of the div element to the comment ID. So you can hang the JavaScript off that.

John Topley
Makes sense, I can get the id. But I'd still be unable to generate text in there from ruby methods right?
Brian Armstrong
A: 

Make your client-side script take an 'options' object as a parameter. Don't use any server-side scripting; put the script in its own .js file.

Then create the 'options' object with a server-side script which outputs js. Include your script and call its entry-point function, passing in your 'options' object.

no
A: 

You just need some more JavaScript knowledge to see power of it, especially jQuery. Your example I would solve like:

<% @comments.each do |comment| %>
  <div class="comment">
    <%= comment.text %>
    <a href="reply.php?id=<%= comment.id %>" class="reply">Reply</a>
  </div>
<% end %>
<script type="text/javascript">
  $('.comment .reply').click(function(e) {
    e.preventDefault();
    var url = $(this).attr('href');
    var result = url.match(/\?id=(\d+)([^\d]|$)/);
    var id = (result && result[1]);
    if (id) {
      // do whatever you want to do with the id
    }
  });
</script>

Benefits:

(1) You don't have javascript all over the place

(2) Works without javascript

sod
This allows you to get the id in javascript, but you still can't call Ruby methods on an object inside the javascript to generate text.
Brian Armstrong