You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RoR应用vendor页面问题:仅刷新生效,导航跳转后下拉框失效

Fixing Linked Dropdown & Placeholder Issues in Rails When Navigating via Header

Hey there, let's break down what's almost certainly causing this problem and walk through how to fix it!

The Root Cause

Rails (starting from version 7) uses Turbo Drive by default. When you navigate via the header (instead of refreshing the page), Turbo doesn't reload the entire browser page—it only swaps out the <body> content of the current page.

If your linked dropdown (country → state → city) and placeholder logic is tied to a one-time page load event like DOMContentLoaded or $(document).ready(), that code only runs once when you first refresh the page. When Turbo navigates to vendor.html.erb, the new DOM elements (your dropdowns and inputs) never get initialized, leading to broken functionality.

Solutions to Try

1. Use Turbo's Lifecycle Events to Re-Initialize Your Code

Instead of relying on page-load-only events, hook into Turbo's turbo:render event—it fires every time Turbo renders new content (including after navigation). Here's a vanilla JS example for your dropdowns:

document.addEventListener('turbo:render', function() {
  // Initialize country → state联动
  const countrySelect = document.getElementById('country_id');
  if (countrySelect) {
    // Remove existing listeners first to avoid duplicates
    countrySelect.replaceWith(countrySelect.cloneNode(true));
    const freshCountrySelect = document.getElementById('country_id');

    freshCountrySelect.addEventListener('change', function() {
      fetch(`/states?country_id=${this.value}`)
        .then(res => res.json())
        .then(states => {
          const stateSelect = document.getElementById('state_id');
          stateSelect.innerHTML = '<option value="">选择州/省份</option>';
          states.forEach(state => {
            const option = document.createElement('option');
            option.value = state.id;
            option.textContent = state.name;
            stateSelect.appendChild(option);
          });
          // Reset city dropdown
          document.getElementById('city_id').innerHTML = '<option value="">选择城市</option>';
        });
    });
  }

  // Initialize state → city联动
  const stateSelect = document.getElementById('state_id');
  if (stateSelect) {
    stateSelect.replaceWith(stateSelect.cloneNode(true));
    const freshStateSelect = document.getElementById('state_id');

    freshStateSelect.addEventListener('change', function() {
      fetch(`/cities?state_id=${this.value}`)
        .then(res => res.json())
        .then(cities => {
          const citySelect = document.getElementById('city_id');
          citySelect.innerHTML = '<option value="">选择城市</option>';
          cities.forEach(city => {
            const option = document.createElement('option');
            option.value = city.id;
            option.textContent = city.name;
            citySelect.appendChild(option);
          });
        });
    });
  }

  // Fix placeholder issues (if they rely on JS)
  const inputs = document.querySelectorAll('input[placeholder]');
  inputs.forEach(input => {
    // Force re-apply placeholder if needed
    input.placeholder = input.getAttribute('placeholder');
  });
});

2. Use Event Delegation (Great for jQuery Users)

If you're using jQuery, bind your events to a parent element (like document) instead of the dropdowns themselves. This works even for elements added after the initial page load:

$(document).on('change', '#country_id', function() {
  $.get(`/states?country_id=${$(this).val()}`, function(states) {
    $('#state_id').html('<option value="">选择州/省份</option>');
    $.each(states, function(_, state) {
      $('#state_id').append(`<option value="${state.id}">${state.name}</option>`);
    });
    $('#city_id').html('<option value="">选择城市</option>');
  });
});

$(document).on('change', '#state_id', function() {
  $.get(`/cities?state_id=${$(this).val()}`, function(cities) {
    $('#city_id').html('<option value="">选择城市</option>');
    $.each(cities, function(_, city) {
      $('#city_id').append(`<option value="${city.id}">${city.name}</option>`);
    });
  });
});

3. Quick Check: Disable Turbo for the Header Link (Last Resort)

If you want to bypass Turbo entirely for this navigation, add data-turbo="false" to your header link:

<%= link_to '供应商管理', vendors_path, data: { turbo: false } %>

This will force a full page reload, but it's less efficient than fixing the JS to work with Turbo.

Final Notes

  • Always test your changes after navigation and page refresh to ensure functionality works in both scenarios.
  • If your placeholder issues are purely HTML-based (no JS), double-check your ERB template to make sure the placeholder attribute is set correctly on inputs—Turbo sometimes has issues with malformed HTML during content swaps.

内容的提问来源于stack exchange,提问作者whatanoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:28:23