Navigate between tabs with a single click

Hey there! I'm having trouble putting together a webpage that features a sidebar. I want to make it so that clicking on one of the links at the top will switch the tab and its content accordingly. However, the current code I have isn't working and I keep encountering this error:

Uncaught TypeError: Cannot read properties of null (reading 'click')

Below is the code I've been working with. Any help is greatly appreciated!:


                        // JavaScript code goes here
                    
                

                        /* CSS code goes here */
                    
                

Answer №1

I managed to resolve this issue and I hope it aligns with your expectations. First, make corrections to your CSS code:

  • Add the class tab-button-active to your CSS code to activate the link when clicked:

    .tab-button-active { color: var(--c-accent-primary) !important; border-bottom: 3px solid var(--c-accent-primary) !important; }

  • Update your CSS code for content and code activation. This code will hide when not active and show with display: flex !important when active, as shown below:

    .content {
        border-top: 1px solid var(--c-border-primary);
        margin-top: 2rem;
        display: none;
      }
    

    .content-active { display: flex !important; }

Secondly, rectify some errors in the JavaScript code:

  • You should swap querySelector with querySelectorAll to select all elements with your query. Below are the corrected lines of code:

    menuBar.querySelectorAll(".tab-button").forEach(link => {
                  link.classList.remove("tabs-button-active");
              })
    
              tabsContainer.querySelectorAll(".content").forEach(tab => {
                  tab.classList.remove("content-active");
              })
    
  • Correct some spelling mistakes: "tab-button-active" is the class name you add when active, not "tabs-button-active". Use the corrected line of code below:

     link.classList.remove("tabs-button-active");
    
  • The tabsContainer does not contain tab-button so you can't use querySelector on this. Below is the corrected code:

    document.addEventListener("DOMContentLoaded", () => { switchTabs();

    document.querySelectorAll(".content").forEach(tabsContainer => {
    
      document.querySelector(".horizontal-tabs .tab-button").click()
    })
    

    });

Here is the modified code, I hope it proves useful:

function switchTabs() {
  document.querySelectorAll(".tab-button").forEach(link => {

link.addEventListener("click", () => {
  const menuBar = link.parentElement;
  const tabsContainer = menuBar.parentElement;
  const tabNumber = link.dataset.forTab;
const tabToActivate = tabsContainer.querySelector(`[data-tab="${tabNumber}"]`)



  menuBar.querySelectorAll(".tab-button").forEach(link => {

    link.classList.remove("tab-button-active");
  })

  tabsContainer.querySelectorAll(".content").forEach(tab => {
    tab.classList.remove("content-active");
  })
  link.classList.add("tab-button-active");
 
  tabToActivate.classList.add("content-active");
});
  });
}

