pushState Executing When Not Supposed To - javascript

I am using the HTML history API to manipulate the browser history stack to control navigation using JavaScript on my site. The function I have set up to change pages is working fine, but weirdly, when I added pushState to each individual page change, the pushState fires automatically, so that the last page change in the function is always the final one executed. This means the state being pushed is always the last page change statement.
The JavaScript:
// Change Page Function
function ChangeContent (page) {
var pages={"homepage":{title: "homepage"},"servicespage":{title: "servicespage"},"estimatespage":{title: "estimatespage"}};
HideNav();
//Show home page
for(var homepage in pages) {
if(page!==homepage) {
document.getElementById(homepage).style.display='none';
}
else {
document.getElementById(homepage).style.display='block';
history.pushState("homepage", "Home", "home" );
window.scrollTo(0,0);
}
}
//Show services page
for(var servicespage in pages) {
if(page!==servicespage) {
document.getElementById(servicespage).style.display='none';
}
else {
document.getElementById(servicespage).style.display='block';
history.pushState( "servicespage", "Our Services", "services");
window.scrollTo(0,0);
}
}
//Show estimates page
for(var estimatespage in pages) {
if(page!==estimatespage) {
document.getElementById(estimatespage).style.display='none';
}
else {
document.getElementById(estimatespage).style.display='block';
history.pushState( "estimatespage", "Get An Estimate", "estimates");
window.scrollTo(0,0);
}
}
}
When you run this code, instead of each individual page pushing it's state when that page is clicked, the state getting pushed is always the estimates page state. I've tried using else if statements instead, and I've tried embedding each for statement into self executing functions in the hope that it might solve a scope issue of some kind, but I've had no luck.
This is my onPopstate function:
// History State Change Display
window.onpopstate = function (event) {
var state = event.state;
console.log(state);
// Change History State Display To Home Page
if (state === "homepage") {
document.getElementById("homepage").style.display = 'block';
} else {
document.getElementById("homepage").style.display = 'none';
}
// Change History State Display To Services Page
if (state === "servicespage") {
document.getElementById("servicespage").style.display = 'block';
} else {
document.getElementById("servicespage").style.display = 'none';
}
// Change History State Display To Estimates Page
if (state === "estimatespage") {
document.getElementById("estimatespage").style.display = 'block';
} else {
document.getElementById("estimatespage").style.display = 'none';
}
};
For some reason each new page I click on has the URL extensions /estimatespage and then when I click the back button, it just cycles through the pages in reverse order in which they were written in the page change function, and properly updates the URL.
I'm not totally sure what the issue here is, but I think I'm pushing the state of all the pages automatically, which is weird, since the rest of the code is only executing when the proper page is selected.
Any help would be appreciated, as I think this is probably more obvious than I'm making it out to be.
HTML
<div id="nav">
<div class="headerlist" onclick="ChangeContent('homepage');">Home</div>
<div class="headerlist" onclick="ChangeContent('servicespage');">Services</div>
<div class="headerlist" onclick="ChangeContent('estimatespage');">Estimates</div>
</div>
<div id=homepage></div>
<div id=servicespage></div>
<div id=estimatespage></div>

You have three for loops in ChangeContent(). All three loops are testing for exactly the same condition -- merely with a renamed variable.
Keeping the style vaguely the same, you might try this instead, note that this single loop is to replace all three of those loops in ChangeContent():
for ( var p in pages ) {
if ( page !== p ) {
document.getElementById( p ).style.display = 'none';
}
else {
document.getElementById( p ).style.display = 'block';
if ( p === "homepage" )
history.pushState( "homepage", "Home", "home" );
else if ( p === "servicespage" )
history.pushState( "servicespage", "Our Services", "services");
else if ( p === "estimatespage" )
history.pushState( "estimatespage", "Get An Estimate", "estimates");
window.scrollTo( 0, 0 );
}
}

Related

Move color of an HTML element to another page

