Window onhashchange not working - javascript

I have a web page that contains two articles. Upon loading this page, jQuery is used to hide the two articles and slide down the first one. User can click on the navigation tab to view the second article. Then go back to the first article by clicking the back button using the onhashchange event. The following is my HTML code:
<nav>
<a href='#1'>Article 1</a>
<a href='#2'>Article 2</a>
</nav>
<article id=1>
The first article.
</article>
<article id=2>
The second article.
</article>
And here is the javascript code:
function change(hash)
{
$('article:visible').slideUp();
if(hash != '')
{
$(hash).slideDown();
}
else
{
$('article').first().slideDown();
}
}
$('nav a').click(function(){
var id = $(this).attr('href');
change(id);
});
$('article').hide();
change(location.hash);
window.onhashchange = change(location.hash);
What was observed is that the page remains on the second article despite clicking the back button. I am using firefox 12.0 browser and don't know what is causing it not to work. Any help is appreciated. Thanks.

You might want to try:
window.onhashchange = change;
//and read location.hash in the change function instead
function change(){
var hash = location.hash;
...
}
or
window.onhashchange = function(){
change(location.hash);
}
window.onhashchange = change(location.hash);
If my JS ain't rusty, this fails because
calls change()
functions that have no return return undefined
you are assigning undefined to window.onhashchange - which is wrong because you're supposed to assign a function to an event.

Related

Trigger Click event of anchor tag using jQuery

I am trying to trigger the click event of an a tag using jQuery and have seen many other Stack Overflow posts about this, but can't figure out why my replications of any of them are not working. My HTML is shown here:
<c:url var="link" value="/hardwareItems" />
<a href="${link}" id="goToHardwareItems">Go
to items</a>
And then here is my jQuery/JS:
$("#form").on("submit", function() {
if (confirm("Add hardware items?")){
$("#goToHardwareItems").trigger('click');
}
else {
window.location.href = "/home";
}
});
What I have is not working though, but when I actually click on the link, I am indeed taken to the page. So the problem is that the event is simply not triggering, even though I am also getting into the if statement. What am I doing wrong?
You can read the value of href and redirect. You are already doing so.
$("#form").on("submit", function () {
// Determine where to go based on user's response
var link = confirm('Add hardware items?') ? $('#goToHardwareItems').attr('href') : '/home';
window.location.href = link;
});

FadeIN FadeOUT page transition javascript bug

