我有一个rails 7应用程序,我正试图用tom-selectslim-select创建一个搜索栏.无论我使用哪个库,我的问题都会复制,因此它一定是我rails方面的问题.

app/views/cities/index.html.erb


<%= form_for :city, url: cities_path, method: 'GET' do |f| %>
  <div class="mt-4 border bg-light px-4 py-3 rounded-3">
    <%= f.select :search_city, [], {},
                  placeholder: 'Type to search',
                  data: {
                    controller: 'ts--search',
                    ts__search_url_value: autocomplete_cities_path
                  } %>
    <%= f.submit 'Search', class: 'btn mx-auto' %>
  </div>
<% end %>

这是我的js控制器(在本例中,我使用的是tom select)

import { Controller } from "@hotwired/stimulus";
import { get } from "@rails/request.js";
import TomSelect from "tom-select";

export default class extends Controller {
  static values = { url: String };

  connect() {
    var config = {
      plugins: ["input_autogrow", "remove_button", "no_active_items"],
      render: {
        option: this.render_option,
        item: this.render_option,
      },
      valueField: "value",
      loadThrottle: 400,
      load: (q, callback) => this.search(q, callback),

      closeAfterSelect: true,
      persist: false,
      create: false,
      delimiter: ", ",
      maxItems: 10,
    };

    new TomSelect(this.element, config);
  }

  async search(q, callback) {
    const response = await get(this.urlValue, {
      query: { query: q },
      responseKind: "json",
    });

    if (response.ok) {
      callback(await response.json);
    } else {
      console.log("Error in search_ctrl: ");
      callback();
    }
  }

  render_option(data, escape) {
    return `<div>${escape(data.text)}</div>`;
  }
}

app/controllers/cities_controller.rb

class CitiesController < ApplicationController
  def index
  end

  def autocomplete
    list = City.order(:name)
               .where("name ilike :q", q: "%#{params[:q]}%")

    render json: list.map { |u| { text: u.name, value: u.id, sub: u.state } }
  end

end

Problem Repro:

  1. 打开城市索引并单击搜索栏.
  2. 下拉菜单打开,我可以键入并 Select 一个建议.一旦选中,建议将显示在搜索栏中,单击"x"将从搜索栏中删除.
  3. 我添加任意数量的搜索令牌,1-N.
  4. 单击"搜索"-&gt;查看结果页面.
  5. 单击浏览器中的后退按钮(或在手机上向后滑动)

Expected behavior:

Actual behavior:

我回来后怎么让JS工作?

推荐答案

// TLDR

// app/javascript/controllers/ts/search_controller.js
disconnect() {
  this.element.tomselect.destroy();
}

当使用浏览器"后退按钮"时,Turbo Drive执行restoration visit并显示页面的缓存副本.此副本在访问另一个页面之前保存.任何附加的javascript行为都会丢失,我们只会得到html.

Stimulus连接到[data-controller=ts--search]时,select元件由TomSelect修改:

<select placeholder="Type to search" data-controller="ts--search" data-ts--search-url-value="/cities/autocomplete" name="city[search_city]" id="city_search_city">
</select>

为此:

<select placeholder="Type to search" data-controller="ts--search" data-ts--search-url-value="/cities/autocomplete" name="city[search_city]" id="city_search_city"
  multiple="multiple"
  tabindex="-1"
  class="tomselected ts-hidden-accessible">
<!--     ^
  NOTE: this class
-->
</select>

<div class="ts-wrapper multi plugin-input_autogrow plugin-remove_button plugin-no_active_items has-options">
   <!-- ... -->
</div>

单击另一个链接时,此修改的html将保存到缓存中,稍后在使用浏览器反向导航时恢复.然后Stimulus再次连接,然而,TomSelect跳过.tomselected个元素以避免再次追加.ts-wrapper.看起来是一样的,因为加载了html和样式,但没有附加任何javascript行为.

通过启用Stimulus调试日志(log)记录,我们可以获得更多的上下文:

// app/javascript/controllers/application.js
application.debug = true // <= set this to `true`

// app/javascript/controllers/ts/search_controller.js
// inside connect()
console.log(this.element.getAttribute("class"));
new TomSelect(this.element, config);
console.log(this.element.getAttribute("class"));

如果缓存了带有搜索表单的页面,并且我们通过单击链接导航到该页面:

                                  // a cached page is displayed while
                                  // waiting for response from the server

ts--search #initialize            // found ts--search on the page
tomselected ts-hidden-accessible  // cached <select>
                                  // new TomSelect() has no effect
tomselected ts-hidden-accessible  // at least it looks the same
ts--search #connect               // finished connecting

                                  // a fresh response from the server arrived

ts--search #disconnect            // <= SOLUTION
ts--search #initialize            // run the lifecycle again on a new page
null                              // untouched <select> from the server
                                  // new TomSelect() now works
tomselected ts-hidden-accessible  // new fancy select is on the page
ts--search #connect               // done

使用浏览器反向导航时:

                                  // a cached page is displayed

ts--search #initialize            // found ts--search on the page
tomselected ts-hidden-accessible  // cached <select>
tomselected ts-hidden-accessible  // new TomSelect() does nothing
ts--search #connect               // fail

当离开表单时(通过单击"离开"、"浏览器后退"或"浏览器前进")还会发生一件事:

before-cache
ts--search #disconnect

Turbo缓存页面之前,Stimulus在我们的搜索控制器中调用disconnect().在turbo缓存页面之前,我们可以在这里恢复原来的select.这样可以在缓存的页面上重新应用TomSelect.

// app/javascript/controllers/ts/search_controller.js

disconnect() {
  this.element.tomselect.destroy();
}

100

100

100

100

Javascript相关问答推荐

具有相同参数的JS类

从mat—country—select获取整个Country数组

类型自定义lazy Promise. all

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

在浏览器中触发插入事件时检索编码值的能力

当输入字段无效时,我的应用程序不会返回错误

如何创建返回不带`new`关键字的实例的类

使用带有HostBinding的Angular 信号来更新样式?

Reaction Redux&Quot;在派单错误中检测到状态Mutations

元素字符串长度html

如何限制显示在分页中的可见页面的数量

自定义图表工具提示以仅显示Y值

AddEventListner,按键事件不工作

如何使用Astro优化大图像?

使用线性插值法旋转直线以查看鼠标会导致 skip

不协调嵌入图片

表单数据中未定义的数组键

单击时同时 Select 和展开可访问的行

带有JS模块模式的Rails的Importmap错误:";Net::ERR_ABORTED 404(未找到)&Quot;

在D3.js中创建具有旋转手柄的可拖动、可调整大小的框?