How to detect the hash change in an HTTP page [duplicate] - php

I am using Ajax and hash for navigation.
Is there a way to check if the window.location.hash changed like this?
http://example.com/blah#123 to http://example.com/blah#456
It works if I check it when the document loads.
But if I have #hash based navigation it doesn't work when I press the back button on the browser (so I jump from blah#456 to blah#123).
It shows inside the address box, but I can't catch it with JavaScript.

The only way to really do this (and is how the 'reallysimplehistory' does this), is by setting an interval that keeps checking the current hash, and comparing it against what it was before, we do this and let subscribers subscribe to a changed event that we fire if the hash changes.. its not perfect but browsers really don't support this event natively.
Update to keep this answer fresh:
If you are using jQuery (which today should be somewhat foundational for most) then a nice solution is to use the abstraction that jQuery gives you by using its events system to listen to hashchange events on the window object.
$(window).on('hashchange', function() {
//.. work ..
});
The nice thing here is you can write code that doesn't need to even worry about hashchange support, however you DO need to do some magic, in form of a somewhat lesser known jQuery feature jQuery special events.
With this feature you essentially get to run some setup code for any event, the first time somebody attempts to use the event in any way (such as binding to the event).
In this setup code you can check for native browser support and if the browser doesn't natively implement this, you can setup a single timer to poll for changes, and trigger the jQuery event.
This completely unbinds your code from needing to understand this support problem, the implementation of a special event of this kind is trivial (to get a simple 98% working version), but why do that when somebody else has already.

HTML5 specifies a hashchange event. This event is now supported by all modern browsers. Support was added in the following browser versions:
Internet Explorer 8
Firefox 3.6
Chrome 5
Safari 5
Opera 10.6

Note that in case of Internet Explorer 7 and Internet Explorer 9 the if statment will give true (for "onhashchange" in windows), but the window.onhashchange will never fire, so it's better to store hash and check it after every 100 millisecond whether it's changed or not for all versions of Internet Explorer.
if (("onhashchange" in window) && !($.browser.msie)) {
window.onhashchange = function () {
alert(window.location.hash);
}
// Or $(window).bind( 'hashchange',function(e) {
// alert(window.location.hash);
// });
}
else {
var prevHash = window.location.hash;
window.setInterval(function () {
if (window.location.hash != prevHash) {
prevHash = window.location.hash;
alert(window.location.hash);
}
}, 100);
}
EDIT -
Since jQuery 1.9, $.browser.msie is not supported. Source: http://api.jquery.com/jquery.browser/

There are a lot of tricks to deal with History and window.location.hash in IE browsers:
As original question said, if you go from page a.html#b to a.html#c, and then hit the back button, the browser doesn't know that page has changed. Let me say it with an example: window.location.href will be 'a.html#c', no matter if you are in a.html#b or a.html#c.
Actually, a.html#b and a.html#c are stored in history only if elements '<a name="#b">' and '<a name="#c">' exists previously in the page.
However, if you put an iframe inside a page, navigate from a.html#b to a.html#c in that iframe and then hit the back button, iframe.contentWindow.document.location.href changes as expected.
If you use 'document.domain=something' in your code, then you can't access to iframe.contentWindow.document.open()' (and many History Managers does that)
I know this isn't a real response, but maybe IE-History notes are useful to somebody.

Firefox has had an onhashchange event since 3.6. See window.onhashchange.

I was using this in a react application to make the URL display different parameters depending what view the user was on.
I watched the hash parameter using
window.addEventListener('hashchange', doSomethingWithChangeFunction);
Then
function doSomethingWithChangeFunction () {
let urlParam = window.location.hash; // Get new hash value
// ... Do something with new hash value
};
Worked a treat, works with forward and back browser buttons and also in browser history.

You could easily implement an observer (the "watch" method) on the "hash" property of "window.location" object.
Firefox has its own implementation for watching changes of object, but if you use some other implementation (such as Watch for object properties changes in JavaScript) - for other browsers, that will do the trick.
The code will look like this:
window.location.watch(
'hash',
function(id,oldVal,newVal){
console.log("the window's hash value has changed from "+oldval+" to "+newVal);
}
);
Then you can test it:
var myHashLink = "home";
window.location = window.location + "#" + myHashLink;
And of course that will trigger your observer function.

