How to deal with page refresh when using HTML5 History? - javascript

I have read through tons of tutorials and examples to no avail which leads me to ask my question here. I am developing a webpage with a fixed side navigation with a dynamic content div.
Problem
When i click on a link let's say 'load', the content div will display the content from my other page 'loadcourses.php' then using the history api i will change the url to 'http://mydomain.com/main.php?page=loadcourses'. Basically the main.php will not change i will just add the title of the other page and tag it as a parameter behind the link.
Next, from the dynamically loaded content, i have some links to show the content of each individual course when clicked. The crucial part lies here, once i clicked on any link, i am supposed to parse another parameter to the next page which is 'course.php'. I have set my href='http://mydomain.com/course.php?cid=CSC101'. Now i have no problem loading the first time with the dynamic div loading the content and successfully retrieving the id CSC101 at the next page. But when i hit refresh, my cid is lost.
The back/forward button works fine as per the history api. Help needed here, Thanks!! I am currently working on this .jsp prototype.
document.addEventListener('DOMContentLoaded', init, false);
function hasBrowserHistory(){return !!(window.history && history.pushState);}
function updateHistory(url, replaceHistory) {
//Create a page path
var path = "?page=" + url.split(".")[0];
var object = {
data: url
};
if(replaceHistory){
//alert('as');
/*
If this is the first page we are loading
replace the current history item.
*/
history.replaceState(object, null, path);
}else{
//alert('qw');
/*
If we got here by clicking one of the links
add a new item to the browser history
*/
history.pushState(object, null, path);
}
}
function loadPage(whichPage, replaceHistory) {
$('#contentCol').load(whichPage);
updateHistory(whichPage, replaceHistory);
}
function historyPopStateHandler(e) {
//var state = history.state;
if (e.state == null) {
alert(e.state.url);
}
if(e.state != null) {
loadPage(e.state.data, true);
}
}
function getUrlVars() {
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function init() {
//Check if the history API is available
if(!hasBrowserHistory()){
alert('Sorry dude, your browser does not support the history API');
return;
}
//Check if we have any url params (e.g bookmark or reload)
var params = getUrlVars();
if(params['page'] != undefined && params['page'] != null){
//Load the holder page with the correct content
loadPage(params['page'] + ".jsp", true);
}else{
//Load the default page
loadPage('loadcourses.jsp', true);
}
//Setup listeners for the links
jQuery('nav > a').click(function(e){
e.preventDefault();
loadPage(jQuery(e.target).attr('href'), false);
});
//Setup listeners for the history events
window.addEventListener('popstate', historyPopStateHandler);
}

yea guyz i heard the same problem but i fixed it... its so simple, when you hit refresh, the browser will request the page from the server and the page would not be there...
to cater for this you need a .htaccess file that will be used in redirecting those requests to the respective php file... like if the url is www.you.com/coding, the .htaccess file will scan for the word coding, the redirect the request to coding.php...
inside the php, you need to get the url of the request $_SERVER['REQUEST_URI'] then do some filtering...
if the request satisfy the filters... have a html page embeded on that php
bla..
?>
so in the html put the values that would have appered when you loaded the form... and thats the logic i even tried it in my website deenze and it worked

Related

Attempting window.location or window.location.href redirect which is causing a loop

I'm attempting to use javascript to determine if the user is using a certain language and if they're not using english then for the page to load a different page BUT with the params of which I've grabbed from the url.
I have been able to load the page with the params but I keep falling into a loop reloading the page, even after skimming through the countless other examples, such as: this or this.
function locateUserLanguage() {
var languageValue = (navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage)).split('-');
var url = window.location.href.split('?');
var baseUrl = url[0];
var urlParams = url[1];
if (languageValue[0] === 'en') {
console.log('no redirect needed, stay here.');
} else {
// I tried to set location into a variable but also wasn't working.
// var newURL = window.location.href.replace(window.location.href, 'https://www.mysite.dog/?' + urlParams);
window.location.href = 'https://www.mysite.dog/?' + urlParams
}
} locateUserLanguage();
I've attempted to place a return true; as well as return false; but neither stop the loop.
I've tried window.location.replace(); and setting the window.location.href straight to what I need, but it's continuing to loop.
There is a possibility that the script in which this function is written is executed in both of your pages (english and non-english) on load. So, as soon as the page is loaded, locateUserLanguage function is executed in both english and non-english website causing the infinite loop.
You need to put a check before you call locateUserLanguage function.
Suppose english website has url = "www.myside.com" and non-english website has url "www.myside.aus". So the condition needs to be
if (window.location.host === "www.myside.com") { locateUserLanguage() }
This will make sure that locateUserLanguage is called only in english website.
Or other apporach can be to load this script only in english website which will avoid the usage of conditional statement.
Hope it helps. Revert for any doubts.