Good evening,
i was working on a part of what i hope will be my future website and i wanted to add a "photograpy" section to it, and here comes the problem.
since the title in the main page constatly changes color, i'd like to grab its current color to transfer it to the title of the other page to play an animation later on.
the problem is that when i press the related button, i am taken to the photograpy page, but the title remains black.
i've tried seraching for help on google but i haven't been able to find much.
here is the JS
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
loaded();
});
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function() {
loaded();
});
}
function loaded() {
document.getElementById("PHtitle").style.color === titlecolor;
}
function script() {
const titlecolor = document.getElementById("title").style.color;
};
document.getElementById('photograpy').onclick = function () {
script();
};
The snippets don't allow for localStorage, so here is just the javascript.
First, I let the variables outside of a function. The titleColor function checks to see if titleColor was saved in localStorage, if not the default color is black.
Then I set the color of the phtitle to the contents of titleColor variable.
In the script function, I set the localStorage variable to the getComputedStyle color of the title.
Then last I use an event listener on the button to run the script for saving the color.
LocalStorage is a way to store data in the user's browser until they close their browser/clear their data etc.. Which will allow it to be usable on different pages then where it was saved.
let titleColor = localStorage.getItem("titleColor") || "#000000";
let PHtitle = document.querySelector("#PHtitle");
let title = document.querySelector("#title");
let btn = document.querySelector("#photography");
if(PHtitle){
PHtitle.style.color = titleColor;
}
function script() {
localStorage.setItem("titleColor", getComputedStyle(title).color)
}
if(btn && title){
btn.addEventListener("click", function() {
script();
})
}

History API does not apply history changes until the user performs any actions on the page

There is a site page on which you need to implement routing using the history of API.
This page can be accessed as follows:
transition from a blank page,
transition from another page (external / internal),
return using the browser button Back,
routing the page inside using the open / close buttons.
Routing example:
site.com/typical-page/routing-page-level1/routing-page-level2/routing-page-level3/other-typical-page
typical-page, other-typical-page - pages without routing
routing-page-level1, routing-page-level2, routing-page-level3 - a page with routing.
Inside the page it works fine I go to the page with routing:
site.com/typical-page/routing-page-level1/
I click on the button level2, go to:
site.com/typical-page/routing-page-level1/routing-page-level2/
level3, go to:
site.com/typical-page/routing-page-level1/routing-page-level2/routing-page-level3
I click Close on the page or the BACK button in the browser I go
site.com/typical-page/routing-page-level1/routing-page-level2/
I click Close again on the page or the BACK button in the browser I go
site.com/typical-page/routing-page-level1/
If I immediately go to site.com/typical-page/routing-page-level1/routing-page-level2/routing-page-level3 from a blank page, and then click BACK in the browser, I return to a blank page.
But, if from a blank page I immediately go to site.com/typical-page/routing-page-level1/routing-page-level2/routing-page-level3, then I click anywhere on the page and then click BACK in the browser , then I’m going to site.com/typical-page/routing-page-level1/routing-page-level2, if again, then
at site.com/typical-page/routing-page-level1.
I understand that the browser does not apply history changes until the user performs any actions on the page. For example, click.
How can this be avoided?
This article was used as a sample JS - window.history - Delete a state
This is pseudo code.
let guideHistory = ['init'];
let flag;
history.pushState({state: '/guide'}, '', '/guide');
// User came from blank page
if (!history.state) {
setTimeout(() => {
flag = true;
history.replaceState({state: '/routing-page-level1'}, '', '/routing-page-level1');
level2.trigger('click');
}, 20);
}
// User came from other page
if (history.state) {
flag = true;
level2Click(level2);
}
level2.on('click', level2Click);
level3.on('click', level3Click);
function level2Click() {
addHistory(level2.attr("data-path"));
if (flag)) {
setTimeout(() => {
level3.trigger('click');
}, 30) ;
}
function addHistory(historyState, historyPath) {
if (guideHistory[0] === 'init'){
guideHistory.pop();
}
if (historyPath) {
guideHistory.push('/routing-page-level1' + '/' + historyPath);
}
else {
guideHistory.push('/routing-page-level1');
}
history.replaceState({state: historyState}, '', '/routing-page-level1/' + historyState);
}
}
function level3Click(event) {
setTimeout(() => {
addHistory(level3, level2));
}, 0);
}
window.onpopstate = function() {
if (guideHistory[0] !== 'init') {
if (!guideHistory.length) {
history.go(-1);
}
else {
pushHistory(guideHistory);
function pushHistory(guideHistory) {
let pop = guideHistory.pop();
history.pushState({state: pop}, '', pop);
}
}
}
};
Thanks!

