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

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">Home</li>
<li role="presentation" class="nav-parent">Gallery</li>
<li role="presentation" class="nav-parent">About</li>
<li role="presentation" class="nav-parent">Contact</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!

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

Related

i need to delete target attribute from anchor if its value is null

For the sake of W3c validation i need to remove target attribute from all anchors where target value is null
i had following code inside body
<div>
home emput
home
home empty
home
</div>
Here is my script
$(document).ready(function () {
var target = []
var i = 0;
$("body a").each(function () {
target[i++] = $(this).attr("target");
if($(this).attr("target") == ""){
$(this).removeAttr("target");
}
});
console.log(target);
});
This code is working fine when I view console empty targets are removed. But when I view the source (Ctrl+u), targets are still there,
I just want to delete them.
Try this, its working
$(document).ready(function () {
var target = []
var i = 0;
$("body a").each(function () {
target = $(this).attr("target");
if(target == "")
{
$(this).removeAttr("target");
}
});
//console.log(target);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
home emput
home
home empty
home
</div>
As you are using "$", I assume you have jQuery
$("a[target='']").each(function() {
$(this).removeAttr("target");
});
https://jsfiddle.net/6g6t60pa/
try this to remove..
$('a[target=""]').removeAttr('target');
but you cannot achieve this while considering W3 Validation, it grabs page content without executing JS, so the best practice is to hide it using server side script(PHP).

Onload bootstrap tab trigger

The active class isn't working and I've tried body On-load click trigger and obviously show tab using id and many other ways, however nothing seems to be working. I have hashed the URL to enable tabs to be linked individually in the search. Any help is much appreciated.
JS: to hash the URL and jump to tab
// jump to tab if it exists
if (location.hash) {
$('a[href=' + location.hash + ']').tab('show');
}
// add tab hash to url to persist state
$(document.body).on("shown.bs.tab", function(e){
location.hash = e.target.hash;
});
});
JS: To go to tab home (not working)
$("document").ready(function(){
$("#home").trigger("click");
});
HTML:
<div class="col-xs-5 col-md-2 nopadding">
<nav class="nav-sidebar">
<ul class="nav tabs">
<li class="lead3">Home </li>
<li class="lead3">tab1</li>
<li class="lead3"><a href="#tab3" data-toggle="tab" >tab3</a></li>
<li class="lead3"> Contact </li>
</ul>
</nav>
tab-pane:
<div class="tab-pane active fade text-style" id="home"> . .. </div>
What you expect from this line?
$("home").trigger("click");
I suppose Jquery can't find element here $("home"). You could evaluate it in console for check.
if you are going to find element with class 'home' or id 'home' then you should use $(".home") or $("#home") properly.
It looks like your Document Ready event doesn't work.
Try remove the quotes around the $("document").
A shorter method for this event is as follows:
$(function() {
});
I know that this is very late but I'd like to post my solution since this was something that I was stuck on as well. There's an important subtlety that I think is easy to miss. You want to trigger the click on the <a> tag inside the nav, not the actual panel. Remember you click on the tab not on the panel to trigger it into view. So to get the correct tab to show when the user navigates to /my/path#home you want to bind on the hashchange event and click the correct element. See https://stackoverflow.com/a/680865/5262119 for more info on binding to the hashchange event.
$(window).bind('hashchange', function(event){
var hash = window.location.hash;
// get the actual anchor tag that links to the panel
var $matchingAnchor = $('nav a[href^="' + hash + '"');
if ($matchingAnchor) $matchingAnchor.click();
});
And assuming you want to restrict this to trigger only a certain page then you can add a location check:
$(window).bind('hashchange', function(event){
var path = window.location.pathname;
var hash = window.location.hash;
var $matchingAnchor = $('nav a[href^="' + hash + '"');
var contextRegex = /my\/page/;
var correctPage = contextRegex.test(path);
if (correctPage && $matchingAnchor) $matchingAnchor.click();
});
I imagine you also want to make sure that clicks on the tabs update the hash in the URL window so bind to the tabs event:
$('nav a').on('click',function() {
var $a = $(this);
var hash = $a.attr("href");
window.location.hash = hash;
});
This would go inside your ready function. You will also have to make sure that the function that triggers the click happens when the page first loads.
Complete solution:
$(document).ready(function() {
// Declare clickback function
function triggerTabClick() {
var path = window.location.pathname;
var hash = window.location.hash;
var $matchingAnchor = $('nav a[href^="' + hash + '"');
var contextRegex = /my\/page/; // or whatever you want this to be
var correctPage = contextRegex.test(path);
if (correctPage && $matchingAnchor) $matchingAnchor.click();
}
// Trigger it when the hash changes
$(window).bind('hashchange', triggerTabClick);
// Trigger it when the page loads
triggerTabClick();
// Hook into click for tabs to make sure hash is updated on click
$('nav a').on('click',function(event){
event.preventDefault();
var $a = $(this);
var hash = $a.attr("href");
var window.location.hash = hash;
})
})

