Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.6k views
in Technique[技术] by (71.8m points)

javascript - Navbar TypeError: Cannot read property 'classList' of null

I am trying to implement a navbar to html which has the effect dynamically switch pages instead of changing links via href. The trick I'm using to accomplish this is by adding a classList of is-active to the div elements in the section tag.

Here is an example code of the generated HTML : navBar.js

const navbarItem = [
    {
        navitem : "About",
        link: 1
    },
    {
        navitem : "Legal",
        link: 2
    },
    {
        navitem : "Contact",
        link: 3
    }
];

window.onload = function navLoad() {
    const navbar = document.getElementById('navbar');
    navbar.innerHTML = 
    `
        <div class="toggle">
            <i class="fa fa-bars menu" aria-hidden="true"></i>
        </div>
        <ul class="nav-list">
            <li class="tab is-active">
                <a onclick="renderNav()">Home</a>
            </li>
            ${navbarItem.map(loadNavitems).join(" ")}
        </ul>
    `
}

function loadNavitems(navItems) {
    return `
            <li class="tab">
                <a data-switcher data-id="${navItems.link}" onclick="renderNav(); navSwap();">${navItems.navitem}</a>
            </li>
        `
}

function renderNav(){
    const pages = document.getElementById('main');
    document.getElementById('alphabetButtons').style.display = "block";
    pages.innerHTML = 
    `
        <section class="pages">
             ${navbarItem.map(item => `
                <div class="page" data-page="${item.link}">
                    <h1>${item.navitem}</h1>
                </div>
             `).join('')}
        </section>
    `
};

And here is the code which takes care of the page switching: navSwitcher.js

function navSwap() {
    const tab_switchers = document.querySelectorAll('[data-switcher]');

    for (let input of tab_switchers) {
        const page_id = input.dataset.switcher;
        console.log(page_id);
        input.addEventListener('click', function () {
            
            if(document.querySelector('.nav-list .tab.is-active')){
                document.querySelector('.nav-list .tab.is-active').classList.remove('is-active');
                console.log('removed'); 
            }
            if(input.parentNode.classList.contains('tab')){
                input.parentNode.classList.add('is-active');
            }
            //SwitchNav(page_id);
        });
    }
}

function SwitchNav(page_id) {
    const currentPage = document.querySelector('.pages .page');
    const next_page = document.querySelector(`.pages .page[data-page="${page_id}"]`);
    console.log(next_page);
    if(document.querySelector('.pages .page.is-active')){
        document.querySelector('.pages .page.is-active').classList.remove('is-active');
    }
    next_page.classList.add('is-active');
    
}

Update : The issue is that causes the error comes when attempting to place [data-page="${page_id}"] after .page inside the querySelector. When console logging, [data-page="${page_id}"] will return null. This is weird because data-page is named correctly in the renderNav function which holds the div of class page.

Hence my hypothesis now is that the issue comes from [data-page="${page_id}"] in the SwitchNav(page_id) function. My question is why is this occuring if everything is named correctly?

Fixes tried:

  • Attempted to change the for/of loop to a regular for loop inside the navSwap function.
  • Inside the navSwap function, const page_id = input.dataset.tab; was changed to const page_id = input.dataset.switcher; which now returns 3 items.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

So after some digging around, in the end it was actually const page_id = tab_switcher.dataset.tab; which was returning undefined, hence causing the error to happen. In reality it was returning id so I changed it to tab_switcher.dataset.id;.

Here is the final attempt at the code (i placed everything in one single file): navBar.js:

const navbarItem = [
    {
        navitem : "About",
        link: 1
    },
    {
        navitem : "Legal",
        link: 2
    },
    {
        navitem : "Contact",
        link: 3
    }
];

window.onload = function navLoad() {
    
    const navbar = document.getElementById('navbar');
    navbar.innerHTML = 
    `
        <div class="toggle">
            <i class="fa fa-bars menu" aria-hidden="true"></i>
        </div>
        <ul class="nav-list">
            <li class="tab is-active">
                <a onclick="renderNav()">Home</a>
            </li>
            ${navbarItem.map(loadNavitems).join(" ")}
        </ul>
    `
}

function loadNavitems(navItems) {
    return `
            <li class="tab">
                <a data-switcher data-id="${navItems.link}" onclick="renderNav(); navSwap();">${navItems.navitem}</a>
            </li>
        `
}

function renderNav(){
    const pages = document.getElementById('main');
    document.getElementById('alphabetButtons').style.display = "block";
    pages.innerHTML = 
    `
        <section class="pages">
             ${navbarItem.map(item => `
                <div class="page" data-page="${item.link}">
                    <h1>${item.navitem}</h1>
                </div>
             `).join('')}
        </section>
    `
};

function navSwap() {
    const tab_switchers = document.querySelectorAll('[data-switcher]');

    for (let i = 0; i < tab_switchers.length; i++) {
        const tab_switcher = tab_switchers[i];
        const page_id = tab_switcher.dataset.id;
        tab_switcher.addEventListener('click', function(){
            document.querySelector('.nav-list .tab.is-active').classList.remove('is-active');
            tab_switcher.parentNode.classList.add('is-active');
            SwitchNav(page_id);
        });
    }
}

function SwitchNav(page_id) {
    const currentPage = document.querySelector('.pages .page');
    const next_page = document.querySelector(`.pages .page[data-page="${page_id}"]`);
    console.log(next_page);
    if(document.querySelector('.pages .page.is-active')){
       currentPage.classList.remove('is-active');
    }
    if(document.querySelector('.pages .page')){
       next_page.classList.add('is-active');
    }
}

Although the code generates the intended results, I have to click twice on the tag to fire it's onclick event. If anybody knows why this occurs it would be of much help to know in the comments.

Also let me know if this is a viable fix. Thanks again :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...