I want to detect hashchanges, and if the hash is empty, prevent it from scrolling to the top of the screen.
Here's what I have:
// Older version of jQuery, so can't use .on()
jQuery(window).bind("hashchange", function (e) {
if (window.location.hash == "") e.preventdefault();
else alert(window.location.hash);
});
Put that into your console, and you can see that it correctly detects hash changes and alerts if they are not just "#", but if you change it append "#" to your url, it still scrolls to the top.
How do I prevent the screen from going to the top of the page when you add an empty hash, "#", to your url?
$(function() {
$('a').click(function(e) {
var lnkHref = $(this).attr('href');
if (lnkHref.substr(lnkHref.length - 1) == '#')
{
e.preventDefault();
// optional if you want to redirect still
var trimmedUrl = lnkHref.substr(0, lnkHref.length - 1);
document.location.href = trimmedUrl;
}
});
})
Related
I'm looking for a way to rewrite URL of the location when the user want's to change page. So, let's say you have something like this:
<body>
<a href="http://example.com" />
</body>
Is there a way I can catch URL changing moment, and actually modify that URL before location is changed, for example I would like to change href into relative link like \http://example.com and redirect page actually there.
If you just want to trap the link and then modify it then yes, that's quite simple...
$("a").on("click", function(e) {
e.preventDefault(); // stops the link doing its default thing
window.location.href = "something/" + $(this).attr("href");
});
You obviously need to modify the line that changes the location, so that it modifies the href value however you need. I'd also recommend giving the links a class and selecting them with that, as the above code will affect every link on the page.
Finally, this will need to run after the DOM is loaded, so either wrap it in a document.ready handler of your choice, or put it in a script at the bottom of the body.
Demo
You can work from here. Also you will need urlrewrite in htaccess for this to work properly.
$(function () {
$('.buttonn').on('click', function (e) {
var seperator = (window.location.href.indexOf("?") === -1) ? "?" : "&";
if (window.location.href.indexOf("s1") === -1 && window.location.href.indexOf("s2") != -1) {
window.location.href = window.location.href.replace(/&?s2=([^&]$|[^&]*)/i, "&s1=s1");
} else if (window.location.href.indexOf("s1") != -1) {
window.location.href = window.location.href.replace(/&?s1=([^&]$|[^&]*)/i, "&s1=s1");
} else {
window.location.href = window.location.href + seperator + "s1=s1";
}
});
});
$(function () {
$('.buttono').on('click', function (e) {
var seperator = (window.location.href.indexOf("?") === -1) ? "?" : "&";
if (window.location.href.indexOf("s2") === -1 && window.location.href.indexOf("s1") != -1) {
window.location.href = window.location.href.replace(/&?s1=([^&]$|[^&]*)/i, "&s2=s2");
} else if (window.location.href.indexOf("s2") != -1) {
window.location.href = window.location.href.replace(/&?s2=([^&]$|[^&]*)/i, "&s2=s2");
} else {
window.location.href = window.location.href + seperator + "s2=s2";
}
});
});
I want to prevent page redirecting I know it can be achieve by this
window.onbeforeunload = function() {
return "Dude, are you sure you want to leave? Think of the kittens!";
}
which was answered here Prevent any form of page refresh using jQuery/Javascript
But in my case I only want to prevent page when it is redirecting by clicking on any of the anchor tag.
Also event.preventDefault() will not work in my case while clicking on anchor tag because all anchors are not redirecting page so it should work fine.
I only want to stop redirecting page if it is redirecting by clicking on anchor. Any solution?
You can keep a flag which tells you whether or not the user clicked an a tag, then read that on your onbeforeunload script:
window.onbeforeunload = function () {
if (_clickedAnchor) {
_clickedAnchor = false;
return "Dude, are you sure you want to leave? Think of the kittens!";
}
}
_clickedAnchor = false;
jQuery(document).ready(function () {
jQuery("a").click(function () {
_clickedAnchor = true;
});
});
You can use onhashchange.
With jQuery:
$(window).on('hashchange', function() {
alert('bye byee?');
});
Plain DOM JavaScript:
window.onhashchange = function() {
alert('bye byee?');
};
Note: You will need to create a custom "hash-change" handler for older browser which don't support this event.
You can easly do this with setInterval and detect any changes in document.location.hash.
Failsafe onhashchange for older browsers:
var currentHash = document.location.hash;
window.prototype.onhashchange = function( callback ) {
if(typeof(callback) == 'function') {
setInterval(function() {
if(document.location.hash !== currentHash) {
callback();
}
}, 650); // more than a half-a-second delay
}
}
And you can use it as an event in regular DOM convention.
So since you tagged jQuery I'll put my solution in terms of that. You can grab all the a tags and then check to make sure the anchor is a redirect, then use the e.preventDefault();
$('a').on('click',function(e){
if ($(this).attr('href') != window.location.href)
{
e.preventDefault();
//do stuff
}
});
The caller will be null if a link is clicked:
window.onbeforeunload = function() {
alert(window.onbeforeunload.caller)
}
This is a known issue for iScroll and it only seems to happen in iOS5 where the menu completely stops working. All my sub links in iScroll are hash anchors. Does anyone have a workaround for this?
The way I handled it was to hijack the anchor links themselves and replace them with scrollToElement calls instead.
// Hijack hash anchors and scroll to them
$('a').click ( function (e) {
var id = $(this).attr('href');
if (id.substr(0,1) == '#') {
e.preventDefault();
setTimeout( function() {
scroller.scrollToElement ( id, 0 );
}, 0);
return false;
} else {
return true;
}
});
This code should only hijack links that begin with #. It then handles the scrollToElement in a setTimeout which fixes some other intermittent bugs. It works well on my end as long as your anchors are properly named with id's. If you are using name attributes instead of id attributes, you'll need to rewrite these.
This code will copy name attributes and put them in the id attribute if it is blank. You probably won't need this, though.
$('a').each (function (i, e) {
var n = $(e).attr('name');
var id = $(e).attr('id');
if ( typeof id == 'undefined' || id === null || id === '') {
$(e).attr('id', n);
}
});
EDIT (12/26/2012)
I found the following code which does exactly what I want, except now when a page's URL has a trailing slash (e.g. example.com/page/), the page doesn't scroll. Works fine if the page's URL ends with '.php' or '.html', etc. Any thoughts on how to get the following script to work with the trailing slash in a URL?
jQuery('a[href*=#]').bind('click', function(e) {
// Get the target
var target = jQuery(this).attr("href");
// prevent the "normal" behaviour which would be a "hard" jump
e.preventDefault();
// perform animated scrolling by getting top-position of target-
// element and set it as scroll target
jQuery('html, body').stop().animate({
scrollTop: jQuery(target).offset().top
}, 500, function() {
location.hash = target; //attach the hash (#jumptarget) to the pageurl
});
return false;
});
I've been using a script successfully for the last couple of years, but have recently run into some issues with it. Basically what the script does is scroll the page to a specific point. This happens with link anchors. For example, if one link is:
anchor link
The page will smoothly scroll to that anchor on the page:
<a name="anchor"></a>
Or:
<a id="anchor"></a>
The issue that occurs arises when some other JS is being used in the page which requires a link to be formatted as such:
other link
When this "other link" is clicked, the page will smoothly scroll, BUT to the top or bottom of the page where there is NO anchor.
What should happen when this "other link" is clicked? The other JS action should occur (which it does), but the smooth page scrolling script should not occur.
Here's a working example from where I got this script:
http://www.dezinerfolio.com/wp-content/uploads/smoothscrolldemo/df_smooth_scroll.html
Here's the JS in full:
Scroller = {
// control the speed of the scroller.
// dont change it here directly, please use Scroller.speed=50;
speed: 10,
// returns the Y position of the div
gy: function (d) {
gy = d.offsetTop
if (d.offsetParent) while (d = d.offsetParent) gy += d.offsetTop
return gy
},
// returns the current scroll position
scrollTop: function (){
body = document.body
d = document.documentElement
if (body && body.scrollTop) return body.scrollTop
if (d && d.scrollTop) return d.scrollTop
if (window.pageYOffset) return window.pageYOffset
return 0
},
// attach an event for an element
// (element, type, function)
add: function(event, body, d) {
if (event.addEventListener) return event.addEventListener(body, d,false)
if (event.attachEvent) return event.attachEvent('on'+body, d)
},
// kill an event of an element
end: function(e){
if (window.event) {
window.event.cancelBubble = true
window.event.returnValue = false
return;
}
if (e.preventDefault && e.stopPropagation) {
e.preventDefault()
e.stopPropagation()
}
},
// move the scroll bar to the particular div.
scroll: function(d){
i = window.innerHeight || document.documentElement.clientHeight;
h = document.body.scrollHeight;
a = Scroller.scrollTop()
if (d>a)
if(h-d>i)
a += Math.ceil((d-a)/Scroller.speed)
else
a += Math.ceil((d-a-(h-d))/Scroller.speed)
else
a = a + (d-a)/Scroller.speed;
window.scrollTo(0,a)
if (a==d || Scroller.offsetTop==a)
clearInterval(Scroller.interval)
Scroller.offsetTop = a
},
// initializer that adds the renderer to the onload function of the window
init: function(){
Scroller.add(window,'load', Scroller.render)
},
// this method extracts all the anchors and validates then as # and attaches the events.
render: function(){
a = document.getElementsByTagName('a');
Scroller.end(this);
window.onscroll
for (i=0;i<a.length;i++) {
l = a[i];
if (l.href && l.href.indexOf('#') != -1 && ((l.pathname==location.pathname) || ('/'+l.pathname==location.pathname)) ){
Scroller.add(l,'click',Scroller.end)
l.onclick = function(){
Scroller.end(this);
l = this.hash.substr(1);
a = document.getElementsByTagName('a');
for (i=0;i<a.length;i++) {
if (a[i].name == l){
clearInterval(Scroller.interval);
Scroller.interval = setInterval('Scroller.scroll('+Scroller.gy(a[i])+')',10);
}
}
}
}
}
}
}
// invoke the initializer of the scroller
Scroller.init();
I would think that there is a way to write the script so that if the href is equal to just the hash mark # without any text after the hash, that the scroller wouldn't be triggered.
Does anyone have any better ideas?
Thanks in advance!
I can't help you with your jQuery function, but there are two simple solutions to your original script. The first is a small modification to tell the script to ignore the special case where an anchor's URL is only the hash tag.
In the render function, change the line:
if (l.href
&& l.href.indexOf('#') != -1
&& (l.pathname == location.pathname
|| '/' + l.pathname == location.pathname)
) {
To:
if (l.href
&& l.href != '#' // <<< Added this conditional >>>
&& l.href.indexOf('#') != -1
&& (l.pathname == location.pathname
|| '/' + l.pathname == location.pathname)
){
This will tell the script to ignore the special case, but won't prevent the browser from reacting normally to the link, so the browser may still jump to the top of the page. The special case you've mentioned is almost always used in javascript constructions to provide an anchor tag with an href attribute, because some older browsers would ignore the tag without one. The '#' was used as the URL to prevent the link from leaving the page.
Instead of the '#', you could use an empty javascript call in your link, like so:
other link
This will avoid your issues with the scrollers completely.
Thanks again, Jarred, for your help! I did come across a script that does just what I want. Here's the better script I found:
jQuery('a[href*=#]').bind('click', function(e) {
e.preventDefault(); //prevent the "normal" behaviour which would be a "hard" jump
var target = jQuery(this).attr("href"); //Get the target
// perform animated scrolling by getting top-position of target-element and set it as scroll target
jQuery('html, body').stop().animate({ scrollTop: jQuery(target).offset().top }, 1000, function() {
location.hash = target; //attach the hash (#jumptarget) to the pageurl
});
return false;
});
I am having a problem with the hashchange event in Firefox. We are using the JQuery hashchange plugin provided by Ben Alman. The code is as follows.
$(window).hashchange(function (e) {
alert("Hello");
//we want to perform a post in here.
});
var temp = "#123";
if (temp !== "") {
if (window.location.hash == temp) {
$(window).hashchange();
}
else{
window.location.hash = temp;
}
}
else {
window.location.hash = "#Home/Home";
};
Now this works fine in IE9 and Chrome, however in Firefox, I see the alert, but as soon as I click OK, the page refreshes, displays the alert again, and continues infinitely. Is there some sort of weird behaviour that Firefox uses that I am unaware of? Or is there simply some other problem that is hidden deeper?
In some browsers window.location.hash includes the # and in some don't so its better if your ignore it while comparing the hash value in your code.
Try this.
$(window).hashchange(function (e) {
alert("Hello");
//we want to perform a post in here.
});
//Remove hash from here which will be compared with window.location.hash
var temp = "123";
if (temp !== "") {
//Replace # by empty nothing
if (window.location.hash.replace('#', '') == temp) {
$(window).hashchange();
}
else{
window.location.hash = '#' + temp;//Now add the hash here
}
}
else {
window.location.hash = "#Home/Home";
};
We located the problem as occuring in MicrosoftAjax.js and found the following solution:
Firefox 6 Infinite Page Refresh With Page With Hash Tags