您的位置:首页 > Web前端 > JavaScript

Rails 用 RJS 简单有效的实现页面局部刷新

2016-07-16 15:43 495 查看
我们时常在做项目的时候会遇到这样的需求,页面上有个基本数据的下拉框,用于选择一些数据,如:项目版本号、联系人、收件地址、银行账号列表什么的。而需求可能会要求说可以在这个页面随时增加那些下拉框的选择值,而不是另开窗口。于是我们可能需要实现一个浮动窗口,里面包含新增表单,实现表单 AJAX 提交,最后在刷新主窗口的下拉菜单控件。

这里介绍一下我最近实现的一个简单方式:

主表单页面:用 link_to + remote 的方式实现一个Ajax 请求的点击
<div class="form-field-user-address">
<%= f.select :address, collection: current_user.addresses %>
</div>
<%= link_to '新增联系地址', new_address_path, remote: true %>
AddressesController 保持标准的 Rails new 函数结构
class AddressesController < ApplicationController
def new
@address = Address.new
end

def create
@address = Address.new(address_params)
respond_to do |format|
if @address.save
format.html { redirect_to addresses_path, notice: '地址新增成功。' }
format.js
else
format.html { render :new }
format.js
end
end
end
end
新增 
new.js.erb
 (以后会大量用js.erb 的做法),由于前面是 remote 请求,HTTP Header 里面带的信息会让 Rails 渲染 js.erb 的模板这里渲染 
_form.html.erb
 生成地址表单的HTML:
var html = "<%= j(render('form', remote: true)) %>";
// bootbox 弹窗插件 http://bootboxjs.com/ bootbox.dialog({
title<
e929
/span>: "新增联系地址",
message: html
});
然后我们就得到了这样的界面:

然后正题来了,我们怎样才能在地址新增成功以后,以无刷新的方式更新主表单上面那个下拉框呢?

这就是本帖要将的技巧,非常简单,而且适用于任何地方!我们新增一个 
create.js.erb
,前面说过remote 的请求,Rails 会选择 js.erb 的模板来渲染
<% if @address.errors.blank? %>
// 用 Ajax 载入当前页面,找到下拉框的 Dom 的新 HTML,再替换目前页面的下拉框 Dom
var selector = '.form-field-user-address';
$.get(location.href, function(html) {
var doc = $(html).find(selector);
$(selector).replaceWith(doc);
});
bootbox.hideAll();
<% else %>
var html = "<%= j(render('form', remote: true)) %>";
// 保存失败,直接替换浮动窗口上面的 HTML 为新的 form render 结果
// 因为 @address 包含验证错误信息,所以 render 出来的 HTML 也包含验证信息
$('form.new_address').replaceWith(html);
<% end %>
为了很多地方都能用到,于是我把上面的变成一个公共函数:
app.coffee
window.App =
refreshDom: (selector) ->
$.get location.href, (html) ->
doc = $(html).find(selector)
$(selector).replaceWith(doc)
create.js.erb
 就可以简化了:
<% if @address.errors.blank? %>
App.refreshDom('.form-field-user-address');
bootbox.hideAll();
<% else %>
var html = "<%= j(render('form', remote: true)) %>";
$('form.new_address').replaceWith(html);
<% end %>
js.erb 里的脚本是直接 eval 跑的,所以里面声明的变量会变成 全局变量 ,所以任何 js.erb 最好加上闭包。CoffeeScript 貌似不用管这个问题,因为默认生成的 JavaScript 就是有闭包的。
你说的闭包指的是命名空间吗
 也许没表达清楚,就是建一个匿名函数表达式去封装一下:
(function() {// Your code})();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: