Activate a Bootstrap tab using turbolinks dynamically

After loading the page, I am attempting to open a Bootstrap 4 tab. It works when I refresh the page, but if I navigate within the site, it gives me a query selector empty error.

This code is a port of the solution mentioned in this tutorial, as I am using Bootstrap-native and had to rewrite it in vanilla JavaScript.


document.addEventListener("turbolinks:load", function() {
  let url = location.href.replace(/\/$/, "");
  if (location.hash) {
    const hash = url.split("#");
    document.querySelector('#nav-tab a[href="#'+hash[1]+'"]').Tab.show();
    url = location.href.replace(/\/#/, "#");
    history.replaceState(null, null, url);
    setTimeout(() => {
      window.scrollTo(0,0);
    }, 400);
  }
});

I included this script just before the closing body tag. When I enter http://www.myURL#mytab and refresh the page, the tab switches successfully. However, if I access the link through a turbo link, the tab cannot be found for selection. I suspect the issue lies with the "load" event, and despite trying various methods, I have not been able to make it work.

Answer №1

If you are integrating this code within a <script> at the conclusion of the <body>, there might not be a necessity to monitor for the turbolinks:load event. Why? Upon initial loading, the browser will have the ability to retrieve any elements positioned prior to the script element. As Turbolinks loads scripts in the <body>, they will possess access to all the rendered elements on the page.

It's important to note that by executing

document.addEventListener("turbolinks:load", …)
in a <script> element within the body, the listener will be activated on every subsequent page load, not solely on the page where the script is displayed. In case the #nav-tab elements are absent during a subsequent page load, an error related to querySelector will be encountered. Moreover, if the script is incorporated on multiple pages, the listener will continuously duplicate, which may not align with your intentions!

To address this issue, the initial step involves removing the event listener. We shall encapsulate your code within an immediately invoked function to prevent contamination of the global scope:

;(function() {
  let url = location.href.replace(/\/$/, "");
  if (location.hash) {
    const hash = url.split("#");
    document.querySelector('#nav-tab a[href="#'+hash[1]+'"]').Tab.show();
    url = location.href.replace(/\/#/, "#");
    history.replaceState(null, null, url);
    setTimeout(() => {
      window.scrollTo(0,0);
    }, 400);
  }
})();

Another key aspect to consider is that Turbolinks maintains its own cache of visited pages, ensuring that when a user selects "Back," a page is retrieved from this cache. To accomplish this, it operates a mechanism for augmenting the browser's history stack. If you circumvent the Turbolinks system and trigger history.replaceState (or history.pushState) manually, you risk disrupting the "Back" navigations. While Turbolinks lacks a documented method for manually enhancing its history stack, you can experiment with the following approach:

;(function() {
  let url = location.href.replace(/\/$/, "");
  if (location.hash) {
    const hash = url.split("#");
    document.querySelector('#nav-tab a[href="#'+hash[1]+'"]').Tab.show();
    url = location.href.replace(/\/#/, "#");
    Turbolinks
      .controller
      .replaceHistoryWithLocationAndRestorationIdentifier(url, Turbolinks.uuid())
    setTimeout(() => {
      window.scrollTo(0,0);
    }, 400);
  }
})();

Note that this technique is not officially documented, hence it may not remain accessible in forthcoming versions.

Lastly, it could prove beneficial to incorporate this snippet within your primary application JavaScript bundle and include it in the <head> section instead of within the body. Under such circumstances, you might require utilizing a `turbolinks:load` handler. The implementation could resemble the following:

document.addEventListener('turbolinks:load', function () {
  let url = location.href.replace(/\/$/, "");
  const hash = url.split("#");
  const navLink = document.querySelector('#nav-tab a[href="#'+hash[1]+'"]')
  if (location.hash && navLink) {
    navLink.Tab.show();
    url = location.href.replace(/\/#/, "#");
    Turbolinks
      .controller
      .replaceHistoryWithLocationAndRestorationIdentifier(url, Turbolinks.uuid())
    setTimeout(() => {
      window.scrollTo(0,0);
    }, 400);
  }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it considered fundamentally inappropriate to call $scope.$digest within $scope.$on?

I recently inherited some AngularJS code, and my knowledge of both the codebase and Angular itself is limited. Within the code I inherited, there are instances where $scope.$digest is being called inside a $scope.$on method within a controller. Here's ...

Issue encountered when attempting to invoke a service from an Angular component within an office.js dialog

Our application utilizes Angular 5 and integrates Office.js to interact with Microsoft Office Word documents. Step 1: We use office displayDialogAsync to load the component. https://i.sstatic.net/uhT66.png Step 2: Inside the attribute-users component, an ...

Javascript will not recognize or interpret PHP's HTML tags

When PHP sends HTML strings to HTML through AJAX wrapped in <p class="select"></p> tags, the CSS reads the class perfectly. However, JavaScript/jQuery does not seem to work as expected. Even when trying to parse <p onclick="function()">&l ...

What is the best method in JavaScript to create three different shades of a color?

My sass function generates lighter and darker versions of a base color, here is the code snippet: $colors: ( betpawa-green: #107A3D, lime-green: #8DC63F, yellow: #FBCD00, ); @mixin color-generator { @each $name, $hex in $colors { &-#{$nam ...

When the ENTER button is pressed in the BUTTON, the keyup event is triggered in the

I am facing an issue with this particular scenario: 1 input 1 button Using jQuery, I have the following bindings: input.keyup = intercept the ENTER press and display an alert message button.click = simply focus on the input field To replicate the probl ...

SVGs do not display on iPhones

Having some issues with my code - specifically, I have an SVG animation that seems to work on all devices except iPhones. I've been struggling to find a solution. Here is the code snippet for the SVG: <div class="contenuto-svg"> <svg vi ...

Using Vue.js to bind labels and radio buttons in a form

My goal is to generate a dynamic list of form polls based on the data. However, using :for or v-bind:for does not result in any HTML markup appearing in the browser, causing the labels to not select the corresponding input when clicked. I have prepared a J ...

Implement authentication verification on all child endpoints within an express router

I have an express router set up and I want only authorized users to access its routes. I am currently using passport middleware. Instead of adding a check for req.user in every endpoint, is there a more efficient way to handle this? router.get("/", asyn ...

The process of encoding Point of Sale (POS) data as application/x-www-form-urlencoded

Can anyone provide guidance on how to correctly POST a URL encoded as application/x-www-form-urlencoded? I have all the necessary variables for the API suggestion below, but I'm struggling with posting it correctly. Thank you in advance for your help ...

What is the process for transitioning from Ajax to Fetch API in JavaScript?

Currently, I am utilizing the JavaScript version of RiveScript which relies on ajax, and I have decided to move away from using jQuery. There is a single line of ajax code that I need to update to integrate the new Fetch API. **Note: The ajax code can be ...

Is it possible to make radio buttons in each row of a grid mutually exclusive within their respective column using JqGrid?

Is there a way to design a grid with a unique column of radio buttons so that when a user clicks on this column in a specific row, only the radio button in that row is selected? This column will contain a vertical group of radio buttons. I am seeking a so ...

The icon on my page is not displaying, and the responsive menu is also not appearing

After tweaking the @media {} settings, I noticed that the icon displays properly when reduced, but disappears completely when fully covered with {}. Additionally, my responsive menu is not visible as expected. `@import url('https://fonts.googleap ...

My Discord bot seems to be malfunctioning and failing to send out

I am new to discord.js and I'm having trouble getting my bot to respond with a message when I send one on the server. The bot shows as online in Discord and "Logged in!" appears in the console when I run it, so client.on("ready") seems to be working f ...

Tips for patiently anticipating the resolution of a new promise

Searching for a way to ensure that a promise waits until a broadcast is fired, I came across some enlightening posts on this platform and decided to implement the technique detailed below. However, it appears that the broadcastPromise does not actually wai ...

Can Google AdWords track conversions on AJAX forms?

We have a situation where a client needs us to integrate their AdWord Conversion tracking code into a landing page after an enquiry form submission. The challenge is that the form operates using AJAX, so there isn't a traditional "landing page" per se ...

Ways to determine the specific content type within req.body?

Based on the information found at https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, it is stated that the body of a request can be one of the following types: ArrayBuffer Blob formData JSON text I am wondering if there is a way ...

How can I use the select2 jQuery plugin with the tags:true option to ensure that selected choices do not appear again in the dropdown menu?

Transitioning to select2 for tagging from a different plugin, I'm facing a gap that I need to address in select2's functionality. Let's consider an example. Suppose my list of choices (retrieved server-side via Ajax request) is: "Dog", "Ca ...

Certain browsers may not trigger the onsubmit event of an HTML form when a hidden submit button and readonly input are involved

Currently, I am in the process of creating a form that should trigger the onsubmit event when the "Enter" key on the keyboard is pressed. However, I have encountered an issue where the event does not fire on certain browsers, depending on the form fields p ...

Utilizing block buttons within a div containing a Bootstrap button group

My dilemma is trying to center a button group within a container while also making each button occupy half of the container's width. I've attempted using "w-50" and "btn-block," but they don't seem to work when in conjunction with "btn-group ...

The perpetual loop in React context triggered by a setState function within a useEffect block

I'm experiencing an endless loop issue with this context component once I uncomment a specific line. Even after completely isolating the component, the problem persists. This peculiar behavior only manifests when the row is discounted and the browser ...