Search code examples
ruby-on-railshotwire-railsstimulus-reflex

Stimulus not Adding Listeners to Search Form Input


I'm trying to create a search-as-you-type search box on my Rails 7 app. The type-hit-enter search works, and it's loading in a turbo frame, but the js-driven search-as-you-type functionality is broken. The event listener for the search box isn't firing at all...when I select the box and type, nothing appears on the browser's network tab or in the JS console.

Here's the search form partial:

<div>
    <%= search_form_for @q, data: { controller: "form-submission", turbo_frame: "companies", turbo_action: "advance" } do |f| %>
        <%= f.search_field :search_multi, placeholder: "Search", class: "form-control search-box", data: { action: "input->form-submission#search" } %>
    <% end %>
</div>

app/javascript/controllers/form_submission_controller.js:

import { Controller } from "@hotwired/stimulus"
    
export default class extends Controller {
    search() {
        clearTimeout(this.timeout)
        this.timeout = setTimeout(() => {
            this.element.requestSubmit()
        }, 200)
    }
}

app/javascript/controllers/index.js:

// Import and register all your controllers from the importmap under controllers/*

import { application } from "controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)

config/importmap.rb

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"

pin "popper", to: 'popper.js', preload: true
pin "bootstrap", to: 'bootstrap.min.js', preload: true

I've tried Chrome and Safari.

I went so far as to rebuild my Rails app installation with the following, and then copied all of my code back over to it: rails new app --database=postgresql --asset-pipeline=sprockets --javascript=importmap

On the JS console: getEventListeners($("#q_search_multi")) shows nothing.

I also tried bin/rails assets:clobber && bin/rails assets:precompile.


Solution

  • Today I rebuilt the application from scratch and determined the cause: I was missing <%= javascript_importmap_tags %> in app/app/views/layouts/application.html.erb. sigh Lesson learned. Here's the full application.html.erb:

    <!DOCTYPE html>
    <html>
      <head>
        <title>App</title>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
        <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
        <%# turbo_include_tags %>
        <%= javascript_importmap_tags %>
      </head>
    
      <body>
        <main class="container">
          <%= yield %>
        </main>
      </body>
    </html>
    

    Shout out to this guide for building a search-as-you-type search box: https://www.colby.so/posts/instant-search-with-rails-6-and-hotwire