Another great implementation is jQuery History which will use the native onhashchange event if it is supported by the browser, if not it will use an iframe or interval appropriately for the browser to ensure all the expected functionality is successfully emulated. It also provides a nice interface to bind to certain states.
Another project worth noting as well is jQuery Ajaxy which is pretty much an extension for jQuery History to add ajax to the mix. As when you start using ajax with hashes it get's quite complicated!

var page_url = 'http://www.yoursite.com/'; // full path leading up to hash;
var current_url_w_hash = page_url + window.location.hash; // now you might have something like: http://www.yoursite.com/#123
function TrackHash() {
if (document.location != page_url + current_url_w_hash) {
window.location = document.location;
}
return false;
}
var RunTabs = setInterval(TrackHash, 200);
That's it... now, anytime you hit your back or forward buttons, the page will reload as per the new hash value.

I've been using path.js for my client side routing. I've found it to be quite succinct and lightweight (it's also been published to NPM too), and makes use of hash based navigation.
path.js NPM
path.js GitHub

SHORT and SIMPLE example
Click on buttons to change hash
window.onhashchange = () => console.log(`Hash changed -> ${window.location.hash}`)
<button onclick="window.location.hash=Math.random()">hash to Math.Random</button>
<button onclick="window.location.hash='ABC'">Hash to ABC</button>
<button onclick="window.location.hash='XYZ'">Hash to XYZ</button>

Related

how to call a function when user left website [duplicate]

Is there a way to run a final JavaScript code when a user closes a browser window or refreshes the page?
I'm thinking of something similar to onload but more like onclose? Thanks.
I don't like the onbeforeunload method, which always yields to a confirmation box popping up (leave page/ stay on mozilla) or (reload/ don't reload on chrome). Is there a way to execute the code quietly?
There is both window.onbeforeunload and window.onunload, which are used differently depending on the browser. You can assign them either by setting the window properties to functions, or using the .addEventListener:
window.onbeforeunload = function(){
// Do something
}
// OR
window.addEventListener("beforeunload", function(e){
// Do something
}, false);
Usually, onbeforeunload is used if you need to stop the user from leaving the page (ex. the user is working on some unsaved data, so he/she should save before leaving). onunload isn't supported by Opera, as far as I know, but you could always set both.
Ok, I found a working solution for this, it consists of using the beforeunload event and then making the handler return null. This executes the wanted code without a confirmation box popping-up. It goes something like this:
window.onbeforeunload = closingCode;
function closingCode(){
// do something...
return null;
}
Sometimes you may want to let the server know that the user is leaving the page. This is useful, for example, to clean up unsaved images stored temporarily on the server, to mark that user as "offline", or to log when they are done their session.
Historically, you would send an AJAX request in the beforeunload function, however this has two problems. If you send an asynchronous request, there is no guarantee that the request would be executed correctly. If you send a synchronous request, it is more reliable, but the browser would hang until the request has finished. If this is a slow request, this would be a huge inconvenience to the user.
Later came navigator.sendBeacon(). By using the sendBeacon() method, the data is transmitted asynchronously to the web server when the User Agent has an opportunity to do so, without delaying the unload or affecting the performance of the next navigation. This solves all of the problems with submission of analytics data: the data is sent reliably, it's sent asynchronously, and it doesn't impact the loading of the next page.
Unless you are targeting only desktop users, sendBeacon() should not be used with unload or beforeunload since these do not reliably fire on mobile devices. Instead you can listen to the visibilitychange event. This event will fire every time your page is visible and the user switches tabs, switches apps, goes to the home screen, answers a phone call, navigates away from the page, closes the tab, refreshes, etc.
Here is an example of its usage:
document.addEventListener('visibilitychange', function() {
if (document.visibilityState == 'hidden') {
navigator.sendBeacon("/log.php", analyticsData);
}
});
When the user returns to the page, document.visibilityState will change to 'visible', so you can also handle that event as well.
sendBeacon() is supported in:
Edge 14
Firefox 31
Chrome 39
Safari 11.1
Opera 26
iOS Safari 11.4
It is NOT currently supported in:
Internet Explorer
Opera Mini
Here is a polyfill for sendBeacon() in case you need to add support for unsupported browsers. If the method is not available in the browser, it will send a synchronous AJAX request instead.
Update:
It might be worth mentioning that sendBeacon() only sends POST requests. If you need to send a request using any other method, an alternative would be to use the fetch API with the keepalive flag set to true, which causes it to behave the same way as sendBeacon(). Browser support for the fetch API is about the same.
fetch(url, {
method: ...,
body: ...,
headers: ...,
credentials: 'include',
mode: 'no-cors',
keepalive: true,
})
jQuery version:
$(window).unload(function(){
// Do Something
});
Update: jQuery 3:
$(window).on("unload", function(e) {
// Do Something
});
Thanks Garrett
The documentation here encourages listening to the onbeforeunload event and/or adding an event listener on window.
window.addEventListener('beforeunload', function(event) {
//do something here
}, false);
You can also just populate the .onunload or .onbeforeunload properties of window with a function or a function reference.
Though behaviour is not standardized across browsers, the function may return a value that the browser will display when confirming whether to leave the page.
You can use window.onbeforeunload.
window.onbeforeunload = confirmExit;
function confirmExit(){
alert("confirm exit is being called");
return false;
}
The event is called beforeunload, so you can assign a function to window.onbeforeunload.
Is there a way to execute the code quietly? (no popup)
I have used this successfully, where other methods (eg returning null or false) had issues. Tested on ie, Edge, Chrome, Opera.
window.addEventListener('beforeunload', function (e) {
// the absence of a returnValue property on the event will guarantee the browser unload happens
delete e['returnValue'];
// my code that silently runs goes here
});
The above code is pasted directly from Mozilla.org's onbeforeunload doc
Update: This doesn't appear to work on IOS Safari :( So not a total solution, but maybe it still helps someone.

