动态嵌套form,使用Stimulus Js库(前后端不分离)
我的git代码:https://github.com/chentianwei411/nested_form-Stimulus-
Stimulus: https://www.cnblogs.com/chentianwei/p/9806875.html
开始:
rails new -m ../jumpstart,\ Gorails视频\(创建一个rails模版\)/template.rb -d postgresql nested_forms
rails webpacker:install:stimulus
在_header.html.erb内添加:
使用javascript_pack_tag方法添加JS pack到Rails views
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
然后修改文件名:
mv app/javascript/controllers/{hello.nested_form}_controller.js
创建手脚架和模型:
rails g scaffold Project name description
rails g model Task description project:belongs_to
rails db:migrate
产生:
create_table "projects", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end create_table "tasks", force: :cascade do |t|
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "project_id"
t.index ["project_id"], name: "index_tasks_on_project_id"
end
嵌套结构的类方法使用:
class Project < ApplicationRecord
has_many :tasks, inverse_of: :project
accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true
end
具体解释见博客:
ActiveRecord Nested Atrributes 关联记录,对嵌套属性进行CURD
Rails-Treasure chest2 嵌套表单;
controller内添加属性白名单:
def project_params
params.require(:project).permit(:name, :description, tasks_attributes: [:id, :description, :_destroy])
end
然后在view视图_form.html.erb上添加一个嵌套的form builder:
<h4>Tasks</h4> <%= form.fields_for :tasks do |task| %>
<div class="form-group">
<%= task.label :description %>
<%= task.text_field :description, class: 'form-control'%>
</div>
<% end %>
使用#fields_for(record_name, record_object = nil, &block),创建一个scope在一个指定的model对象如form_for,但是不创建自身的form tags。它用于在一个form内创建额外的model对象。(具体见api文档)
修改project_controller,添加语句@project.tasks.new。或者设置视图中的#fields_for方法的第2个参数record_object为Task.new
def new
@project = Project.new
@project.tasks.new
end
⚠️:重构视图,可以把fields_for方法的块block提取出来。_nest.html.erb
使用template标签,让JavaScript决定是否显示在页面。配合使用stimulus.js。
<template>
<%= form.fields_for :tasks, Task.new, child_index: 'New_RECORD' do |task| %>
<%= render 'nest', form: task%>
<% end %>
</template>
child_index: 'New_RECORD' 即子索引的名字,会在label,input标签的for,name, id属性上使用到:
<div class="form-group">
<label for="project_tasks_attributes_New_RECORD_description">Description</label>
<input class="form-control" type="text" name="project[tasks_attributes][New_RECORD][description]" id="project_tasks_attributes_New_RECORD_description">
</div>
视图的最终代码:
- data-controller调用js文件中的类对象实例化的对象
- data-target, 用于取对应元素。
- data-action,用于绑定事件。这里使用了link_to视图方法。
<div data-controller="nested-form">
<template data-target="nested-form.template">
<%= form.fields_for :tasks, Task.new, child_index: 'New_RECORD' do |task| %>
<%= render 'nest', form: task%>
<% end %>
</template> <%= form.fields_for :tasks do |task| %>
<%= render 'nest', form: task%>
<% end %> <div class="mb-3" data-target='nested-form.links'>
<%= link_to 'Add Task', '#', class: 'btn btn-outline-primary', data: {action: 'click->nested-form#add_association'} %>
</div>
</div>
nested_form_controller.rb
export default class extends Controller {
static targets = [ "links", "template" ]
connect() {
}
add_association(event) {
event.preventDefault()
var content = this.templateTarget.innerHTML.replace(/New_RECORD/g, new Date().getTime())
this.linksTargets.insertAdjacentHTML('beforebegin', content)
}
}
⚠️这里用到js库的2个方法replace和insertAdjacentHTML用于对元素内容操作和元素节点的插入。
视图上的最终代码:
<input class="form-control" type="text" name="project[tasks_attributes][1554196211709][description]" id="project_tasks_attributes_1554196211709_description">
功能:增加task,还可以删除task。
在_nest.html.erb表格内增加一个"Remove"连接按钮。
<%= content_tag :div, class:'nested-fields', data: {new_record: form.object.new_record?} do %>
<div class="form-group">
<%= form.label :description %>
<%= form.text_field :description, class: 'form-control'%>
<small><%= link_to "REMOVE", "#", data: {action: "click->nested-form#remove_association"}%></small>
<!-- <%= form.hidden_field :_destroy%> -->
</div>
<% end %>
data-new-record用于判断是不是新建数据。
添加一个data-action绑定事件remove_association。
再看nested_form_controller.js,添加事件:
remove_association(event) {
event.preventDefault()
let wrapper = event.target.closest(".nested-fields") #有nest-fileds类的元素
if (wrapper.dataset.newRecord == "true") {
wrapper.remove()
} else {
console.log("不能删除")
}
}
注意:
dataset属性提供了读写所有客制化的data属性 data-*
考虑到edit界面,有已经添加的task和新增的task,所以要区分,新增的直接从nom树移除,已经添加的则要发出删除请求。
修改上面的代码:
_nest.html.erb内添加一个input标签,并隐藏。它的用途是标记作用!
在js中添加2行代码:
- 找到这个input标签,并设置value等于1或者true, 这样更新时,会自动判断是否删除。
- 从节点树上隐藏这个元素。CSS#display属性设置none。
remove_association(event) {
event.preventDefault()
let wrapper = event.target.closest(".nested-fields")
if (wrapper.dataset.newRecord == "true") {
wrapper.remove()
} else {
wrapper.querySelector("input[name*='_destroy']").value = true
wrapper.style.display = 'none'
}
}
动态嵌套form,使用Stimulus Js库(前后端不分离)的更多相关文章
- Vue 应用 nginx 配置 前后端不分离模式
一.先在官网下载nginx 软件,解压后放在软件盘中如D盘 将nginx 文件夹拖到编译器中,打开conf 文件夹中的 nginx.conf 文件,找到其中的server {} 配置项,默认35 行. ...
- List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac
List多个字段标识过滤 class Program{ public static void Main(string[] args) { List<T> list = new List& ...
- Node.js实现前后端交互——用户注册
我之前写过一篇关于使用Node.js作为后端实现用户登陆的功能,现在再写一下node.js做后端实现简单的用户注册实例吧.另外需要说的是,上次有大佬提醒需要加密数据传输,不应该使用明文传输用户信息.在 ...
- 前后端不分离部署教程(基于Vue,Nginx)
有小伙伴私信问我vue项目是如何进行前后端不分离打包发布的,那我岂能坐视不管,如此宠粉的我肯定是要给发一篇教程的,话不多说,开始操作 前端假如我们要发布我们的Vue项目,假设我们前端用的是histor ...
- 在IDEA中使用Maven将SpringBoot项目打成jar包、同时运行打成的jar包(前后端项目分离)
1.maven教程官网 https://m.runoob.com/maven/ 2.理解Maven的构建生命周期(clean.Package) 3.在项目中使用maven进行打包 4.运行打包好的ja ...
- ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目
一.前言 这几年前端的发展速度就像坐上了火箭,各种的框架一个接一个的出现,需要学习的东西越来越多,分工也越来越细,作为一个 .NET Web 程序猿,多了解了解行业的发展,让自己扩展出新的技能树,对自 ...
- .Net Core与Vue.js模块化前后端分离快速开发解决方案(NetModular)
NetModular是什么? NetModular不仅仅是一个框架,它也是一整套的模块化与前后端分离的快速开发的解决方案,目标是致力于开箱即用,让开发人员完全专注于业务开发,不需要关心底层封装和实现. ...
- 一行代码实现Vue微信支付,无需引用wexin-sdk库,前后端分离HTML微信支付,无需引用任何库
前后端分离项目实现微信支付的流程: 1:用户点击支付 2:请求服务端获取支付参数 3:客户端通过JS调起微信支付(微信打开的网页) * 本文主要解决的是第3步,视为前两步已经完成,能正确拿到支付参数, ...
- 【转载】java前后端 动静分离,JavaWeb项目为什么我们要放弃jsp?
原文:http://blog.csdn.net/piantoutongyang/article/details/50878214 今天看到两篇文章,讲解 为什么web开发启用jsp,确实挺有道理,整理 ...
随机推荐
- bfs经典
题意:地图上分别用‘.’表示硬地,‘#’表示禁地,‘E’表示易碎地面.你的任务操作一个1*1*2的长方体.长方体有两种状态分别为:立在地面上,躺在地面上.把长方体从入口移动到出口,求需要的最小步数. ...
- 父网访问子网(校园网访问校园网IP路由器下的一台电脑)远程路由器下的电脑
网路由器添加转发规则,端口转发,本人仅使用Pandora Box路由器固件 当然设置了这些还不够,还需要设置其他的允许端口转发的东西,例如 然后远程桌面的话还需要设置某些相关设置,例如电脑允许使用远程 ...
- # 2017-2018-2 20155228 《信息安全系统设计原理》 使用VirtualStudio2008创建和调用静态库和使用VirtualC++6.0创建和调用动态库
使用virtual c++ 6.0创建和调用动态库 不得不说一下关于环境的问题 只要我打一个响指,一半的安装在win7上的VC6.0都会因为兼容性问题直接崩掉 懒得研究怎么解决兼容性的问题了,直接开一 ...
- jenkins构建任务后发送邮件
1.jenkins登录后-系统管理-系统设置打开后定位到下面的位置:系统管理员邮件地址一定要填写 2.下滑页面定位到extend E-mail Notification:这个是jenkins的一个插件 ...
- mysql知识点汇总
1. 数据库的安装 2. 数据库设计需要注意什么 3. SQL语句优化 4. 怎样处理慢查询? 5. 怎样更好的利用数据库索引? 6. 事务隔离级别有哪些?怎么实现的? 7. 数据库锁有哪些? 8. ...
- 防止sql注入(简单)
(1)mysql_real_escape_string -- 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count ...
- springboot-yml内list、map组合写法
yml:myProps: varmaplist: key11: - t1 - t2 - t3 key22: - t11 - t22 - t33 list: - topic1 - topic2 - to ...
- SAP如何修改表的数据
修改表: 事务代码:se16n 输入表名字 输入 /h 进入维护模式 修改 GD-EDIT 和 GD-SAPEDIT 内容为大写X. se ...
- 复旦大学2017--2018学年第二学期高等代数II期末考试情况分析
一.期末考试成绩班级前十名 张菲诺(95).刘宇其(95).魏一鸣(93).郭宇城(92).程梓兼(91).葛珈玮(90).汪子怡(90).余张伟(90).张昰昊(89).朱柏青(89) 二.总成绩计 ...
- Spring 学习——Spring AOP——AOP配置篇Advice(有参数传递)
声明通知Advice 配置方式(以前置通知为例子) 方式一 <aop:config> <aop:aspect id="ikAspectAop" ref=" ...