[英]Rails - cascading select forms not updating each other and showing all results
[英]Rails 6 Cascading Select List
在Rails 6 中,我希望profiles/_form 有兩個下拉列表,country 和city。 當我從國家/地區選擇一個值時,這應該會改變城市的選擇。 我希望在不刷新頁面的情況下發生這種情況。 我的解決方案如下,它適用於新操作,但不適用於編輯操作。 這是正確的方法還是我完全錯過了慣用的 rails 6 解決方案?
返回城市選擇框的選項標簽的路線:
# config/routes.rb
get 'cities_by_country/:id', to: 'profiles#cities_by_country'
運行的動作
# profiles_controller
def cities_by_country
@city_list = Profile::CITY_LIST[params[:id].to_i]
respond_to do |format|
format.js { render :cities_by_country}
end
end
生成選項標簽的js文件
#views/profiles/cities_by_country.js.erb
<%= options_for_select(@city_list) %>
在國家選擇標簽上附加“更改”事件的 javascript:
# app/javascript/packs/country_cities.js
import Rails from '@rails/ujs';
var country_select, city_select, selected_country;
window.addEventListener("load", () => {
country_select = document.querySelector("select#profile_country");
city_select = document.querySelector("select#profile_city");
country_select.addEventListener('change', (event) => {
selected_country = country_select.selectedIndex;
Rails.ajax({
url: "/cities_by_country/" + selected_country,
type: "get",
data: "",
success: function (data) {
city_select.innerHTML = data;
},
error: function (data) { }
})
})
});
很抱歉把它堆在你身上,但這真的壞了。
讓我們從控制器/路由開始。 通過嵌套路由執行此操作的慣用方法 - GET /countries/:country_id/cities
。 你也不應該把它硬塞進你的 Profile 模型/ProfilesController。
您可以使用以下命令聲明路線:
get '/countries/:country_id/cities', to: 'countries/cities#index'
或者通過塊使用resources
:
resources :countries, only: [] do
resources :cities, only: [:index], module: :countries
end
控制器像這樣:
module Countries
class CitiesController < ApplicationController
# GET /countries/:country_id/cities
def index
@cities = Profile::CITY_LIST[params[:city_id].to_i]
end
end
end
不確定我是否真的能理解為什么您要在模型中使用常量而不是實際創建國家和城市模型,而根本不應該對此負責。
JavaScript 的最大問題是它完全非冪等。 它都在window.addEventListener("load")
上運行,以便它在初始頁面加載時工作,然后在 Turbolinks 用 AJAX 替換頁面內容時完全崩潰,因為這些事件處理程序直接附加到元素本身。
要編寫與 Turbolinks 一起使用的 JavaScript,您需要以不同的方式思考。 創建冪等處理程序,在事件冒泡 DOM 時捕獲該事件。
# app/javascript/packs/country_cities.js
import Rails from '@rails/ujs';
document.addEventListener('change', (event) => {
let input = event.target;
if (input.matches('#profile_country')) {
Rails.ajax({
url: `/cities/${input.value}/country`,
type: 'get',
dataType : 'script'
});
}
});
如果你想使用js.erb
模板,你還需要重寫你的視圖,以便它轉換頁面:
// app/views/countries/cities.js.erb
document.getElementById("#profile_city").innerHTML = "<%= j options_for_select(@cities) %>";
但是,如果您想避免讓服務器負責客戶端轉換,您也可以只使用 JSON 並在客戶端上創建選項元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.