如何使用AJAX更新simple_form输入字段?

时间:2022-06-12 17:07:09

I have a simple_form input field that is part of a form that I need to update asynchronously when the onchange event is triggered.

我有一个simple_form输入字段,它是我需要在触发onchange事件时异步更新的表单的一部分。

The field that I need to update is displayed as a select box since it is a collection. But the collection represents records of a nested set model. So when the user selects a particular value, I want to be able to update the same field with its children and give the user the option of picking any of the children as the value for the same field.

我需要更新的字段显示为选择框,因为它是一个集合。但该集合表示嵌套集模型的记录。因此,当用户选择特定值时,我希望能够使用其子项更新相同的字段,并为用户提供选择任何子项作为相同字段的值的选项。

The problem is, how do I update just that field without touching the rest of the form.

问题是,如何在不触及表单其余部分的情况下更新该字段。

Just to give some idea of my current setup: The form looks something like this:

只是想了解我当前的设置:表单看起来像这样:

 <%= simple_form_for @product, html: {class: 'form-horizontal'} do |f| %>
     <%= f.input :product_name %>
     <%= f.association :location, collection: @locations, input_html: { data: {remote: :true, url: "/update_locations"} } %>
 <%= f.submit 'Post', class: 'btn btn-default btn-lg' %>
  <% end %>

@product is a new Product which belongs_to Location, @locations is a collection of Location each of which has_many Product hence the use of the simple_form association method Location also acts_as_nested_set

@product是belongs_to Location的新产品,@ locations是Location的集合,其中每个都有has_many Product因此使用simple_form关联方法Location也acts_as_nested_set

I have this in my routes.rb

我在我的routes.rb中有这个

get 'update_locations'    => 'products#update_locations'

I need help in completing the controller action:

我需要帮助来完成控制器操作:

  def update_locations
    @product = Product.new
    @location = Location.find_by_id(params[:product][:location_id])
    @locations = @location.children
    
    # TODO: render code that updates the simple_form field with
    # the new @locations collection
  end

I am not sure what code should go in the partial view that the controller above is supposed to render.

我不确定在上面的控制器应该渲染的局部视图中应该使用什么代码。

1 个解决方案

#1


3  

The problem was I didn't know how to update just one element inside a simple_form. I also had a very loose grasp on using AJAX with rails not knowing you could have both HTML and JS partial views for the same controller, as such I was trying to fit all my code in just HTML which would have been cumbersome and going against unobtrusive JavaScript.

问题是我不知道如何更新simple_form中的一个元素。我对使用带有轨道的AJAX非常松懈,不知道你可以为同一个控制器同时拥有HTML和JS部分视图,因此我试图将我的所有代码都放在HTML中,这本身就很麻烦并且反对不引人注目JavaScript的。

Stumbling upon the jQuery method replaceWith was also very helpful.

绊倒jQuery方法replaceWith也非常有帮助。

Armed with this knowledge, I was able to accomplish what I had set out to do.

有了这些知识,我就能完成我的目标。

I created a JavaScript partial view which is rendered in response to the AJAX call. The partial renders a .html.erb partial view which rebuilt a simple_form with the updated element. The JS view then extracts the updated element from the rebuilt form and uses the jQuery replaceWith() method to replace just the specific element inside the initial form while leaving the rest of the form unchanged.

我创建了一个JavaScript部分视图,它是为响应AJAX调用而呈现的。 partial呈现.html.erb局部视图,该视图使用更新的元素重建simple_form。然后,JS视图从重建的表单中提取更新的元素,并使用jQuery replaceWith()方法仅替换初始表单中的特定元素,同时保持表单的其余部分不变。

Here is how the JS partial (location.js.erb) looks like:

以下是JS partial(location.js.erb)的外观:

var updatedLocations = $('#product_location_id', $('<%= j render "updateLocations" %>'))
$('#product_location_id').replaceWith(updatedLocations)

And the HTML erb partial (updateLocations.html.erb) looks something like this:

HTML erb partial(updateLocations.html.erb)看起来像这样:

<%= simple_form_for @product, html: {class: 'form-horizontal'} do |f| %>

<%= f.association :location, collection: @locations, input_html: { data: {update_locations: "true", remote: :true, url: "/update_locations"} } %>

<% end %>

And the controller:

和控制器:

  def update_locations
    @product = Product.new
    @location = Location.find_by_id(params[:product][:location_id])
    @locations = @location.children
    if @locations.empty?
      render nothing: true
    else
      render partial: 'locations'
    end
  end

#1


3  

The problem was I didn't know how to update just one element inside a simple_form. I also had a very loose grasp on using AJAX with rails not knowing you could have both HTML and JS partial views for the same controller, as such I was trying to fit all my code in just HTML which would have been cumbersome and going against unobtrusive JavaScript.

问题是我不知道如何更新simple_form中的一个元素。我对使用带有轨道的AJAX非常松懈,不知道你可以为同一个控制器同时拥有HTML和JS部分视图,因此我试图将我的所有代码都放在HTML中,这本身就很麻烦并且反对不引人注目JavaScript的。

Stumbling upon the jQuery method replaceWith was also very helpful.

绊倒jQuery方法replaceWith也非常有帮助。

Armed with this knowledge, I was able to accomplish what I had set out to do.

有了这些知识,我就能完成我的目标。

I created a JavaScript partial view which is rendered in response to the AJAX call. The partial renders a .html.erb partial view which rebuilt a simple_form with the updated element. The JS view then extracts the updated element from the rebuilt form and uses the jQuery replaceWith() method to replace just the specific element inside the initial form while leaving the rest of the form unchanged.

我创建了一个JavaScript部分视图,它是为响应AJAX调用而呈现的。 partial呈现.html.erb局部视图,该视图使用更新的元素重建simple_form。然后,JS视图从重建的表单中提取更新的元素,并使用jQuery replaceWith()方法仅替换初始表单中的特定元素,同时保持表单的其余部分不变。

Here is how the JS partial (location.js.erb) looks like:

以下是JS partial(location.js.erb)的外观:

var updatedLocations = $('#product_location_id', $('<%= j render "updateLocations" %>'))
$('#product_location_id').replaceWith(updatedLocations)

And the HTML erb partial (updateLocations.html.erb) looks something like this:

HTML erb partial(updateLocations.html.erb)看起来像这样:

<%= simple_form_for @product, html: {class: 'form-horizontal'} do |f| %>

<%= f.association :location, collection: @locations, input_html: { data: {update_locations: "true", remote: :true, url: "/update_locations"} } %>

<% end %>

And the controller:

和控制器:

  def update_locations
    @product = Product.new
    @location = Location.find_by_id(params[:product][:location_id])
    @locations = @location.children
    if @locations.empty?
      render nothing: true
    else
      render partial: 'locations'
    end
  end