JS: Erroneous popstate event when trying to navigate back past the initial page load

I'm trying to implement JS history using pushState/popState. Navigating back and forward works just fine, but I have trouble navigating before the initial page load using the browser's back button. It needs 1 extra hit on the browser's back button to leave the page. Why is that?
function action(text) {
history.pushState({"text":text}, text);
doAction(text);
}
function doAction(text) {
$('span').text(text);
}
var $button = $('button');
var $p = $('p');
$p.hide();
action("foo");
$button.on('click', function(){
action("bar");
$button.hide();
$p.show();
})
window.addEventListener("popstate", function(e) {
if (e.state !== null) {
$button.show();
$p.text("Next back should navigate away from this page");
} else {
$p.text("Still here? Why is that? Next back will really navigate away");
}
});
https://jsfiddle.net/lilalinux/p8ewyjr9/20/
Edit: Tested with Chrome OS/X
The initial page load shouldn't use history.pushState because it would add another history entry. There is alredy an implicit first history item with state null.
Using history.replaceState for the initial page load, sets a state for that item but doesn't add another one.
var initialPageLoad = true;
function action(text) {
if (initialPageLoad) {
// replace the state of the first (implicit) item
history.replaceState({"text":text}, text);
} else {
// add new history item
history.pushState({"text":text}, text);
}
initialPageLoad = false;
doAction(text);
}
function doAction(text) {
$('span').text(text);
}
var $button = $('button');
var $p = $('p');
$p.hide();
action("foo");
$button.on('click', function(){
action("bar");
$button.hide();
$p.show();
})
window.addEventListener("popstate", function(e) {
if (e.state !== null) {
$button.show();
$p.text("Next back should navigate away from this page");
// } else {
// won't happen anymore, as the first item has state now
// $p.text("Still here? Why is that? Next back will really navigate away");
}
});

how to avoid flicker when two events are fired

I have written a code where I have configured the OnPageShow(event) for checking if the page is from cache. If the page is from cache, I reload the same page for hitting the server. But while doing this, there is a screen flickering issue. The reason is When I click the browser back button, first the page from cache loads and is displayed, and then after complete loading it goes in the OnPageShow method which again refreshes the page. Is there any way to avoid the flickering issue ?
Here is the code:
function RefreshloadWindow()
{
if(!(window.performance && window.performance.navigation.type == 2))
{
console.log("In On Load");
GetLatestBreadcrum();
}
}
function GetLatestBreadcrum()
{
console.log("In Breadcrum function");
var matches=[];
var divElements=document.getElementById("breadCrumDiv").children;
console.log(divElements);
var j=0;
for(i=0;i<divElements.length;i++)
{
//console.log(divElements[i].tagName);
if(divElements[i].tagName=="A")
{
matches[j]=divElements[i];
j++;
}
}
for(z=0;z<matches.length;z++)
{
console.log(matches[z]);
}
var lastElement=matches.length;
//matches[lastElement-1].click();
window.name=matches[lastElement-1];
console.log(window.name);
}
function IsPagePersisted(event)
{
if(event.persisted || window.performance && window.performance.navigation.type == 2)
{
//console.log("From Cache 2");
var iLink=document.createElement('A');
iLink.href=window.name;
GetLatestBreadcrum();
iLink.click();
}
}
And Body tag is as follow:
<body onpageshow="IsPagePersisted(event)" onload="RefreshloadWindow()" >
If you do not want to show the page initially you can add
"display: none;" to the body tag and then remove that style after the reload.

