Search code examples
ruby-on-railspopover

Rails 7: Popover does not work when clicking submit button


I'm working in an rails 7 application where a bootstrap popover should raise when an element is clicked. It was working until I added a form with a submit button. After that, the element does not "pops" after hitting the submit button (but works after refresh). I'd like to know why this happens and how can I fix it.

The application is rather big, so I tried to create a simple application where the problem appears. I'll describe all the steps to create the application and the contents of the files:

  1. versions:

ruby -v ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux] rails -v Rails 7.0.4.3

  1. create application

rails new popover --css=bootstrap

  1. enter

cd popover

  1. generate controller

bin/rails g controller test action

  1. file app/javascript/application.js

     import "@hotwired/turbo-rails"
     import "./controllers"
     import * as bootstrap from "bootstrap"
    
     let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
     let popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
       return new bootstrap.Popover(popoverTriggerEl) })
    
     var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
     var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
       return new bootstrap.Tooltip(tooltipTriggerEl) })
    
  2. file app/controllers/test_controller.rb

     class TestController < ApplicationController
       def action
         grr = params[:grr].present? ? params[:grr] : nil
       end
     end
    
  3. file app/views/test/action.html.erb

    <div id="some-id">
    <%= form_tag('action',  :method => "get") do %>
    
    <fieldset class="">
        <legend class="">Type Something</legend>
    
        <div class="form-group">
          <div class="form-group">
            <%= label_tag "GRR: ",  nil, class: "col-lg-2 col-form-label"   %>
            <%= text_field_tag :grr,  nil, class: "col-lg-4" %>
          </div>
          <%= submit_tag "Submit", class: "col-lg-2 btn btn-primary "    %>
        </div>
    </fieldset>
    
    <%end%>
    
    <%= generate_popover %>
    

Popover works until you click the submit button. It works again after refresh page.

  1. file app/helpers/test_helper.rb

     module TestHelper
       def generate_popover
         button_tag("click me to popover message",
            data: { bs_toggle: 'popover',
                    bs_html: 'true',
                    bs_content: "Popover Msg" })
       end
     end
    

I' like to know what causes the problem and how to fix it.


Solution

  • If this premise is correct:

    • page loads with:
      • form for "GRR:"
      • buttton with data-bs_toggle="popover"

    and:

    • Before form submission, popover button works as expected
    • After form submission, popover button does not work
    • After page refresh, popover button works as expected

    When the submit button is pushed the form is either:

    • AJAXing the form data to the controller action
    • performing a GET request to the controller action

    Which ever one of those that is happening, it is breaking bootstrap's eventListener that is waiting for the button click.

    Refreshing the page re-loads bootstrap's JS and the eventListener is re-established and the button works again as expected.

    The fix is a bit trickier, but you've got to find a way to either prevent the eventListener from getting broken or force the eventListener to be re-established after form submission.

    What I'd try first, especially if I didn't care about AJAX vs. GET, is to toggle my form's remote setting:

    <%= form_tag('action',  method: "get", remote: true) do %>
    <%= form_tag('action',  method: "get", remote: false) do %>
    

    If one of those fixes it, I'd call it a win and move on. Much easier than messing with the JS.


    Update

    try to specifically disable turbolinks on the form_tag or the submit_tag:

    <%= form_tag('action',  method: "get", remote: false, data: { turbo: false }) do %>
    
    <%= submit_tag "Submit", class: "col-lg-2 btn btn-primary", data-turbo: false %>