How To Make Link on Parent Node Active in Tree View?

I want to make link on parent node active in tree view. So far I do this:
<li>A - Referensi Spasial <!--this is parent node-->
<ul>
<li>Jaring Kerangka Referensi Geodesi</li>
<li>Model Geoid
<ul>
<li>AB01010010</li>
<li>AB01010020</li>
</ul>
</li>
<li>Stasiun Pasang Surut</li>
</ul>
</li>
When I click the parent node, it just expand the children nodes. What I want is when I click it, it open the link I set on <a></a>
Here is my screenshot of my tree view:
And this is the javascript code:
$.fn.extend({
treed: function (o) {
var openedClass = 'glyphicon-minus-sign';
var closedClass = 'glyphicon-plus-sign';
if (typeof o != 'undefined'){
if (typeof o.openedClass != 'undefined'){
openedClass = o.openedClass;
}
if (typeof o.closedClass != 'undefined'){
closedClass = o.closedClass;
}
};
//initialize each of the top levels
var tree = $(this);
tree.addClass("tree");
tree.find('li').has("ul").each(function () {
var branch = $(this); //li with children ul
branch.prepend("<i class='indicator glyphicon " + closedClass + "'></i>");
branch.addClass('branch');
branch.on('click', function (e) {
if (this == e.target) {
var icon = $(this).children('i:first');
icon.toggleClass(openedClass + " " + closedClass);
$(this).children().children().toggle();
}
})
branch.children().children().toggle();
});
//fire event from the dynamically added icon
tree.find('.branch .indicator').each(function(){
$(this).on('click', function () {
$(this).closest('li').click();
});
});
//fire event to open branch if the li contains an anchor instead of text
tree.find('.branch>a').each(function () {
$(this).on('click', function (e) {
$(this).closest('li').click();
e.preventDefault();
});
});
//fire event to open branch if the li contains a button instead of text
tree.find('.branch>button').each(function () {
$(this).on('click', function (e) {
$(this).closest('li').click();
e.preventDefault();
});
});
}
});
//Initialization of treeviews
$('#tree1').treed();
So, how can I do that thing? Can anyone help me? Thanks
If my understanding is correct, you are asking why your links seem to have no effect at all, and clicking on them just expands the tree as if it were normal text?
It seems to me that this is simply due to the code that attaches events on those links, i.e. the block below comment "fire event to open branch if the li contains an anchor instead of text".
The $(this).closest('li').click(); instruction generates a new click event on the parent "li" item.
The e.preventDefault(); instruction prevents the link from receiving the "click" event, therefore it does not redirect the page / scroll to anchor.
So the result is as if the "click" had "jumped" your link and be passed to the parent "li", therefore not redirecting but expanding the tree.
You could simply remove that block to restore the links normal behaviour. However, the "click" event would still bubble to the parent "li" element, and expand the tree. Not an issue if the pages is redirected, but it is noticeable if the link goes to a local anchor (same page).
To prevent this (but still let the link do its normal job), keep the block but replace the 2 inner instructions by e.stopPropagation();. On the contrary of preventDefault(), it lets the current event happening, but it stops the event bubbling (parent elements do not receive it).
Now I am not sure about the reason for that block. It seems that it was more intended for anchors (which use the same "a" tag but with "name" attribute instead of "href"). But there would be no reason to prevent the "click" event on an anchor?

Cannot find where I have a popstate loop creating multiple history entries

