I'm working on building my template and have the initial steps down. I'm on Rails 7.0.2.4, turbo-rails 1.1.1, Bootstrap 5.
In my layouts template's I have the following:
= javascript_include_tag "application", data:{turbo:{track: "reload"}}, defer: true
Which links to my app/javascript/application.js, and the relevant parts here are:
import * as bootstrap from "bootstrap"
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
The second part above enabled Bootstraps tooltips.
Back in my template, I break it down into three Turbo Frames:
%turbo-frame{id: "main_frame", data:{turbo:{action: "advance"}}}
.container-fluid
.row.flex-nowrap
.col-auto.col-md-3.col-xl-2.px-sm-2.px-0.bg-dark
%turbo-frame{id: "sidebar", data:{turbo:{action: "advance"}}}
.col
%turbo-frame{id: "content", data:{turbo:{action: "advance"}}}
= yield
First, there is the main_frame, which is then divided into a Sidebar and a Content frame. Clicking on links in the sidebar, which have date-turbo-frame: "content" attributes, swaps out the Content frame with that necessary content.
Now, on most full Content frames, the top of that frame has a navigation header which has a button on the left and right sides and text in the middle:
%turbo-frame{id: "content", data:{turbo:{action: "advance"}}}
.row
.d-flex
.p-2
%a{href: path, data:{turbo:{frame: "content"},
bs:{toggle: "tooltip", placement: "bottom",
title: "Back"}},
aria:{label: "Back"}}
%i.bi.bi-arrow-left-circle-fill{aria:{hidden: "true"}}
.flex-grow-1
// Some Text
.p-2
%a{href: new_path, data:{turbo:{frame: "new"},
bs:{toggle: "tooltip", placement: "bottom",
title: "New"}},
aria:{label: "New"}}
%i.bi.bi-plus{aria:{hidden: "true"}}
When you navigate to this replaced Content, the tooltips do not work. However, when you do a FULL page reload via the browser, the tooltips are suddenly working because the code is in the head.
Is there a way I can get the frames to load the necessary Javascript?
CodePudding user response:
Basically with Turbo your JS is added into the head and not modified across pages loads.
So when you call :
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
Basically it will search the DOM for requested DOM nodes at the exact time your JS is appended to the application. And if your app refreshes a turbo Frame, then it won't be played. Please see this thread I replied recently : How to load page specific custom Javascript functions in a Rails 7 app with Turbo, ImportMaps and Stimulus?
If you want your Tooltips being refreshed when new content is loaded then you have to use Stimulus, put the code into the connect()
method of a Stimulus controller, and attach that controller to every part of your application that may contain tooltips.
You can also attach your controller to the <html>
tag and add a mutation observer (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) inside the connect()
method if you don't want to attach your Stimulus controller at many places across your app. (You can also add the Mutation Observer in javascript/application.js
if you wish. Stimulus purpose is actually to prevent spamming Mutation Observers but if you have many Tooltips, it is still a viable solution)