如何创建不属于表/表单的字段影响选项选择的动态表单
Posted
技术标签:
【中文标题】如何创建不属于表/表单的字段影响选项选择的动态表单【英文标题】:How to create a dynamic form where fields not belonging to a table/form influence the option choices 【发布时间】:2020-02-14 01:33:20 【问题描述】:我能够创建一个订单表单,用户可以在其中填写一个bike_type,然后表单会呈现属于这个bike_type 的自行车。
订单通过连接表链接到自行车(因为它们之间存在多对多关系)。 自行车属于bike_type bike_type 属于bike_store问题
当表单重新呈现时,例如(i) 引发验证,因此再次呈现“新”操作或 (ii) 当我想编辑订单时:
所有字段都使用以前的数据重新填充,但 bike_type 和 Bike 字段除外(这些字段为空)。代码
订单控制器
class OrdersController < ApplicationController
def new
@bike_store = BikeStore.find(params[:bike_store_id])
@order = Order.new
@order.order_bikes.build
@bike_type_list = @bike_store.bike_types
@bikes = []
# Display bikes for category
if params[:bike_type].present?
@bikes = BikeType.find(params[:bike_type]).bikes
end
if request.xhr?
respond_to do |format|
format.json
render json: bikes: @bikes
end
end
authorize @order
end
def create
@order = Order.new(order_params)
@bike_store = BikeStore.find(params[:bike_store_id])
@order.bike_store = @bike_store
authorize @order
@order.save
if @order.save
redirect_to bike_store_path(@bike_store)
else
@bike_type_list = @bike_store.bike_types
render 'new'
end
end
def edit
@bike_store = BikeStore.find(params[:bike_store_id])
@order = Order.find(params[:id])
@bike_type_list = @bike_store.bike_types
@bikes = @order.bikes
authorize @order
end
def update
@bike_store = BikeStore.find(params[:bike_store_id])
@order = Order.find(params[:id])
@bikes = @order.bikes
if @order.update(order_params)
redirect_to redirect_to bike_store_path(@bike_store)
else
render 'edit'
end
authorize @order
end
private
def set_order
@order = Order.find(params[:id])
end
def order_params
params.require(:order).permit(:arrival, :departure, :payment,
order_bikes_attributes: [:id, :bike_id, :bike_quantity, :_destroy,
bikes_attributes: [:id,:name, :bike_type_id,
bike_types_attributes: [:id, :name]]])
end
end
视图/订单/_form
<%= simple_form_for [@bike_store, @order] do |f|%>
<%= f.simple_fields_for :order_bikes do |order_bike| %>
<%= order_bike.simple_fields_for :bikes do |bike| %>
<%= bike.input :bike_type, collection: @bike_type_list, input_html:
id: "bike_type"
%>
<%= order_bike.association :bike, collection: @bikes, input_html:
value: @bikes.object_id,
id: "dynamic-bikes"
%>
<% end %>
<% end %>
<% end %>
<script >
// dynamic bikes for change category
$(document).on("change", "#bike_type", function()
var bike_type = $(this).val();
$.ajax(
url: "/bike_stores/<%= @bike_store.id %>/orders/new",
method: "GET",
dataType: "json",
data: bike_type: bike_type,
error: function (xhr, status, error)
console.error('AJAX Error: ' + status + error);
,
success: function (response)
var bikes = response["bikes"];
$("#dynamic-bikes").empty();
$("#dynamic-bikes").append('<option>Select bike</option>');
for(var i=0; i< bikes.length; i++)
$("#dynamic-bikes").append('<option value="' + bikes[i]["id"] + '">' + bikes[i]["name"] + '</option>');
);
);
// dynamic bikes for releading form (e.g. new)
$(document).ready(function()
var bike_type = $("#bike_type").val();
$.ajax(
url: "/bike_stores/<%= @bike_store.id %>/orders/new",
method: "GET",
dataType: "json",
data: bike_type: bike_type,
error: function (xhr, status, error)
console.error('AJAX Error: ' + status + error);
,
success: function (response)
var bikes = response["bikes"];
$("#dynamic-bikes").empty();
$("#dynamic-bikes").append('<option>Select bike</option>');
for(var i=0; i< bikes.length; i++)
$("#dynamic-bikes").append('<option value="' + bikes[i]["id"] + '">' + bikes[i]["name"] + '</option>');
);
);
</script>
【问题讨论】:
用户没有理由传递那么多信息。尤其是嵌套属性。用户应该只传递指向标准化产品表的 id 及其数量。我认为您基本上只是在这里给自己一个巨大的质量分配漏洞。 @Max,这是一个有趣的观点,因为我目前正在做的事情似乎确实过于复杂和脆弱。由于这是我第一次在类似电子商务的环境中工作,我将提出一个新问题,其中包含更多概念性问题,如何解决处理订单、bike_types 和相关自行车的问题。 【参考方案1】:听起来您想将表单提交前的表单页面的“状态”保留到提交后的同一表单页面中(发生验证错误时)。通常,您只需要“重播”上一页中发生的 Javascript 事件,因此“通常”,下面的内容应该已经足够让它工作了:
TL;DR:
app/views/order/_form.html.erb:
<!-- ... -->
<!-- ... -->
<script>
// on document ready (after all DOM elements have been loaded):
$(function()
// replay event by immediately triggering a
// "change" event on your `#bike_type` input
$('#bike_type').change();
)
// dynamic bikes for change category
$(document).on("change", "#bike_type", function()
// ...
// ...
)
// ...
// ...
</script>
【讨论】:
这并不总是有效,特别是如果您有意不想在页面加载后立即更改trigger
。如果它不能完全正常工作,请告诉我上面代码的其他影响,如果它很容易修复,我会更新上面的答案。
非常感谢您的详尽解释。澄清一下,您建议:(i) 保留“更改”事件 (ii) 通过在最后一行之前添加 $('#bike_type').change();
来更改 $(document).ready(function()
?
@techquestion ...
表示您的其余代码;所以 i) 是正确的,并且 ii) 您可以在 <script>
的最顶层上下文中的任何位置添加 $(document).ready(function() ... )
,因为无论您将其放在何处(之前或之后),无论如何,DOMContentLoaded
事件都是异步发生的
感谢您的上下文!它似乎不起作用,但我正在考虑为我的订单采用一种新方法,因为这似乎太复杂而无法正常运行。以上是关于如何创建不属于表/表单的字段影响选项选择的动态表单的主要内容,如果未能解决你的问题,请参考以下文章