I'm trying to create a single webpage that replaces the content of the main div when navigation links are clicked. I've been able to implement the pushstate function to replace the div content and change the url address pretty easily. I also am able to get the content to refresh when the back/forward buttons are clicked with the popstate function. However, now I click the first link and it works fine, I click the next link and it seems to apply 2 pushstates, the 3rd click, applies 3 pushstates, etc. It seems there is a push loop occurring somewhere but not sure where it is. I am in search of some advice on how to eliminate the multiple pushstates from occurring so they aren't duplicated in my history.
HTML code:
<nav id="headerNav">
<ul>
<li><button class="navButton" id="signIn" href="./content/signIn.php" name="reply" title="SignIn">Sign In</button></li>
<li><button class="navButton" id="signUp" href="./content/registration.php" name="registration" title="Registration">Sign Up</button></li>
<li><button class="navButton" id="about" href="./content/about.php" name="settings" title="About">About</button></li>
</ul>
</nav>
<section id="mainContent">
<!-- CONTENT PAGES REPLACE HERE -->
<?php
include ('./content/start.php');
?>
</section>
Javascript
$(document).ready(function() {
if (window.history && history.pushState) {
$(".navButton").click(function(e) {
e.preventDefault();
$("#mainContent").fadeOut().load($(this).attr("href")).fadeIn();
history.pushState(null, $(this).attr("title"), $(this).attr("name"));
});
}
});
window.addEventListener('popstate', function() {
//WHEN BACK/FORWARD CLICKED CHECKS URL PATHNAME TO DETERMINE WHICH CONTENT TO PLACE IN DIV
if (location.pathname == "/index.php") {
$("#mainContent").load("./content/start.php");
} else {
$("#mainContent").load("./content" + location.pathname + ".php");
}
});
SOLVED! It was my "if" condition to test for the history API. When I removed that it eliminated the repeated history pushes. I also have my htaccess file redirecting all typed in urls to the index page that allows the pathname comparison to fire for the content. Works great but I know I'll have to address the bookmarking IF later as the site grows. For now, it functions the way I need it to so I can move forward!
window.onload = function() {
// PUSHES CORRECT CONTENT DEPENDING ON URL PATH - ENSURES BACK/FORWARD AND BOOKMARKS WORK
if (location.pathname == "/index2.php") {
$("#mainContent").load("./content/start.php");
} else {
$("#mainContent").load("./content" + location.pathname + ".php");
}
// EVEN HANDLER TO DETECT CLICK OF NAVBUTTON CLASS
$(".navButton").click(function(e) {
$(this).addClass("active");
$(".navButton").not(this).removeClass("active");
var $mainContent = $("#mainContent");
var $href = $(this).attr("href");
var $title = $(this).attr("title");
var $name = $(this).attr("name");
// REPLACES CONTENT WITH DYNAMIC TRANSITION
$mainContent.fadeOut(100, function() {
$mainContent.load($href, function() {
$mainContent.fadeIn(100);
});
});
//CHANGES DOCUMENT TITLE SINCE PUSHSTATE CAN'T DO THIS YET
document.title = $title;
// PUSHES URL CHANGE AND HISTORY STATE TO BROWSER
history.pushState('', $title, $name);
//PREVENTS DEFAULT ACTION OF NAVBUTTON
e.preventDefault();
});
// THIS EVENT MAKES SURE THAT THE BACK/FORWARD BUTTONS WORK AS WELL
window.onpopstate = function(event) {
if (location.pathname == "/index2.php") {
$("#mainContent").load("./content/start.php");
} else {
$("#mainContent").load("./content" + location.pathname + ".php");
}
};
};

form action url change depending on #tag

Is it possible to change a forms action Url with jQuery/js depending on a browser #tag?
The tabs are working correctly I just need the action to change as well.
Here is the tab js I am currently using, I am also using the jQuery Address Plugin also:
var QTABS = {
init: function () {
// attached onload and change event to address plugin
$.address.init(function(event) {
// first load, set panel
QTABS.setPanel(event);
}).change(function(event) {
// if the url changes, set panel
QTABS.setPanel(event);
});
},
// the core function to display correct panel
setPanel: function (event) {
// grab the hash tag from address plugin event
var hashtag = event.pathNames[0];
// get the correct tab item, if no hashtag, get the first tab item
var tab = (hashtag) ? $('.tabs li a[href=#' + hashtag + ']') : $('.tabs li:first a');
// reset everything to default
$('.tabs li').removeClass('activeTab');
$('.tab_container .tab_content').hide();
// if hashtag is found
if (hashtag) {
// set current tab item active and display correct panel
tab.parent().addClass('activeTab');
$('.tab_container .tab_content:eq(' + (tab.parent().index()) + ')').show();
} else {
// set the first tab item and first panel
$('.tabs li:first').addClass('activeTab');
$('.tab_container .tab_content:first').show();
}
if ($('.tabs').length)
{
// change the page title to current selected tab
document.title = tab.attr('title');
}
}
}
// Execute this script!
QTABS.init();
This is what i ahve used successfully
$("#myDelete").click(function(){
$('#myForm').attr("action", "accounttrandelete.php");
$("#myForm").submit();
return false;
});
$("#myEdit").click(function(){
$('#myForm').attr("action", "accounttranedit.php");
$("#myForm").submit();
return false;
});
$("#myRec").click(function(){
$('#myForm').attr("action", "accounttranrec.php");
$("#myForm").submit();
return false;
});
$("#myUnRec").click(function(){
$('#myForm').attr("action", "accounttranunrec.php");
$("#myForm").submit();
return false;
});
Because I don't know where the form is and how you want to access it. If you want change the action url to do this:
$("form").attr("action", "Put your new Url here");
UPDATE:
$("#tag")..attr("action", "Put your new Url here");
If you want to use standard Javascript you can change as follow:
document.forms[0].action = "Put your new Url here";
Note: you can replace forms[0] by the name of your form.
UPDATE:
If you have a form with an id then its similar to above method call:
document.getElementById("tag").action = "Put your new Url here";

Categories

Resources