document.addEventListener("DOMContentLoaded", () => {
  switchTabs();

  document.querySelectorAll(".content").forEach(tabsContainer => {

document.querySelector(".horizontal-tabs .tab-button").click()
  })
});
   @import url("https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
:root {
  --c-text-primary: #282a32;
  --c-text-secondary: #686b87;
  --c-text-action: #404089;
...
html::-webkit-scrollbar-thumb {
  background-color: var(--c-text-primary);
  border: 4px solid var(--c-background-primary);
  border-radius: 99em;
}

Answer №2

An issue has been identified:

document.querySelectorAll(".content").forEach(tabsContainer => {
  console.log(tabsContainer);
  tabsContainer.querySelector(".horizontal-tabs .tab-button").click();
})

The class horizontal-tabs does not exist within your content class.

Therefore, when attempting to select

tabsContainer.querySelector(".horizontal-tabs .tab-button")
, a null element is returned.

If you are unsure of the elements you are selecting, it is recommended to print them to the console for clarification.

Answer №3

I completed the task by resolving all errors that were encountered.

One minor issue I noticed was that the strong element was not properly closed:

<!-- old code -->
<a style="font-size: 45px; color: #A388E7;" class="navbar-brand" href="#"><strong>StudioPick</a>
<!-- new code -->
<a style="font-size: 45px; color: #A388E7;" class="navbar-brand" href="#"><strong>StudioPick</strong></a>

It's important to use querySelectorAll instead of querySelector if you plan to iterate over elements using forEach since querySelector only returns a single element:

//old code
menuBar.querySelector(".tab-button").forEach(link => {
      link.classList.remove("tabs-button-active");
})

tabsContainer.querySelector(".content").forEach(tab => {
      tab.classList.remove("content-active");
})

//new code
menuBar.querySelectorAll(".tab-button").forEach(link => {
      link.classList.remove("tabs-button-active");
})

tabsContainer.querySelectorAll(".content").forEach(tab => {
      tab.classList.remove("content-active");
})

Instead of using tabsContainer, it would be more appropriate to use document in the following scenario, as tabsContainer does not contain any horizontal-tabs, which might cause the null issue you mentioned initially:

//old code
document.querySelectorAll(".content").forEach(tabsContainer => {
    tabsContainer.querySelector(".horizontal-tabs .tab-button").click();
})

//new code
document.querySelectorAll(".content").forEach(tabsContainer => {
    document.querySelector(".horizontal-tabs .tab-button").click();
})

Here is the corrected and fixed code:

function switchTabs(){
document.querySelectorAll(".tab-button").forEach((link) => {
    link.addEventListener("click", () => {
        const menuBar = link.parentElement;
        const tabsContainer = menuBar.parentElement;
        const tabNumber = link.dataset.forTab;
        const tabToActivate = tabsContainer.querySelector(`.content[data-tab="${tabNumber}"]`);

        menuBar.querySelectorAll(".tab-button").forEach(link => {
            link.classList.remove("tabs-button-active");
        })

        tabsContainer.querySelectorAll(".content").forEach(tab => {
            tab.classList.remove("content-active");
        })

        link.classList.add(".tab-button-active");
        tabToActivate.classList.add(".content-active");
    });
});
}

document.addEventListener("DOMContentLoaded", () => {
switchTabs();

document.querySelectorAll(".content").forEach(tabsContainer => {
    document.querySelector(".horizontal-tabs .tab-button").click();
})
});
@import url("https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
:root {
  --c-text-primary: #282a32;
  --c-text-secondary: #686b87;
  --c-text-action: #404089;
  --c-accent-primary: #434ce8;
  --c-border-primary: #eff1f6;
  --c-background-primary: #ffffff;
  --c-background-secondary: #fdfcff;
  --c-background-tertiary: #ecf3fe;
  --c-background-quaternary: #e9ecf4;
}
  ... (styling removed for brevity) ...

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

Issue with Bootstrap carousel: image protrudes past boundaries of parent container

Struggling with setting up a bootstrap carousel on my page. I want the image to extend beyond the parent div, positioned at the bottom rather than the top. How can I achieve this without disrupting the default carousel behavior? Here's a sketch of how ...

Is it possible to include multiple spyObjs within a beforeEach block?

In the process of testing an Angular 1 application using Jasmine, I have encountered a dilemma. My question is, can two spies be created for two different services within the same beforeEach statement? Currently, I have managed to make the first spy work ...

The upload directory in KCFinder can be accessed and selected using a URL

Issue: While using the link to open kcfinder as defined in kcfinder, I encountered a problem. The link is intended to open kcfinder with the provided parameters: window.open('/kcfinder/browse.php?type=files&dir=files/public&subDi ...

My API is feeding data to the Material UI CardMedia image

Has anyone encountered a similar error while using the CardMedia API provided by Material-UI? I am currently utilizing the Card & CardMedia components from material-ui to display data fetched from an api. However, I am facing difficulty in displaying ...

"encountered net::ERR_NAME_NOT_RESOLVED error when trying to upload image to s3 storage

I am currently developing an application using Angular. I have been attempting to upload a picture to my S3 bucket, but each time I try, I encounter this error in the console. https://i.stack.imgur.com/qn3AD.png Below is the code snippet from my upload.s ...

Unset the class upon clicking outside the div, but maintain the class unset when the div is closed

I have a div that opens when the question mark icon in the upper right corner of the document is clicked. When clicked, a class is added which transforms the question mark into a close icon. When clicking outside the div, the div closes and the class is re ...

Utilizing AJAX to integrate the Google Maps Direction API

Currently, I am developing a small website that utilizes the Google Maps API and AJAX to load directions based on selected locations from a dropdown menu. The database stores latitude and longitude coordinates of various locations, which are retrieved via ...

Prevent unnecessary clicks with Vue.js

In my vue.js application, there is a feature to remove items. The following code snippet shows the div element: <div class="ride-delete" @click="delete"> <p>Delete</p> </div> This is the function used to handle the click ...

What is the best way to automatically add a date and timestamp to every new entry?

I am currently working on a project that utilizes AngularJS and Ionic frameworks. The main feature of the project will involve users inputting data to create a list, and allowing any user to comment on each item in the list. One challenge I have encounter ...

Just starting out with Angular - facing issues with setting up in eclipse

I'm attempting to create a test Angular project in Eclipse by copying the three files from the Angular website https://docs.angularjs.org/api/ng/directive/ngController into my Eclipse project. I initially created it as a static web project and then co ...

Trouble keeping HTML/Javascript/CSS Collapsible Menu closed after refreshing the page

My issue is that the collapsible menu I have created does not remain closed when the page is refreshed. Upon reloading the page, the collapsible menu is always fully expanded, even if it was collapsed before the refresh. This creates a problem as there is ...

Integrating additional JavaScript into an Ionic 2 project

Imagine we have a foo.js file containing a variable, function, and class that are not yet part of the project. Now suppose we want to access these elements in our home.ts method or make them globally available for use within a home.ts method. How can this ...

What's the best way to capture an element screenshot using JavaScript?

I'm working on developing a unique gradient selection application. One of the exciting features I would like to incorporate is the ability for users to save their chosen gradients as digital images (.jpg format) directly onto their computers. When the ...

Nested loops combined with a timeout occasionally results in failure

I encountered a problem with the loops and timeouts in my script that I created for practice. If you want to take a look at the script, you can find it here: http://codepen.io/JulienBarreira/pen/EWNoxJ When running the script, I noticed that sometimes one ...

What is causing Safari to block styling for <em> elements in RESET.CSS only?

I am utilizing Eric Meyer's reset.css file, which can be found at this link: Interestingly, my <em> definition in my main stylesheet is working perfectly fine on all browsers except Safari. Somehow, only in Safari, the styling for italics is no ...

Guide on utilizing multiple ng-apps alongside multiple controllers

Having trouble accessing controller values in different ng-apps? Here's a setup with two ng-apps and their controllers, where you may encounter errors when trying to access the value of one controller in another. Need some assistance with this issue. ...

Modifying pagination numbers with Reactjs: A step-by-step guide

I am currently working on Reactjs (nextjs) and I have successfully integrated the "Nextjs" framework. The pagination is working fine, but the buttons are displaying as "1,2,3,20" instead of "1,2...20" (showing all numbers without using "..."). How can I mo ...

Forming triangles with outlines

Recently, I had the challenge of designing speech bubbles and found a clever technique to create the triangular tip at the end using CSS. By setting the element's width and height to 0 and playing around with borders, you can achieve diagonal shapes f ...

Is it possible to transfer a Mongo connection to JQuery code using socket.io?

I'm currently working on setting up a global MongoDB connection in my node.js web app. Here is what I have so far: var MongoClient = require('mongodb').MongoClient; var mconn = null; MongoClient.connect('mongodb://myHost:27017/users&a ...

jPlayer calculates the "duration" as 1,440 minutes on iOs devices for all mp3 files

My homemade webpage is designed for playing mp3s and viewing pdfs. I'm using jPlayer v 2.9.2 to play the mp3s, which works fine on PC but encounters issues on iPhone. The duration values are incorrect, showing "1439:59" remaining for all files, causin ...