Using $location for only part of a page breaks back button

I want to use $location to navigate a self-contained comments section on a normal statically loaded page, but it seems to break the back back button.
The problem comes when I've navigated to a few pages using $location, then click on an external link. It goes to that link, but when I hit back, it changes the URL to the last one but doesn't actually change the page (i.e. it stays on the external page). If I then keep on clicking back, it changes the URL (so the url history is fine), but it doesn't actually load up the page from that url until I get to the first one that I've visited (if that makes sense...). So, for example:
So, navigating the app:
www.example.com - loads up my page with the comments
www.example.com?page=2 - uses $location and loads the new comments correctly
www.example.com?page=3 - uses $location and loads the new comments correctly
www.externalexamplepage.com - navigates correctly to the page.
back - changes the address to www.example.com?page=3 but stays on www.externalexamplepage.com
back - changes the address to www.example.com?page=2 but stays on www.externalexamplepage.com
back - changes the address to www.example.com and loads up the page correctly.
So, how can I get it to not break the back button? This is what I've got in my comments directive:
$scope.$on('$locationChangeStart', function(e, newUrl) {
// If moving off current page...
if ($scope.changingCommentsPage === false) {
$window.location.href = newUrl;
}
});
$scope.$on('$locationChangeSuccess', function() {
// Get current urlParams
var urlParams = $location.search();
// Get new comments if page has changed
if ($scope.page != urlParams.page || typeof urlParams.page === "undefined") {
$scope.changingCommentsPage = false;
$scope.page = urlParams.page ? urlParams.page : 1;
if ($scope.page < 1) return;
// Get comments
getComments($scope.model.page);
}
});

Adding Browser History and Navigation To JavaScript DOM Page Change Function

I am using JavaScript to change the pages of my website, but I am running into the issue where I can't use browser navigation to go back or forwards through the history once I have changed pages.
I have tried adding a /#pagename to the URL for each page, and a few other things, but I can't seem to find something that works. I need to be able to make sure that the browser is saving the history of the page changes I make, so it can navigate those pages with the forward and back buttons.
// Change Page Function
function ChangeContent (page) {
var pages={"homepage":{title: "homepage"},"servicespage":{title: "servicespage"}};
//Show home page
for(var homepage in pages) {
if(page!==homepage) {
document.getElementById(homepage).style.display='none';
}
else {
document.getElementById(homepage).style.display='block';
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';
window.scrollTo(0,0);
}
}
}
You should look at window.history.pushState to add history entries and window.onpopstate to react to the user travelling "backward" through the entries you've added.
When you want to "change" pages, make a call like:
window.history.pushState( stateData, title, url );
where...
stateData is some object containing data you define
title is a string name for the new state
url is the string to which the browser's url should be changed
For example, if you want to change to "servicespage" and make the url change to "/#services":
window.history.pushState( { title: "Services" }, "servicespage", "/#services" );
Note that you still have to manipulate the DOM at this point.
Then, if you want to react to the user going backward through history:
window.onpopstate = function( event ) {
var data = event.state;
// data references the first argument of 'pushState'
// do whatever showing or hiding of <div>s here
};

How can I execute a script after calling window.location.href?

