Search code examples
cssbootstrap-5ruby-on-rails-7hotwire-rails

Hamburger Menu Goes Down, But Not Up


I am using Ruby on Rails 7. Bootstrap 5. My hamburger menu will open, but will not close. All other dropdowns work fine. Here is my code:

<nav class="navbar navbar-expand-lg bg-dark border-bottom border-body" data-bs-theme="dark">

    <div class="container-fluid">
      <a class="navbar-brand" href="/" style="color: white">ContactPoints.io</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>

      <div class="collapse navbar-collapse" id="navbarTogglerDemo02">
        <ul class="navbar-nav ms-auto mb-2 mb-lg-0">
          <% if current_user %>
            <%= render "layouts/logged_in_nav" %>
          <% else %>
            <%= render "layouts/logged_out_nav" %>
          <% end %>
        </ul>
      </div>
    </div>
  </nav>

Here are my CDNs:

<!DOCTYPE html>
<html>
  <head>
    <title>Contact Points</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= favicon_link_tag 'favicon.ico' %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>

    <%# Bootstrap 5 JS %>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>

    <%# Bootstrap 5 CSS %>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

    <!-- Include Stripe javascript -->
    <script src="https://js.stripe.com/v3"></script>

    <!-- Include Bootstrap modal library -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>

    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>

    <script src="https://cdn.jsdelivr.net/gh/xcash/[email protected]/dist/latest/bootstrap-autocomplete.min.js"></script>

  </head>

  <body>

    <%= render '/layouts/topnav' %>

    <% if flash[:alert].present? %>
      <div style="background-color: yellow; text-align: center; padding: 10px;">
        <%= flash[:alert] %>
      </div>
    <% end %>

    <br>

    <%= yield %>

  </body>
</html>

Every other feature of bootstrap seems to work fine, even other dropdowns. The only issue is this hamburger menu.

The CDNs appear to be correct. I tried taking the 'perfect' code from GetBootstrap (which works there) and swapping that in for mine. Same issue. So it doesn't appear to be the code. It appears to be something else.

UPDATE: Based on feedback from @mikegross I started commenting out various combinations of CDNs. I found a combination of comment-outs that allowed the hamburger menu to work:

<!-- Include Bootstrap modal library -->
<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> -->

<%# javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>

When I comment both of them out, it works. When either of them is allowed to function, it doesn't work. Very curious.

To summarize, if I comment out the javascript_include_tag code, hamburger menu doesn't work. If I comment out the bootstrap modal library code, hamburger menu doesn't work. If I comment out BOTH of them, then the hamburger menu works.

We are getting closer to a solution, but I'm not precisely sure what that solution is.

Here is my application.js (in javascript/controllers)

import { Application } from "@hotwired/stimulus"
// import "controllers"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus   = application

export { application }

console.log("other javascript.js is being called");
console.log("why do we have two application.js?");

//= require pagy
//= require pagy/extras/bootstrap

This is the other application.js (this one in the main javascript folder)

// Entry point for the build script in your package.json
import "@hotwired/turbo-rails"
import "./controllers"
import * as bootstrap from "bootstrap"

console.log("application js is being called")

Is it normal to have 2 application.js files when using hotwire? ChatGPT says yes, and that my two application.js files look okay.

Note: I removed this line from application.js, hoping that it would avoid conflicts with the bootstrap CDN, but no change. Hamburger menu still wouldn't work:

import * as bootstrap from "bootstrap"

Solution

  • I was able to find the solution.

    I was importing bootstrap twice.

    Once via the CDN in application.html.erb

    Again via application.js

    The solution was to:

    1. Comment out the bootstrap modal CDN import code -- not necessary since it's also part of the main bootstrap JS import.

    2. Comment out the bootstrap js CDN import code -- not necessary since it was already being imported by the @import on the application.js page.

    3. Leave the bootstrap css CDN untouched

    This allowed the javascript_include_tag to import the bootstrap JS via the @import, and in this way, it was not being imported twice.

    Surprised that this double import caused so much trouble with that hamburger menu, but alas, that was the problem.

    So for anyone else having this problem, check to see if you are trying to import bootstrap in two different methods. If so, get rid of one of them.