Wait few second before closing page

I need a script that, when user closes the page, waits few seconds (without popups) and then closes the page.
I remember seeing somewhere here a way to do this, using ajax (if I remember correctly), by running a php file and waiting the answer before closing, but I can't find it anymore. The php file contained sleep-function.
Any help is greatly appreciated
(This is used mainly to fade out text. When user comes to site text fades in via css3 transition, and when he leaves page the text fades out. I just need time for fadeout. Yes, I know this is not user-friendly but I was specially asked to do it this way)
Your probably thinking of a synchronous ajax request (which blocks the UI):
window.addEventListener('unload',function()
{
var xhr = new XMLHttpRequest();
xhr.open('GET', 'script.php?when=unload',false);//<-- false makes request synchronous
xhr.send();
},false);
But there are other ways, check this answer
On the whole, I'd not do things like this. If a site attempted to deny me the option of closing the window when I feel like it, I'd never use/visit it again. That, and the fact that your JS code is still subject to how the browser implements it, and the browser can be controlled by the client's OS. If I close the browser application, a JS event has nothing to say in that matter, especially if I terminate the browser process (using kill -9, or ctrl+alt+del).
The very least you can do is offer the client a choice, to either force-quit, or wait, explaining why you'd rather the client waited a while:
window.addEventListener('beforeunload',function u(e)
{
var forceQuit = confirm('\tDo you wish to leave Now?\n
if you do, some changes you made won\'t be saved');
if (forceQuit)
{
return e;
}
//synchronous ajax result here, or:
e.returnValue = false;
e.cancelBubble = true;
if (e.preventDefault)
{
e.preventDefault();
e.stopPropagation();
}
setTimeout(function()
{//first, remove handler, so the beforeunload's behaviour is back to default
window.removeEventListener('beforeunload',u,false);
//dispatch new beforeunload event:
window.dispatchEvent( new Event('beforeunload'));
},5000);
},false);
Have a look at jquery unload. You can bind a delay-function to the unload-event.

Processing ID in the URL

