AJAX and setInterval for window.location.hash - javascript

//Gather AJAX links
var ajaxLink = $("#logo, .navLink, .tableLink, .footerLink");
//Mark the recent state as null (because there is none yet)
var recentState = null;
//Initialize the page state based on the URL (bookmarking compatibility)
window.onload = function() {
//If no page state exists, assume the user is at index.html
if (window.location.hash == "") {
window.location.hash = "page=index";
}
//Load the page state based on the URL
loadStateFromURL();
//Keep the page state synchronized (back/forward button compatibility)
setInterval(loadStateFromURL, 500);
//Exit
return;
}
//Use AJAX for certain links
ajaxLink.click(function() {
//Update the URL
window.location.hash = "page=" + $(this).attr("id");
//Load the page state based on the URL
loadStateFromURL();
//Return false or else page will refresh
return false;
});
//Load the page state based on the URL
function loadStateFromURL() {
//If nothing has changed, exit
if (window.location.hash == recentState) {
return;
}
//Mark the recent state
recentState = window.location.hash;
//Go through an array of all AJAX links and check their IDs
for (var i = 0; i < ajaxLink.length; i++) {
//If we find a link's ID that matches the current state, load the relevant content
if ("#page=" + ajaxLink[i].id == window.location.hash) {
//Load contents into article.main
$("article.main").fadeOut(0).load(ajaxLink[i].href, function(response, status, xhr) {
//Show an error if the request fails
if (status == "error") {
$("article.main").load("./404.html");
window.location.hash = "page=404";
}
}).fadeIn(500);
//Update the page title
document.title = "\u2622 My Website Name \u2622 " + ajaxLink[i].text;
document.getElementById("headH2").textContent = ajaxLink[i].text;
//State has been fixed, exit
return;
}
}
}
This code works flawlessly when I run it locally!!!
But when I throw it on the web server my AJAX'd links will refresh the page when I first visit. However, if I use the back button then try the link again (or I'm assuming if the page is already in the browser cache), it will work properly.
I cannot allow this, because when people first visit my page the first link they click on will not operate as intended.
One of things I've also been testing is I'll bookmark my own site with a breadcrumb bookmark (example.com/#page=14) and see if it updates without my page already being in the browser cache. Again, it works on my local machine but not on my web server.

use event.preventDefault()
ajaxLink.click(function(e) {
e.preventDefault();
//Update the URL
window.location.hash = "page=" + $(this).attr("id");
//Load the page state based on the URL
loadStateFromURL();
//Return false or else page will refresh
return false;
});

The issue maybe is that when you are applying your click event to these links, they may not be loaded to the DOM. So the possible solution is to put ajaxLink.click(function() { ... }); part inside window.load event or document.ready event. Since you have used window.load event, you can do something like this.
//Initialize the page state based on the URL (bookmarking compatibility)
window.onload = function() {
//If no page state exists, assume the user is at index.html
if (window.location.hash == "") {
window.location.hash = "page=index";
}
//Load the page state based on the URL
loadStateFromURL();
//Keep the page state synchronized (back/forward button compatibility)
setInterval(loadStateFromURL, 500);
//Use AJAX for certain links
ajaxLink.click(function() {
//Update the URL
window.location.hash = "page=" + $(this).attr("id");
//Load the page state based on the URL
loadStateFromURL();
//Return false or else page will refresh
return false;
});
//Exit
return;
}

Solved my own question, had to continuously parse the AJAX links to stay updated with the DOM as it changes.
First I put the ajaxLink declaration into a function:
//Gather AJAX links
function parseAjaxLinks() {
var ajaxLink = $("#logo, .navLink, .tableLink, .footerLink");
return ajaxLink;
}
Then I had to put the ajaxLink click events into a function:
//Load the page state from an AJAX link click event
function loadStateFromClick() {
//Update the AJAX links
var ajaxLink = parseAjaxLinks();
ajaxLink.click(function() {
//Update the URL
window.location.hash = "page=" + $(this).attr("id");
//Load the page state based on the URL
loadStateFromURL();
//Return false or else page will refresh
return false;
});
}
Then I added a line in my window.onload event to keep my AJAX click events synchronized with the DOM (this adds overhead, but oh well):
//Initialize the page state based on the URL (bookmarking compatibility)
window.onload = function() {
//If no page state exists, assume the user is at index.html
if (window.location.hash == "") {
window.location.hash = "page=index";
recentState = window.location.hash;
}
//Load the page state based on the URL
loadStateFromURL();
//Keep the page state synchronized (back/forward button compatibility)
setInterval(loadStateFromURL, 250);
//Keep AJAX links synchronized (with DOM)
setInterval(loadStateFromClick, 250);
//Exit
return;
}
If you have a keen eye, you saw I had called the new parseAjaxLinks in my new loadStateFromClick function, so I added a line to the top of my loadStateFromURL function to keep the links updated in there as well:
//Load the page state based on the URL
function loadStateFromURL() {
//Update the AJAX links
var ajaxLink = parseAjaxLinks();
...
What I learned from this is the variables which are dependent on the DOM need to be continuously updated. While the DOM is loading, things are unpredictable and kind of sucks. **Drinks beer**

Related

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");
}
});

ajax image viewer , back button and history - missing html and css