When I click any of my links to take me to a new HTML page, the javascript routes me to the same HTML page and not each links individual href.
Heres my code
$(document).ready(function() {
$('body').css('display', 'none');
$('body').fadeIn(1000);
$('.link').click(function(event) {
event.preventDefault();
newLocation = $('.link a').attr("href");
$('body').fadeOut(1000, newpage);
});
function newpage() {
window.location = newLocation;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="music" class="link">Music</div>
<div id="exhibition" class="link">Exhibition</div>
<div id="contact" class="link">Contact</div>
<div id="about" class="link">About</div>
My aim is to have the Page FadeIN on load and FadeOUT when a link has been clicked, I am getting my desired effect but im just not sure what this issue with the links is - Anyone know?
As #Taplar says, when you fetch the location from the link's href, you're not getting the right one. You're just fetch the first link in the document and looking at its href attribute.
You can easily fix this by replacing this (which looks for all anchor elements in the document that have an ancestor with the link class and then returns the first one it finds):
newLocation = $('.link a').attr('href');
with this (which finds all anchor elements as a child of whatever element has the click handler registered that was clicked):
newLocation = $(event.currentTarget).find('a').attr('href');
The other thing you're doing that is tricky, but doesn't necessarily break anything, is relying on newLocation being correctly shared between the click handler and the newpage function. I would suggest instead that you explicitly pass a parameter to newpage so that it is more reusable and you can be sure where the value is coming from.
You can see this working below.
$(document).ready(function() {
$('body').css('display', 'none');
$('body').fadeIn(1000);
$('.link').click(function(event) {
event.preventDefault();
newLocation = $(event.currentTarget).find('a').attr('href');
// Pass anonymous function to fadeOut that calls newpage with newLocation
$('body').fadeOut(1000, function () { newpage(newLocation); });
});
// newpage now accepts a parameter and uses it
function newpage(location) {
// Print to console so you can see what URL is getting used
// You'll always get 404 using StackOverflow's UI since they don't have the relevant pages
console.log(location);
window.location = location;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="music" class="link">Music</div>
<div id="exhibition" class="link">Exhibition</div>
<div id="contact" class="link">Contact</div>
<div id="about" class="link">About</div>

History API with jQuery - address bar changes but doesn't refresh divs

I've been able to easily use the history.pushState to change the content of my div and have the address bar reflect a fake url. However, whenever I push the back/forward buttons the url changes back but the content remains the same. Typing in the url comes up with an error. It seems I have the first part of the history API down, but need help doing state changes.
I'm a fairly new programmer and trying to build my website in jQuery and keep the code as concise as possible.
HTML code:
<ul>
<li><button class="navButton" id="signUp" href="./content/registration.php" name="registration" title="Registration">Sign Up</button></li>
<li><button class="navButton" id="settings" href="./content/account_settings.php" name="settings" title="settings">Settings</button></li>
<li><button class="navButton" id="about" href="./content/about.php" name="about" title="About">About</button></li>
</ul>
<div id="mainContent"></div>
Javascript code:
$(document).ready(function() {
// INITIAL CONTENT ON FIRST LOAD
$("#mainContent").load('./content/start.php');
// CODE FROM HISTORY.JS
(function(window, undefined) {
var History = window.History;
if (!History.enabled) {
return false;
}
History.Adapter.bind(window, 'statechange', function() {
var State = History.getState();
History.log(State.data, State.title, State.url);
});
// EVENT LISTENER FOR NAVBUTTON CLASS TO REPLACE CONTENT IN MAINCONTENT DIV
$('.navButton').click(function(e) {
e.preventDefault();
pageurl = $(this).attr('name');
$("#mainContent").fadeOut().load($(this).attr("href")).fadeIn();
if (pageurl != window.location) {
history.pushState('', $(this).attr('title'), $(this).attr('name'));
}
});
})(window);
});
I have installed history.js but if I don't need to use it, that would be preferred. I would love to have this code corrected so the back button refreshes and this works!
So I solved this by adding an if statement under the popstate to compare the url and determine the content loaded in the mainContent div. Works!.. but discovered my original pushstate is pushing several popstates the more you click the navButtons. That question is posted Cannot find where I have a popstate loop creating multiple history entries
window.addEventListener('popstate', function() {
//WHEN BACK/FORWARD CLICKED CHECKS URL PATHNAME TO DETERMINE WHICH CONTENT TO PLACE IN DIV
if (location.pathname == "/index.php") {
$("#mainContent").load("./content/start.php");
} else {
$("#mainContent").load("./content" + location.pathname + ".php");
}
});
Advice: use the built html5 history state, to pass in objects or params or so on...
Action when you are pushing a state into browser:
history.pushState('{url:location}', $(this).attr('title'), $(this).attr('name'));
Action when your clicked back or front using the browser:
$(window).on('popstate', function(e){
if(e.originalEvent.state != null){
console.log("url to render"+e.originalEvent.state.url)
}else{
console.log("nothing in the state, do nothing")
}

anchor jumping by using javascript

I have a question that will be found very often. The problem is that nowhere can be found an explicit solution.
I have two problems regarding anchors.
The main goal should be to get a nice clean url without any hashes in it while using anchors to jump on a page.
So the structure of the anchors is:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
<div class="wrap">
<a name="one">text 1</a>
<a name="two">text 2</a>
<a name="three" class="box">text 3</a>
</div>
Okay, if you will click one of the links the url will automatically change to
www.domain.com/page#1
At the end this should be just:
www.domain.com/page
So far, so good. Now the second thing is, when you search the internet for that problem you will find javascript as a solution.
I have found this function:
function jumpto(anchor){
window.location.href = "#"+anchor;
}
and calling that function with:
<a onclick="jumpto('one');">One</a>
what will be the same like before. It will add the hash to the url. I also added
<a onclick="jumpto('one'); return false;">
without success. So if there is someone who could tell me how to solve this I really would appreciate.
Thanks a lot.
You can get the coordinate of the target element and set the scroll position to it. But this is so complicated.
Here is a lazier way to do that:
function jump(h){
var url = location.href; //Save down the URL without hash.
location.href = "#"+h; //Go to the target element.
history.replaceState(null,null,url); //Don't like hashes. Changing it back.
}
This uses replaceState to manipulate the url. If you also want support for IE, then you will have to do it the complicated way:
function jump(h){
var top = document.getElementById(h).offsetTop; //Getting Y of target element
window.scrollTo(0, top); //Go there directly or some transition
}​
Demo: http://jsfiddle.net/DerekL/rEpPA/
Another one w/ transition: http://jsfiddle.net/DerekL/x3edvp4t/
You can also use .scrollIntoView:
document.getElementById(h).scrollIntoView(); //Even IE6 supports this
(Well I lied. It's not complicated at all.)
I think it is much more simple solution:
window.location = (""+window.location).replace(/#[A-Za-z0-9_]*$/,'')+"#myAnchor"
This method does not reload the website, and sets the focus on the anchors which are needed for screen reader.
I don't have enough rep for a comment.
The getElementById() based method in the selected answer won't work if the anchor has name but not id set (which is not recommended, but does happen in the wild).
Something to bear in mind if you don't have control of the document markup (e.g. webextension).
The location based method in the selected answer can also be simplified with location.replace:
function jump(hash) { location.replace("#" + hash) }
Because when you do
window.location.href = "#"+anchor;
You load a new page, you can do:
One
<script>
function getPosition(element){
var e = document.getElementById(element);
var left = 0;
var top = 0;
do{
left += e.offsetLeft;
top += e.offsetTop;
}while(e = e.offsetParent);
return [left, top];
}
function jumpTo(id){
window.scrollTo(getPosition(id));
}
</script>
I have a button for a prompt that on click it opens the display dialogue and then I can write what I want to search and it goes to that location on the page. It uses javascript to answer the header.
On the .html file I have:
<button onclick="myFunction()">Load Prompt</button>
<span id="test100"><h4>Hello</h4></span>
On the .js file I have
function myFunction() {
var input = prompt("list or new or quit");
while(input !== "quit") {
if(input ==="test100") {
window.location.hash = 'test100';
return;
// else if(input.indexOf("test100") >= 0) {
// window.location.hash = 'test100';
// return;
// }
}
}
}
When I write test100 into the prompt, then it will go to where I have placed span id="test100" in the html file.
I use Google Chrome.
Note: This idea comes from linking on the same page using
Test link
which on click will send to the anchor. For it to work multiple times, from experience need to reload the page.
Credit to the people at stackoverflow (and possibly stackexchange, too) can't remember how I gathered all the bits and pieces. ☺
The first suggested solution of accepted solution did not work for me entirely. The main problem was when it was already jumped to hash, and hash already in url, jump did not happen again. I propose here, for the sake of completeness, somewhat more elaborate solution which works (tested in Chrome and FF). el is element with anchor tag.
el.addEventListener('click', function(ev) {
ev.preventDefault();
const href = ev.target.getAttribute('href');
const hashIndex = href.indexOf('#');
if (hashIndex !== -1) {
const hashPart = href.substring(hashIndex);
if (location.hash === hashPart) {
document.querySelector(hashPart).scrollIntoView();
}
else {
location.hash = hashPart;
}
}
})

jQuery Accordion - How to pass state using URL's?

I am trying to maintain state in my JQuery accordion menu, I'd like to avoid any server-side processing or unnecessary variable passing if possible.
Here is my code:
<ul class="accordion">
<li>
Autos
<div class="slide">
<ul>
<li>Cars</li>
<li>Motorbikes</li>
</ul>
</div>
</li>
<li>
Pets
<div class="slide">
<ul>
<li>Cats</li>
<li>Dogs</li>
</ul>
</div>
</li>
</ul>
<script type="text/javascript">
$(document).ready(function() {
var accordion = $('ul.accordion');
var show_link = '/cats';
active = FIND_SECTION_TO_OPEN_BASED_ON_URL;
accordion.accordion('activate', active );
});
</script>
By hardcoding
accordion.accordion('activate', 0 );
I can have the "Autos" menu open when the page loads, but I want to be about to dynamically find which menu or ul to open based on the URL, I'm pretty new to JavaScript and where I am stuck is on this line:
active = FIND_SECTION_TO_OPEN_BASED_ON_URL.to_int;
Does anyone know how to implement this?
(I've done a lot of research on this and have not been able to find a solution which works here)
You can use the location.hash property to get the menu to open from the URL. You would pass the menu number in a hash tag like this:
URL: http://www.domainname.com/page.html#1
And then use the JS to get it and pass it to the script:
<script type="text/javascript">
$(document).ready(function() {
var accordion = $('ul.accordion');
var show_link = '/cats';
var active = window.locatioh.hash.replace("#", "");
accordion.accordion('activate', active );
});
</script>
First off you need to pass the current page via the anchor like so (What you pass doesn't really matter, just that it's unique):
Autos
...
Pets
Then you can base the index off of the resultant hash
active = $(".opener[href='"+location.hash+"']").parents("li").index();
Here's what I did for my page. My URLS are in the format site.com/#page/accordion/tab. I also made it so that when the user clicks on an accordion or tab, the hash changes. That way if you were to navigate to the URL somewhere else, you would go to the accordion you were just looking at.
I did run into a problem though with the hashchange event. Since it's a hash, if the user goes from site.com/#page/accordion-one to site.com/#page/accordion-two, that's a hashchange not a pageload, so I put the below code in a function and bound it to the hashchange event. Problem is I have to unbind it when I change the hash in the below code, and I'm having some trouble with it still catching the hashchange event when I rebind it.
See my question here.
var hash = window.location.hash;
hash = hash.replace(/#/, "");
hash = hash.split("/");
if(typeof hash[1] !== 'undefined'){
//select campus accordion
//first disable the animation and the function that changes the hash:
$("#accordion").accordion("option", "animated", false);
$('.ui-accordion').unbind('accordionchangestart');
$("#accordion").accordion("activate", $("#accordion-"+hash[1]));
$("#accordion").accordion("option", "animated", 'slide');
$('.ui-accordion').bind('accordionchangestart', function(event, ui) {
var hash = window.location.hash;
hash = hash.replace(/#/, "");
hash = hash.split("/");
var name = $(ui.newHeader).attr("name");
var val = hash[0]+"/"+name;
sessionStorage.setItem("accordion", val);
hashChange(val);
});
}
if(typeof hash[2] !== 'undefined'){
//select tab
$(".ui-tabs").tabs("select", "#tabs-"+hash[2] );
}
My new library does this. Check it out.

Categories