javascript html5 history, variable initialization and popState

main question
Is there a javascript way to identify if we are accessing a page for the first time or it is a cause of a back?
My problem
I'm implementing html5 navigation in my ajax driven webpage.
On the main script, I initialize a variable with some values.
<script>
var awnsers=[];
process(awnsers);
<script>
Process(awnsers) will update the view according to the given awnsers, using ajax.
In the funciton that calls ajax, and replaces the view, I store the history
history.pushState(state, "", "");
I defined the popstate also, where I restore the view according to the back. Moreover, I modify the global variable awnsers for the old value.
function popState(event) {
if (event.state) {
state = event.state;
awnsers=state.awnsers;
updateView(state.view);
}
}
Navigation (back and forth) goes corectly except when I go to an external page, and press back (arrving to my page again).
As we are accessing the page, first, the main script is called,the valiable awnsers is updated, and the ajax starts. Meanwile, the pop state event is called, and updates the view. After that the main ajax ends, and updates the view according to empty values.
So I need the code:
<script>
var awnsers=[];
process(awnsers);
<script>
only be called when the user enters the page but NOT when it is a back. Any way to do this?
THanks!
Possible solution
After the first awnser I have thought of a possible solution. Tested and works, whoever, I don't know if there is any cleaner solution. I add the changes that I've done.
First I add:
$(function() {
justLoaded=true;
});
then I modify the popState function, so that is in charge to initialize the variables
function popState(event) {
if (event.state) {
state = event.state;
awnsers=state.awnsers;
updateView(state.view);
} else if(justLoaded){
awnsers=[];
process(awnsers);
}
justLoaded=false;
}
Thats all.
what about using a global variable?
var hasLoaded = false;
// this function can be called by dom ready or window load
function onPageLoad() {
hasLoaded = true;
}
// this function is called when you user presses browser back button and they are still on your page
function onBack() {
if (hasLoaded) {
// came by back button and page was loaded
}
else {
// page wasn't loaded. this is first visit of the page
}
}
Use cookie to store the current state.
yeah! This is what I have:
var popped = (($.browser.msie && parseInt($.browser.version, 10) < 9) ? 'state' in window.history : window.history.hasOwnProperty('state')), initialURL = location.href;
$(window).on('popstate', function (event) {
var initialPop = !popped && location.href === initialURL, state;
popped = true;
if (initialPop) { return; }
state = event.originalEvent.state;
if (state && state.reset) {
if (history.state === state) {
$.ajax({url: state.loc,
success: function (response) {
$(".fragment").fadeOut(100, function () {
$(".fragment").html($(".fragment", response).html()).fadeIn(100);
);
document.title = response.match(/<title>(.*)<\/title>/)[1];
}
});
} else { history.go(0); }
else {window.location = window.location.href; }
});
And:
$.ajax({url:link,
success: function (response) {
var replace = args.replace.split(",");
$.each(replace, function (i) {
replace[i] += ($(replace[i]).find("#video-content").length > 0) ? " #video-content" : "";
var selector = ".fragment "+replace[i];
$(selector).fadeOut(100, function () {
$(selector).html($(selector,response).html()).fadeIn(100, function () {
if (base.children("span[data-video]")[0]) {
if ($.browser.msie && parseInt($.browser.version, 10) === 7) {
$("#theVideo").html("");
_.videoPlayer();
} else {
_.player.cueVideoById(base.children("span[data-video]").attr("data-video"));
}
}
});
});
});
document.title = response.match(/<title>(.*)<\/title>/)[1];
window.history.ready = true;
if (history && history.pushState) { history.pushState({reset:true, loc:link}, null, link); }
}
});

Categories

Resources