I have a script that redirects the user to another page. I want to load some content into a div on the new page after the new page has fully loaded. How can I do this. The following doesn't work.
function goToPage() {
window.location.href = 'http://www.mypage.com/info';
$('.my_class').load('my/url/path/with/content/to/load');
}
The newly loaded page http://www.mypage.com/info contains the following div:
<div class="my_class"></div>
What am I doing wrong?
Redirect to the new page, but append a hash signal to the URL.
function goToPage() {
window.location.href = 'http://www.mypage.com/info#load-stuff;
}
Then on load of the target page, evaluate the URL checking for that hash signal.
function pageLoad() {
if (window.location.hash === "#load-stuff") {
$('.my_class').load('my/url/path/with/content/to/load');
}
}
If your application is using jQuery it'd look something like:
$(function () {
if (window.location.hash === "#load-stuff") {
$('.my_class').load('my/url/path/with/content/to/load');
}
});
That's the rough idea at least.
As pointed out in the other answers, you won't be able to perform any script instructions from your original site. Instead of using PHP to create the content statically, you could also use HTML fragments as arguments, e.g. like this:
// in the original page:
function goToPage() {
window.location.href = 'http://www.mypage.com/info#my/url/path/with/content/to/load';
}
// in http://www.mypage.com/info:
$( document ).ready(function () {
if(window.location.hash)
$('.my_class').load(window.location.hash.substring(1));
}
An easy way to pass data to your page you are redirecting to would be to set some url parameters.
For example:
window.location.href - "http://youpage.com/?key=value"
When that page loads you could have a:
$(document).ready(function(){
var my_param = getUrlParameter('key');
if(my_param == "value"){
//do your stuff here
}
});
var getUrlParameter = function getUrlParameter(sParam) {
var sPageURL = decodeURIComponent(window.location.search.substring(1)),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1];
}
}
};
You should just run
$('.my_class').load('my/url/path/with/content/to/load');
on this page: http://www.mypage.com/info.
When you do window.location.href = 'http://www.mypage.com/info'; you're redirecting to another page. Nothing after that line will happen. You have to instead run the code after that line on the page that's loaded.
You can do this a few different ways. Try leveraging the localstorage API and passing info or content with a name and value pair (or a few of them) and unpack it on the receiving end.
On the page you're redirecting to, check for the localstorage key, and then load the contents of it (the aforementioned name and value pairs) into a div.
As an alternative, you can write one script file that you can deploy to several pages; do a check on window.location.href and conditionally load script accordingly. If you're on the redirected page, you can run whatever script you like. The nice part about doing it this way is that you're still working with one JS file - no need to fragment your code (assuming, of course, that the pages you're working with are all on the same site).
You don't need to do anything with php if you don't want to, or hashes... there's a few nifty tools that will do the trick if you can leverage HTML5 and its associated APIs.
window.location = '#/MyPage';
setTimeout(function() {
//MyCode To Run After PageLoad
});
You are redirecting the browser with window.location.href and I'm afraid as you are purely just changing the browser's location, you can't have any affect/input on the page you are moving to (unless you use query string parameters and then create content with something like PHP (myurl.php?newcontent=whatever) )
Once you redirect you can no longer execute scripts on that page, as the page is unloaded.
Try this,
redirect page:
function goToPage() {
window.location.href = 'http://www.mypage.com/info;
}
mypage.com/info:
js:
$('.my_class').load('my/url/path/with/content/to/load');
html:
<div class="my_class"></div>
I hope this helped you out, and let me know if you need further assistance!

Ajax with history.pushState and popstate - what do I do when popstate state property is null?

I'm trying out the HTML5 history API with ajax loading of content.
I've got a bunch of test pages connected by relative links. I have this JS, which handles clicks on those links. When a link is clicked the handler grabs its href attribute and passes it to ajaxLoadPage(), which loads content from the requested page into the content area of the current page. (My PHP pages are set up to return a full HTML page if you request them normally, but only a chunk of content if ?fragment=true is appended to the URL of the request.)
Then my click handler calls history.pushState() to display the URL in the address bar and add it to the browser history.
$(document).ready(function(){
var content = $('#content');
var ajaxLoadPage = function (url) {
console.log('Loading ' + url + ' fragment');
content.load(url + '?fragment=true');
}
// Handle click event of all links with href not starting with http, https or #
$('a').not('[href^=http], [href^=https], [href^=#]').on('click', function(e){
e.preventDefault();
var href = $(this).attr('href');
ajaxLoadPage(href);
history.pushState({page:href}, null, href);
});
// This mostly works - only problem is when popstate happens and state is null
// e.g. when we try to go back to the initial page we loaded normally
$(window).bind('popstate', function(event){
console.log('Popstate');
var state = event.originalEvent.state;
console.log(state);
if (state !== null) {
if (state.page !== undefined) {
ajaxLoadPage(state.page);
}
}
});
});
When you add URLs to the history with pushState you also need to include an event handler for the popstate event to deal with clicks on the back or forward buttons. (If you don't do this, clicking back shows the URL you pushed to history in the address bar, but the page isn't updated.) So my popstate handler grabs the URL saved in the state property of each entry I created, and passes it to ajaxLoadPage to load the appropriate content.
This works OK for pages my click handler added to the history. But what happens with pages the browser added to history when I requested them "normally"? Say I land on my first page normally and then navigate through my site with clicks that do that ajax loading - if I then try to go back through the history to that first page, the last click shows the URL for the first page, but doesn't load the page in the browser. Why is that?
I can sort of see this has something to do with the state property of that last popstate event. The state property is null for that event, because it's only entries added to the history by pushState() or replaceState() that can give it a value. But my first loading of the page was a "normal" request - how come the browser doesn't just step back and load the initial URL normally?
This is an older question but there is a much simpler answer using native javascript for this issue.
For the initial state you should not be using history.pushState but rather history.replaceState.
All arguments are the same for both methods with the only difference is that pushState creates a NEW history record and thus is the source of your problem. replaceState only replaces the state of that history record and will behave as expected, that is go back to the initial starting page.
I ran into the same issue as the original question. This line
var initialPop = !popped && location.href == initialURL;
should be changed to
var initialPop = !popped;
This is sufficient to catch the initial pop. Then you do not need to add the original page to the pushState. i.e. remove the following:
var home = 'index.html';
history.pushState({page:home}, null, home);
The final code based on AJAX tabs (and using Mootools):
if ( this.supports_history_api() ) {
var popped = ('state' in window.history && window.history.state !== null)
, changeTabBack = false;
window.addEvent('myShowTabEvent', function ( url ) {
if ( url && !changingTabBack )
setLocation(url);
else
changingTabBack = false;
//Make sure you do not add to the pushState after clicking the back button
});
window.addEventListener("popstate", function(e) {
var initialPop = !popped;
popped = true;
if ( initialPop )
return;
var tabLink = $$('a[href="' + location.pathname + '"][data-toggle*=tab]')[0];
if ( tabLink ) {
changingTabBack = true;
tabLink.tab('show');
}
});
}
I still don't understand why the back button behaves like this - I'd have thought the browser would be happy to step back to an entry that was created by a normal request. Maybe when you insert other entries with pushState the history stops behaving in the normal way. But I found a way to make my code work better. You can't always depend on the state property containing the URL you want to step back to. But stepping back through history changes the URL in the address bar as you would expect, so it may be more reliable to load your content based on window.location. Following this great example I've changed my popstate handler so it loads content based on the URL in the address bar instead of looking for a URL in the state property.
One thing you have to watch out for is that some browsers (like Chrome) fire a popstate event when you initially hit a page. When this happens you're liable to reload your initial page's content unnecessarily. So I've added some bits of code from the excellent pjax to ignore that initial pop.
$(document).ready(function(){
// Used to detect initial (useless) popstate.
// If history.state exists, pushState() has created the current entry so we can
// assume browser isn't going to fire initial popstate
var popped = ('state' in window.history && window.history.state !== null), initialURL = location.href;
var content = $('#content');
var ajaxLoadPage = function (url) {
console.log('Loading ' + url + ' fragment');
content.load(url + '?fragment=true');
}
// Handle click event of all links with href not starting with http, https or #
$('a').not('[href^=http], [href^=https], [href^=#]').on('click', function(e){
e.preventDefault();
var href = $(this).attr('href');
ajaxLoadPage(href);
history.pushState({page:href}, null, href);
});
$(window).bind('popstate', function(event){
// Ignore inital popstate that some browsers fire on page load
var initialPop = !popped && location.href == initialURL;
popped = true;
if (initialPop) return;
console.log('Popstate');
// By the time popstate has fired, location.pathname has been changed
ajaxLoadPage(location.pathname);
});
});
One improvement you could make to this JS is only to attach the click event handler if the browser supports the history API.
I actually found myself with a similar need today and found the code you provided to be very useful. I came to the same problem you did, and I believe all that you're missing is pushing your index file or home page to the history in the same manner that you are all subsequent pages.
Here is an example of what I did to resolve this (not sure if it's the RIGHT answer, but it's simple and it works!):
var home = 'index.html';
history.pushState({page:home}, null, home);
Hope this helps!
I realize this is an old question, but when trying to manage state easily like this, it might be better to take the following approach:
$(window).on('popstate',function(e){
var state = e.originalEvent.state;
if(state != null){
if(state.hasOwnProperty('window')){
//callback on window
window[state.window].call(window,state);
}
}
});
in this way, you can specify an optional callback function on the state object when adding to history, then when popstate is trigger, this function would be called with the state object as a parameter.
function pushState(title,url,callback)
{
var state = {
Url : url,
Title : title,
};
if(window[callback] && typeof window[callback] === 'function')
{
state.callback = callback;
}
history.pushState(state,state.Title,state.Url);
}
You could easily extend this to suit your needs.
And Finally says:
I'd have thought the browser would be happy to step back to an entry that was created by a normal request.
I found an explanation of that strange browser's behavior here. The explanation is
you should save the state when your site is loaded the first time and thereafter every time it changes state
I tested this - it works.
It means there is no need in loading your content based on window.location.
I hope I don't mislead.

Categories

Resources