Villi Magg
Villi Magg

Reputation: 1193

DOM/Page not updating but console.log shows updated value

I'm doing an SPA from scratch and so far I've gotten everything working except the active state off the navigation links will not update according to where user is navigating to.

The funny thing is that when I open up the Developer Tools in Chrome, under "Elements" the DOM is still showing the active class on the original nav element, but under "Console", when I console.log the element, it shows that the class has been removed.

I've tried event.stopPropagation() in a few places and the jQuery.off() function but nothing seems to fix this problem.

Problem: The class list of the active and the former active link doesn't update when clicking on a navigation link, but the console.log function does show an updated classlist off the former active link

Desired Behaviour: That the former active link losses its active class and that the currently active link gets an active class after its navigation link has been clicked and the page renders the new content(the supposedly new page).

UPDATE 1: Updated the code according to suggestions and it got the first part of my problem working. Removing active class from all li elements now works, but making the page render the updated links with active class on currently active link after navigation does not work. See in app.js under generateView() function.

UPDATE 2: Got it working. See on the bottom of this Question. Thank you!

My app.js

(function ($, hbs){

'use strict';

// declare some usefull variables to use throughout the app
var
    doc = document,
    oldPath = '',
    newPath = '',
    navParentEl = '';


// 1: Manually trigger a hashchange to start the app.
window.onload = function (e) {
    $(window).trigger('hashchange');
};

// 2: Catch clicks on the root-level element for anchor tag clicks.
doc.body.addEventListener('click', function (e) {
    //e.stopPropagation();
    var tag = e.target;

    // check element clicket
    if (tag.tagName === 'A' && tag.href && e.button === 0) {
        // it's a left-click on an anchor. Lets navigate!
        if (tag.origin === window.location.origin) {
            // prevent the page from navigating

            e.preventDefault();

            // it's a link within the site, HURRAY!
            oldPath = window.location;
            newPath = tag.href,
            navParentEl = tag.parentElement;

            console.log(navParentEl);

            // Update the URL bar! IMPORTANT!
            // @TODO: MOVE INTO A FUNCTION OR OBJECT
            window.history.pushState(null, '', newPath);
            render(window.location.hash, data, e);
        }
    }
});

// register Handlebars partials
hbs.registerPartial({
    'header': hbs.templates.header,
    'footer': hbs.templates.footer
});

$(window).on('hashchange', function (e) {
    // On every hash change the render function is called with the new hash.
    render(window.location.hash, data, e);
});

function render(url, data, evt) {
    var temp = url.split('/')[0];

    // Hide current page
    $('.pages').addClass('hidden');

    // remove anchors .active class
    //$('.nav-parent').removeClass('active');

    var map = {
        '': function (data) {
            renderPage('home', data);
        },
        '#home': function (data) {
            renderPage('home', data);
        },
        '#gallery': function (data) {
            renderPage('gallery', data);
        },
        '#about': function (data) {
            renderPage('about', data);
        }
    };

    if (map[temp]) {
        map[temp](data);
    } else {
        renderErrorPage(data);
    }
}

function renderPage(page, data) {
    var tpl = hbs.templates[page](data);
    generateView(tpl, page);
}

function renderErrorPage(data) {
    renderPage('error', data);
}

function generateView(tpl, page) {
    var pageId = '#' + page;

    $(pageId).removeClass('hidden');
    $('.container').html(tpl);

    // this works for removing the active class from all li elements
    $('.nav-parent').removeClass('active');

    // add .active class to the new active anchor element
    // does not work
    $(navParentEl).addClass('active');

}

})(jQuery, Handlebars);

My navigation HTML:

<div class="header clearfix">
    <nav>
        <ul class="nav nav-pills pull-right">
            <li role="presentation" class="nav-parent active"><a href="#home" class="links">Home</a></li>
            <li role="presentation" class="nav-parent"><a href="#gallery" class="links">Gallery</a></li>
            <li role="presentation" class="nav-parent"><a href="#about" class="links">About</a></li>
            <li role="presentation" class="nav-parent"><a href="#contact" class="links">Contact</a></li>
        </ul>
    </nav>
    <h3 class="text-muted">{{ projectName }}</h3>
</div>

UPDATE 2: Got it working after some tips. I needed to re-think my generateView() function. Here's the final code for that function:

function generateView(tpl, page) {
    var pageId = '#' + page;

    // remove hidden class from content to be shown
    $(pageId).removeClass('hidden');
    // add the template to the html
    $('.container').html(tpl);
    // move the active class from the former active link
    $('.nav-parent').removeClass('active');

    // get the current hash of the location
    var newHash = window.location.hash,
        // get all links
        _links = document.querySelectorAll('.links'),
        currentActiveLink = '';

    // iterate over the _links object and find the link with href === newHash
    for ( var i = 0; i < _links.length; i++ ) {
        if ( _links[i].getAttribute('href') === newHash ) {
            // store the link with href == newHash 
            // inside the currentActiveLink variable
            currentActiveLink = _links[i];
        }
    }

    // add active class to current active link
    currentActiveLink.parentElement.classList.add('active');
}

Thank you!

Upvotes: 1

Views: 1960

Answers (1)

Gonzi
Gonzi

Reputation: 87

isnt it possible that you redraw your navigation? didnt really go through your code but it took me a looong time to discover that in my SPI. I changed some params, but I also ajax-loaded those elements wit default serverside properties... EDIT: yea I can see that happening in your app

Upvotes: 1

Related Questions