Thursday, September 3, 2009

JQuery on Rails

I am starting to test out JQuery on Rails and see if i can reproduce the same result of what i did back then with the Rails bundled Prototype helpers.

in rjs, (js.rjs)

page.replace_html "widget-count-#{@post.id}", :partial => 'widget_count', :locals => {:post => @post}
page.replace "widget-button-#{@post.id}", image_tag('wiggy.png')

in jquery, (js.erb)

$("#widget-count-<%= @post.id %>").replaceWith
('<%= escape_javascript(render(:partial => 'widget_count', :locals => {:post => @post} ))%>');
$("#widget-button-<%= @post.id %>").replaceWith
('<%= image_tag('wiggy.png') %>');


in addition to that, if you are using JQuery, do not forget to import that JQuery javascript file.

However, if you are dealing with ajax request... there is something extra you need to do. Based on RyanB's railscast at http://railscasts.com/episodes/136-jquery,

in application.js

#to request for js format by default instead of html if you have both respond_to |format|

jQuery.ajaxSetup({
'beforeSend' : function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})


#Changing the behavior of the form, note the form id "new_comment" to submit an ajax request

$(document).ready(function(){
$("#new_comment").submit(function(){
$.post($(this).attr("action"), $(this).serialize(), null, "script");
return false
})
})


JQuery.js has to be loaded first before application.js in order to get it work.

Then for the appearance of the comment in an ajax manner,

in rjs, (js.rjs)

if @comment.save
page.insert_html :top,"comments", :partial => 'comment'


in jquery, (js.erb)

<% if @comment.save %>
$("#comments").prepend("<%= escape_javascript(render :partial => 'comment') %>")
<% end %>


Finally if you intend to use JQuery with other Javascript libraries, Prototype for example, bear in mind the need to declare noconflict. http://docs.jquery.com/Using_jQuery_with_Other_Libraries

One of the example to prevent conflict between JQuery and Prototype is by,

Add this right after the libraries are loaded. Perhaps in application.js

jQuery.noConflict();

Then anytime you intend to use JQuery libraries wrap the JQuery codes inside the jQuery(document).ready(function($){ #jquery codes }) as such,

jQuery(document).ready(function($){
<% if @comment.save %>
$("#comments").prepend("<%= escape_javascript(render :partial => 'comment') %>");
<% else %>
alert('NO!');
<% end %>
})


The $(element) codes without wrapping into jQuery will be treated as Prototype and the score is settled.