I am playing with jquery and js, trying to build an ajax overlay image viewer for a PHP website. With this code included at the bottom of the 'gallery page', the viewer opens and i can navigate with next and previous links inside the viewer. But the back button and the history is hard to understand. The browser often shows only the response of the ajax call, without the underlying page and css files, after some clicks back.
Perhaps somebody knows what is generally happening in such a case? I would like to understand why back sometimes results in a broken page, i.e. only the ajax response.
<script type="text/javascript">
$(document).ready(function() {
function loadOverlay(href) {
$.ajax({
url: href,
})
.done(function( data ) {
var theoverlay = $('#flvr_overlay');
theoverlay.html( data );
var zoompic = $('#zoompic');
zoompic.load(function() {
var nih = zoompic.prop('naturalHeight');
var photobox = $('#photobox');
if($(window).width() >= 750){
photobox.css('height',nih);
}
theoverlay.show();
$('body').css('overflow-y','hidden');
$(window).resize(function () {
var viewportWidth = $(window).width();
if (viewportWidth < 750) {
photobox.css('height','auto');
zoompic.removeClass('translatecenter');
}else{
photobox.css('height',nih);
zoompic.addClass('translatecenter');
}
});
});
});
return false;
}
var inithref = window.location.href;
$(window).on('popstate', function (e) {
if (e.originalEvent.state !== null) {
//load next/previous
loadOverlay(location.href);
} else {
//close overlay
$('#flvr_overlay').hide().empty();
$('body').css('overflow-y','scroll');
history.replaceState(null, inithref, inithref);
}
});
$(document).on('click', '.overlay', function () {
var href = $(this).attr('href');
history.pushState({}, href, href);
loadOverlay(href);
return false;
});
});
</script>
edit
clicking forward works:
/photos (normal page)
/photos/123 (overlay with '/photos' below)
/locations/x (normal page)
/photos/567 (overlay with '/locations/x' below)
clicking back gives me the broken view at point 2.
Do you need to prevent the default behaviour in your popstate to prevent the browser from actually navigating back to the previous page?
you have to manage it by own code.
You have a few options.
Use localstorage to remember the last query
Use cookies (but don't)
Use the hash as you tried with document.location.hash = "last search" to update the url. You would look at the hash again and if it is set then do another ajax to populate the data. If you had done localstorage then you could just cache the last ajax request.
I would go with the localstorage and the hash solution because that's what some websites do. You can also copy and paste a URL and it will just load the same query. This is pretty nice and I would say very accessible
Changing to document.location.hash = "latest search" didn't change anything.t.
This goes into the rest of the jQuery code:
// Replace the search result table on load.
if (('localStorage' in window) && window['localStorage'] !== null) {
if ('myTable' in localStorage && window.location.hash) {
$("#myTable").html(localStorage.getItem('myTable'));
}
}
// Save the search result table when leaving the page.
$(window).unload(function () {
if (('localStorage' in window) && window['localStorage'] !== null) {
var form = $("#myTable").html();
localStorage.setItem('myTable', form);
}
});
Another solution is that use INPUT fields to preserved while using back button. So, I do like that :
My page contains an input hidden like that :
Once ajax content is dynamicaly loaded, I backup content into my hidden field before displaying it:
function loadAlaxContent()
{
var xmlRequest = $.ajax({
//prepare ajax request
// ...
}).done( function(htmlData) {
// save content
$('#bfCache').val( $('#bfCache').val() + htmlData);
// display it
displayAjaxContent(htmlData);
});
}
And last thing to do is to test the hidden field value at page loading. If it contains something, that because the back button has been used, so, we just have to display it.
jQuery(document).ready(function($) {
htmlData = $('#bfCache').val();
if(htmlData)
displayAjaxContent( htmlData );
});

jQuery .load: any way to load the same page when page is refreshed

So I have a website that loads pages to a container div:
function goto(addr) {
$("#content").load(addr);
}
and a link that executes it
About us
My problem is that whenever the page is refreshed, the loaded content resets to the default page (page/home.php). How could I do so that it loads the previous displayed page?
Use local storage for example or sessions.
Local storage example:
$(document).ready(function() {
var lastPage = localStorage['lastPage'];
if (!lastPage) { // If user was on any url before we will exectue goto function
goto(lastPage)
}
function goto(addr) {
localStorage['lastPage'] = addr; // Set url to local storage before load page
$("#content").load(addr);
}
});
not only localStore but you need change the hash of url, and after do one function to catch hash code and execute at you "goto" function...
"something like that"
function hashnav(){
var hashfull = document.location.hash
var hash = hashfull.replace('#', '');
var $page = '';
goto(hash);
}
function changeHash($hash) {
window.location.hash = $hash;
}
function goto(addr) {
changeHash(addr);
}
$(window).bind( 'hashchange', function() {
hashnav();
return false;
});

If current page is X, do this action

I have a simple site, which slides the content off the page before taking you to the URL. However, I need to be able to determine the slide direction, depending on which page you're currently on.
I need to do this, but I'm not sure how to articulate it properly with jQuery:
if (current page == about.php) {
animate right then go to target URL }
else {
do default behaviour }
At the moment, I have this function which doesn't work well, because it animates in a certain way regardless of which URL you're going to:
function animateLeftAndGo(x) {
$(x).click(function (e) {
e.preventDefault();
var href = this.href;
$('.pop-up').fadeOut(function(){
$('.wrapper').animate({left: "+=150%"}, "slow", function(){
window.location = href;
});
});
});
}
Which is called by:
animateLeftAndGo('a.archive');
How can I set up an if statement that asks if the current URL is about.php?
In JavaScript use the location object: http://www.w3schools.com/jsref/obj_location.asp
if (location.pathname == '') {
}

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