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})();
相关文章推荐
- JSP中使用<c:forEach>标签循环遍历元素
- js交互
- JavaScript的作用域链
- js canvas实现擦除动画
- 【JavaScript】面向对象与原型
- 项目:微空间
- JS之常用互动方法
- JavaScript实现图片轮播和鼠标悬停显示
- JavaScript给网页添加水印
- 高性能js之数据访问性能
- JavaScript中对象的含义与this的指向
- swing组件之JScrollPane滚动条
- JavaScript学习笔记 - 进阶篇(8)- DOM对象,控制HTML元素
- JavaScript学习笔记 - 进阶篇(7)- 浏览器对象
- JavaScript学习笔记 - 进阶篇(6)- JavaScript内置对象
- JavaScript学习笔记 - 进阶篇(5)- 事件响应
- JavaScript学习笔记 - 进阶篇(4)- 函数
- JavaScript学习笔记 - 进阶篇(3)- 流程控制语句
- JavaScript学习笔记 - 进阶篇(2)- 数组
- JavaScript学习笔记 - 进阶篇(1)- JS基础语法