jQuery

在第43个railscast, 我们介绍了如何通过ajax来更新页面的多个元素,我们使用了Prototype libraries 和 form_remote_for 来提交AJAX请求, 和使用RJS模板生成javascript作为response,返回给浏览器,更新这些元素。

在本节中,我们将使用jQuery, 而不是Prototype 和 RJS, 来做同样的事情。

既然使用jQuery,我们就不能够再使用rails提供的RJS或者任何的辅助方法如form_remote_for了。
如果我们仍然想使用RJS,那么就要安装一个plugin叫做jRails的。
这个plugin将会rewrite那些 与jQuery 协同工作的方法, 但是这里我们只会单独使用jQuery, 因为 它可以使我们javascript更隐蔽,在页面看不出来,增强我们的rails应用的安全性。

继续以前面的程序为例,我们的页面显示了一个产品,并且允许用户添加评论,当一个新的评论被添加,他会显示在review的列表中,那个显示有几条评论的数字会被更新,form会被reset,并且会有一个flash。

当前的处理方式是浏览器提交post请求,然后重新载入这个页面,我们将要写一些jQuery代码,来让form把他的数据通过AJAX请求传送到服务器,然后在不用reload的前提下更新当前页面。


{========================================================>
map.resources :product, :has_many => :reviews
将生成很多的路径,例如/product/1/reviews/create etc.
========================================================>}



2. 添加jQuery到我们的程序:
第一件要做的事情就是添加 jQuery库到我们程序,可以从jQuery网站下载,下载之后,把它放到public/javascripts 目录下, 然后,我们要在layout 页面中添加对这个库的引用(在header 部分)

  <%= javascript_include_tag ['jquery-1.3.2', 'application'] %> 

每一个jQuery的版本包含两个版本,一个开发版和一个精简版,最好使用开发版,因为他会使得调试比较容易。 除了引用jquery库,还要引用application.js 库, 因为我们的jQuery代码会被放到application.js中。 不过jquery的引用要在前面,要保证application.js 被load之前, jquery已经load进来了。




3. 添加隐蔽的javascript
为了使我们的javascript更隐蔽,我们不希望修改view代码,而是通过jQuery动态的修改页面的元素行为, 我们首先写一个函数,这个函数在form被submit的时候将会执行。

我们的form含有一个new_review的id,下面的代码将会通过AJAX方式将这个id传给server。
$(document).ready(function(){
  $('#new_review').submit(function(){
    $.post($(this).attr('action'), $(this).serialize(), null, "script");
    return false;
  });
});


我们来分析一下上面的代码:
第一行创建一个函数,这个函数在document的对象模型被loaded完成后就会执行。

第二行通过我们的form的id找到form,然后也创建一个函数,这个函数在form被submit的时候就会执行。但是我们的form没有定义new_review的id啊,原来这也是rails的约定,form_for 生成的 html form的 id 就是 new_**** 呵呵

第三行创建一个AJAX请求,这个请求将会被提交到服务器,$.post 这个函数接受4个参数,第一个参数是url,也就是请求将会被提交到的url,这里我们赋给这个参数的值是form的action属性。
第二个参数是要提交的数据,在这里,我们使用了jQuery的serialize方法,这个方法将会人工将form的各个元素序列化为一序列的 key/value 对,供传送到server。
下一个参数是一个回调函数 callback function, 这个函数将会在AJAX请求完成后自动执行,这里我们用不到,所以置为null。
为什么我们用不到呢? 因为我们的第四个参数是“script”, 他告诉 $.post 函数,服务器将会返回一段javascript代码,这段代码应该白浏览器执行。

如果你关心$.post的更多的细节,请参考jQuery.com 的文档。

最后一行,我们return false, 目的是使默认的submit 行为不被触发。



4. 下面我们该修改reviews controller了,使得他能够同时处理html 和 javascript 两种请求。 当前,它保存这个新的review,然后重定向到product的show页面,对于javascript请求,不能使用redirect,我们将使用respond_to 来建立两种处理block。

def create
  @review = Review.create!(params[:review])
  flash[:notice] = "Thank you for your review"
  respond_to do |format|
    format.html {redirect_to @review.product}
    format.js
  end
end


为什么js block是空的呢?因为它只需要我们创建的javascript返回给浏览器,这写javascript存在与 create.js.erb中, (没有安装jRails插件,我们不能使用RJS模板)所以我们使用的js.erb文件。
下面我们首先加入一行简单的 alert 到create.js.erb 文件中。 检查一下我们的流程是否走通了。

alert("hello from AJAX")

我做到这一步的时候,已经成功了,但是不知道为什么原文中说还要有下面一步才能工作:
rails并不知道jQuery提交的请求想让他返回html还是javascript,我们得想办法告诉rails我们提交的是javascript请求,如何告诉呢?
第一种方法是,在$.post 方法的url参数中, 添加.js 后缀,这样rails就知道应该返回javascript了
第二种方法也是我们最推荐的方法,因为使用这种方法,适用于所有页面的jQuery请求,不需要重复了。 那就是往 application.js 文件中加入如下一行:
jQuery.ajaxSetup({
  'beforeSend': function(xhr){xhr.setRequestHeader("Accept", "text/javascript")}
})

这几行代码的意思是修改request的header中的Accept属性,告诉rails让他返回javascript。



5. 添加jQuery code,生成javascript代码,返回给浏览器执行。
我们下面就要用真实的jQuery code来替换stupid alert了。这些代码的作用更新浏览器的当前页面。
第一件事情是添加一个flash,我们将在form前添加一个div:
$('#new_review').before('<div id="flash_notice"><%= escape_javascript(flash.delete(:notice))</div>');

要添加动态的内容,方法是把erb tags嵌入到javascript中,使用escape_javascript是为了使得从erb输出的结果是安全的。而且我们还调用了flash.delete来马上清空flash,使得下次请求不会再次出现flash。


还需要更新有多少review那个数字,他的id是review_count, jQuery的html方法可以用来更改他的内容:
$('#reviews_count').html('<%= pluralize(@review.product.reviews.count, "Review")%>');

还要把新添加的review显示出来,每一review都是作为一个list的一个item通过partial来渲染的,要把新的review显示出来,我们需要使用新的review渲染partial,然后append到list上。
$('#reviews').append('<%=escape_javascript(render(:partial => @review))%>')


最后,还要reset form:
$('#new_review')[0].reset();
$ 是一个 jQuery 函数, 他会返回一个jQuery对象,他返回的只是一个jQuery对象,我们要得到实际的DOM元素的话,还需要指定他的数组的第一个元素。





6. 以上,我们都是使用jQuery现成的函数,下面我们演示如何定义你自己的函数:
$('#new_review').submit(function(){
    $.post($(this).attr('action'), $(this).serialize(), null, "script");
    return false;
  });

上面这段代码是提交AJAX请求,如果我们要在多个form使用这个函数,我们可以把这个功能抽象成一个jQuery函数,
$('#new_review').submitWithAjax();
而我们自己的函数定义如下:
jQuery.fn.submitWithAjax = function() {
  this.submit(function(){
    $.post($(this).attr('action'), $(this).serialize(),null,"script");
    return false;
  });
}

你可能感兴趣的:(JavaScript,jquery,Ajax,Flash,Rails)