I have gotta website powered by a set of jQueries; Dynamically loading the contents with a set of menu buttons.
Now, all I want to know is this:
Have you seen in blogger? The url is like
blogger.com/blogger.g?blogID=abcd#id
For the #id, if you put #overview it shows the stats. If you put #allposts it shows all the posts and similarly the content varies depending only on the #id in the url. I've seen many websites use this method to provide PermaLinks too.
How can I do it? for each menu button I provided an #id, which if passed in the url I need to switch to that particular menu.
Note : I use PHP, js, jQuery and HTML5 +/- Ajax
PS: Please, do not say you can use this and that! I'm a kinda middle of a knowledge i.e I'm not a pro. So please provide me with some algorithms or code.
Thanks in advance :)
window.location.hash will contain the hash value in the URL (#id, #overview, etc...). You can then use javascript that runs when your page loads to check the value of window.location.hash and based on what it contains, you can modify your page, using ajax calls if retrieving data from the server is necessary.
The hash value is not sent to the server so it must be client-side code that processes it.
As for specific code, you would use something like this;
$(document).ready(function() {
switch(window.location.hash) {
case "#id":
// code here
break;
case "#overview":
// code here
break;
default:
// code here
break;
}
});
What specific code goes in there obviously depends upon what you're trying to do. If you need to get data from your server, then you would issue ajax calls to retrieve that data.
This are called hash values which are not sent by the browser to the server, they can only be accessed by javascript.
They can be retrieved by
var hash_val = window.location.hash;
Javascript also provide event for hash change
window.onhashchange = function(){
}
And if you want it to modify content then
window.onload=function()
{
var hash_val = window.location.hash;
//do more ajax stuff here
}

AJAX/jquery functions only works once per pageload

I'm creating a dynamic todo list. The list is downloaded from a local database and displayed in a table. At each todo there's a submit-button which you can press and the todo is supposed to register in the database as "done". In my code this is done through a variable called status in which a value of 1 is done, and a value of 0 is undone.
My problem is that you can press any button and all works well; new status is sent to a PHP script, which in turn modifies the status value in the database. Then the webpage automatically updates the display table. But if you try once more, on any of the other buttons, it doesn't work. You'll have to reload the webpage for any of the other buttons to work.
Here's my Jquery/AJAX code:
$(document).ready( function() {
$('#todo_display_table input[type="submit"]').click(function(evt) {
evt.preventDefault();
var todo_id = $(this).val();
//document.write(todo_id);//debug
$.when(changeTodoStatusTo(1, todo_id)).then(updateTodoDisplay);
});
});
function updateTodoDisplay() {
$.post("./daily_todo_display.php", null, replaceTbodyHTML);
}
function replaceTbodyHTML(data) {
$('#todo_display_table tbody').html(data);
}
function changeTodoStatusTo(newStatus, todo_id) {
//Send til phpscript som lagrer ny status i databasen
var parameters = {
todo_id: todo_id,
newStatus: newStatus
};
return $.post("./daily_todo_change_todo_status.php", parameters); //, printDebugInfo);
}
I can post my PHP-scripts as well, but I have tested these separately and they seem to work. Again, all of the functionality on my page works fine, but they seem to stop working after you clicked one time.
I have checked the database and the status value only update itself the on first try(first click of any of the buttons), which would indicate that the problem lies in either the click() function or in the changeTodoStatusTo() function. Thnx for any help, and don't hesitate to ask for more information =)
You shouldn't use the live function of jQuery:
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
This method provides a means to attach delegated event handlers to the document element of a page, which simplifies the use of event handlers when content is dynamically added to a page. See the discussion of direct versus delegated events in the .on() method for more information.
jQuery live documentation
As the documentation states, use .on() instead. It works the same way as .live() :)
Are you recreating the submit buttons when you update??? It is hard to tell without seeing all of your code. Have you tried changing this:
$('#todo_display_table input[type="submit"]').click(function(evt) {
to this:
$('#todo_display_table input[type="submit"]').live('click', function(evt) {
see this if applicable: http://api.jquery.com/live/
I'm guessing you're losing the click event code when you update the html() of the #todo_display_table. Try live() instead
$('#todo_display_table input[type="submit"]').live('click', function(evt) {
This is a classic case of browser caching. I experienced the same effect awhile back. One way out would be to invoke all your posts as such:
$.post("./daily_todo_change_todo_status.php?id=" + (count++), parameters);
Within your php script, just ignore the id component. By doing it this way, the browser will generate a new string each time and it won't think that it was calling on the older cached page.
Hope it helped :) Cheers!
It sounds like you're facing some issues with the browser caching the response of your POST requests. This is a common problem with some browsers. You should know that browsers cache content based on the URI, not the actual file. In other words, the query string is included. One workaround to avoid caching the requests is to use a slightly different URI each time:
$.post("./daily_todo_change_todo_status.php?t="+new Date().getTime(), null, callbackFn);
By inserting the current timestamp, you're guaranteed to always make a fresh request to the server, instead of the browser just pulling cached data in lieu of a request.
In addition, in your second POST request, you are attempting to return data. This function is designed to return the response and process it inside a callback function, asynchronously, so that you don't block execution on the page.
However, I see you have a comment there that it's for debugging information, so hopefully this is something you'd remove in production.
From the code I can see, your event handling seems to be just fine. However, you are most likely losing the events when replaceTbodyHTML is called. You could just try running the code from the onload again when you update. For example,
function addListeners() {
$('#todo_display_table input[type="submit"]').click(function(evt) {
evt.preventDefault();
var todo_id = $(this).val();
//document.write(todo_id);//debug
$.when(changeTodoStatusTo(1, todo_id)).then(updateTodoDisplay);
});
}
$(document).ready(addListeners);
And then at the end of replaceTbodyHTML add addListeners();

How can web form content be preserved for the back button

When a web form is submitted and takes the user to another page, it is quite often the case that the user will click the Back button in order to submit the form again (the form is an advanced search in my case.)
How can I reliably preserve the form options selected by the user when they click Back (so they don't have to start from scratch with filling the form in again if they are only changing one of many form elements?)
Do I have to go down the route of storing the form options in session data (cookies or server-side) or is there a way to get the browser to handle this for me?
(Environment is PHP/JavaScript - and the site must work on IE6+ and Firefox2+)
I believe you're at the mercy of the browser. When you hit back, the browser does not make a new request to the server for the content, it uses the cache (in nearly every browser I've seen anyway). So anything server-side is out.
I'm wondering if you could do something very complicated like storing the search result in a cookie during the onunload event of the results page, and then reading the cookie in javascript on the search page and filling in the form - but this is just speculation, I don't know if it would work.
I'd put it in the session.
It's going to be the most reliable and even if they don't go straight "back", it'll still have their search options there.
Putting it in the cookie would also work, but wouldn't be recommended unless it's a very small form.
It's up to the browser, but in most cases you don't have to do anything.
IE, Firefox, etc. will happily remember the contents of the form in the previous page, and show it again when Back is clicked... as long as you don't do anything to stop that working, such as making the page no-cache or building the form entirely from script.
(Putting stuff in the session is likely to confuse browsers with two tabs open on the same form. Be very careful when doing anything like that.)
The problem you have is that the browser will return a cached version of the page, and probably not ask the server for it again, meaning using the session would be irrelevant.
You could however use AJAX to load the details of the previously submitted form on the page's load event.
You would basically have to store it on your server in some way (probably in session variables, as suggested) after the POST. You also have to setup Javascript on the form page to execute on load to issue an AJAX call to get the data from your server (in, say, JSON format) and prefill the form fields with the data.
Example jQuery code:
$( document ).ready( function() {
$.getJSON(
"/getformdata.php",
function( data ) {
$.each( data.items, function(i,item) {
$( '#' + item.eid ).val( item.val );
} );
});
} );
Your /getformdata.php might return data like:
{
'items': [
{
'eid': 'formfield1',
'val': 'John',
},
{
'eid': 'formfield2',
'val': 'Doe',
}
]
}
and it would obviously return an empty array if there were nothing saved yet for the session. The above code is rough and untested, but that should give you the basic idea.
As a side note: current versions of Opera and Firefox will preserve form field content when going Back. Your JS code will overwrite this, but that should be safe.
Another ajaxy options (so it's not good for users without javascript) is to submit the form via javascript and then go the confirmation page (or show the message on the form by replacing the button with a message). That way there is no "back" possible.
Why not store the values into a cookie before submitting? You could also include a timestamp or token to indicate when it was filled out. Then when the page loads, you can determine whether you should fill in the fields with data from the cookie, or just leave them blank because this is a new search.
You could also do everything local by javascript. So you store a cookie with the search value and on pageload you check if the cookie exists. Something like this:
$('#formSubmitButton').click( function() {
var value = $('#searchbox').val();
var days = 1;
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = "searchbox="+value+expires+"; path=/";
});
$(document).ready( function() {
var nameEQ = "searchbox=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) var valueC = c.substring(nameEQ.length,c.length);
}
$('#searchbox').val(valueC);
});
Have not tested this but is should work. You will need jQuery for this.
Cookie functions came from: http://www.quirksmode.org/js/cookies.html
I should say btw that both FireFox and IE have this behaviour by default.

Categories