Popstate not working as expected(needs multiple clicks) - javascript

I am trying to learn History Web API, but already have problems at the first hurdle.
I am able to get history.pushState working, but have issues with popstate. It works fine when clicked for the first time after AJAX page load, but if I load that same page again, I need to click back button twice. If I load it one more time, I need to click back three times, and so on.
Here is my code:
$(function(){
var $main = $('#main');
$(window).on('popstate', function () {
loadPage(location.href);
});
$(document).on('click', 'a', function(){
var href = $(this).attr('href');
history.pushState({}, '', href);
loadPage(href);
return false;
})
loadPage = function(href){
$main.load(href);
}
})

You need the state Object. In your case you using a empty Object wich will not work proberly. Just test is with a Object like this : {"url":yourUrlVar}
Reference: History.pushState - MDN

Related

How to make sure hashtag attach the ajax updated content?

I had created a pagination with ajax. When user click the page number, it called the ajax function. I want to remember the previous ajax html data when user hit the back button. Therefore, I am trying to add the hash to each page. eg. when user click page 3, url is www.site.com/#3, page 4, is www.site.com/#4. It works OK so far. However, when I click the back button, it always load the second last page no matter the hash is 3 or 4. So, how can I make sure each hash attach to the ajax's update content? if the url is www.site.com/#4, it will always load the page 4 content. Appreicate.
$('#pagination a').click(function(e){
e.preventDefault();
$this = $(this).attr('href');//href is the page number
var data = {
action: 'post_pagination_ajax',
post_num : $this,
};
$.ajax({
url: ajax_front_gallery.ajaxurl,
type:'POST',
data: data,
success: function(data){
$('.post-content').html(data);
}
});
window.location.hash = $this;
return false;
});
You have a click event, however when you hit back button there is no any click event, browser just loads previous page from history. So what you have to do is to make also a load event. Final result will look something like this:
function loadContent ( url,data ) {
$.ajax({
url: url,
type:'POST',
data: data,
success: function(data){
$('.post-content').html(data);
}
});
}
$('#pagination a').click(function(e){
e.preventDefault();
var hash = $(this).attr('href');
var data = {
action: 'post_pagination_ajax',
post_num : $(this).attr('href')
};
loadContent( ajax_front_gallery.ajaxurl,data );
window.location.hash = hash;
return false;
});
$( window ).load(function() {
var data = {
action: 'post_pagination_ajax',
post_num : window.location.hash
};
loadContent( ajax_front_gallery.ajaxurl,data );
});
Edit:
Even though this solves your problem i would recommend doing it other way. Since you change hash and want to load content based on hash. There is a hashchange event for that. So you could do:
$(window).hashchange( function(){
var data = {
action: 'post_pagination_ajax',
post_num : location.hash
};
loadContent( ajax_front_gallery.ajaxurl,data );
});
//Trigger hash-change if page laoded with existing hash
$(window).hashchange();
And you won't need any click event on a preventing the default behaviour, because default behaviour of changing hash in url is what you want.
So I am not really sure if there is a standard how browser handle the url fragment (hash). The problem is that setting the hash is originally used for saying the browser where to scroll (with anchors etc.: http://www.w3schools.com/jsref/prop_loc_hash.asp). So when you set the hash most browser will put a new state in the history but will not use the current state of the DOM but use the old one before the hash was set.
But I can say, when ever I implement asynchrone paging with Javascript I do it similiar like you do, but I check the hash on the page load and load the specific page, so you always have the result you want.
I think this is the way the Google search works and it was the source of my idea.

HTML5/jQuery: pushstate back issue

I have in my code the ajax call that loads my content. What I want is to add a deeplinking effect and from my research I found out that only raw coding will do it.
This is what I have so far:
jQuery("#sw_layered_cat a").click(function(){
var url_ajax = jQuery(this).attr('href');
history.pushState('', '', url_ajax);
});
This is working pretty well because the controller of ajax brings the results on my screen, and in another controller I change the url of the page. When it comes to go back to the previous url, I get the correct url but no content is loaded.
No matter what I try I cannot get the previous default url. For example, if I am in ../default/shop/paper.html(1) and move forward to ../default/shop/paper/paper-pads.html(2) and press back, I get the correct url (1) but the content is not loading.
I know I have to do something like:
window.onpopstate = function(event){ loadPage(//param); }
but I cant get the right param.
window.onpopstate = function () {
// Something like this. document.location should provide the data you want
// at any rate
loadPage(document.location);
};

How to reload div content on click

I have a jQuery script that loads content into a div. When you click on a menu item, the content gets loaded inside of "contentarea" and the URL gets updated. That part works perfectly. However, I would also like to be able to click inside of the div (once content has been loaded into it), and load another page in its place. For example, the Forms page gets loaded into contentarea, and inside of the forms page there is a link to the contact us page. When I click on the link, I would like for the forms page to be cleared from content area and the contact us page to be loaded in its place. See the following image:
With the way my script is setup right now, content only loads when I click from outside of the div.
Here's the code I need to modify:
<script type="text/javascript">
//Jquery loader
function getHash() {
return window.location.hash
}
$("a").on("click", function (e) {
page = this.href.replace("#", "") + ".html",
hash = $(this).prop("hash");
$('#contentarea').load(page, function () {
if (page.match("home.html")) {
history.pushState('', document.title, window.location.pathname);
} else {
location.hash = hash;
};
});
});
//on pageload
history.pushState
var hash = getHash();
if (hash) {
$("a[href='" + hash + "']").trigger("click");
} else {
$("a[href='#home']").trigger("click");
}
</script>
Any help would be greatly appreciated!
Since you are using jQuery, i would propose this:
$(document).ready(function() {
$(document).on( 'click', 'a', function( e ) {
$('#contentarea').load( e.target.href );
});
});
But if you are creating an app, and you are applying it globally, in your case i would reconsider your structure to avoid major changes on your code later. I've passed on that, because you have to manage states (variables of page/state if they exist: like errors, title, url, and obviously content) and determine which of them is active or not to pass to next page or not. Then you have to filter links that you don't want to propague to your history states handler cause you just don't want to...
On some cases, you can't apply existent frameworks on your project because the best approach is to use their code on your framework (yes, create your own framework).
I hope this could help you! :)

Jquery mobile changepage with back button not working

I have 4 pages within my JQM main HTML file. When I switch to one using changepage it's fine the first time, but I use a data-rel=back button to go back and this switches to the previous page but then bounces back to the page that has the back button. Should I just not use data-rel=back? If not what alternative is there?
Using JQM 1.3.1
$("#listView").on("vclick","li", function(e) {
//ajax call to get results for second page
$.mobile.changePage('#second');
}
Button on second page
Back
To go to previous page programmatically, use the below code. You need also to use stopImmediatePropagation(); to stop jQuery Mobile from jumping twice, which will result showing the same page.
Edit: I tested it on iPad, preventDefault() is required too.
Demo
$(document).on('vclick', '[data-rel=back]', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
var back = $.mobile.activePage.prev('[data-role=page]');
$.mobile.changePage(back, {
transition: 'slide',
reverse: true });
});
Use this one. You can redirect between pages using location.hash=" " with page id in it.
DEMO http://jsfiddle.net/yeyene/uJz3E/7/
$("#listView").on("vclick","li", function(e) {
// second is the page you want to redirect on click.
location.hash = "second";
});

Can I prevent history.popstate from triggering on initial page-load?

I'm working on a site that serves content via AJAX.
If you click an item in the menu, a content div gets updated with $.get response, nothing fancy.
I'm implementing history.pushState to allow navigation with the browser's back/forward button.
I have the following to load content on history navigation:
$(function() {
$(window).bind("popstate", function() {
$.getScript(location.href);
});
});
The problem is, when a page is loaded for the first time, this function does $.getScript so the page is loaded immediately again. The first time the page is loaded it renders the initial HTML view, then on the second load it renders the JS view, since its a JS request.
How could I prevent this event from firing on pages with HTML requests?
Using the native HTML5 History API you're going to run into some problems, every HTML5 browser handles the API a little bit differently so you can't just code it once and expect it to work without implementing workarounds. History.js provides a cross-browser API for the HTML5 History API and a optional hashchange fallback for HTML4 browsers if you want to go down that route.
For upgrading your website into a RIA/Ajax-Application you can use this code snippet:
https://github.com/browserstate/ajaxify
Which is part of the longer article Intelligent State Handling which goes into explanations about hashbang, hashes and the html5 history api.
Let me know if you need any further help :) Cheers.
You need to get the event.originalEvent
// Somewhere in your previous code
if (history && history.pushState) {
history.pushState({module:"leave"}, document.title, this.href);
}
$(window).bind("popstate", function(evt) {
var state = evt.originalEvent.state;
if (state && state.module === "leave") {
$.getScript(location.href);
}
});
When the popstate event is fired on page load it will not have a state property in the event object. This allows you to check if the event is fired for a page load or not.
window.onpopstate = function (event) {
if (event.state) {
// do your thing
} else {
// triggered by a page load
}
}
When the browser first loads, it always fires a popstate event. So you need to determine if this popstate is yours or not.
When you do your pushState, make sure you have a state object. That way you can check it later.
Then on the popstate handler, check the state object :)
$(function() {
$(window).bind("popstate", function(data) {
if (data.state.isMine)
$.getScript(location.href);
});
});
// then add the state object
history.pushState({isMine:true},title,url);
Let me know if you need any more help :)
I use the below approach to change the address bar and save the current state including the current HTML body, and I reload it on the back button click without any other AJAX call. All gets saved in your browser:
<script type="text/javascript">
$(document).ajaxComplete(function(ev, jqXHR, settings) {
var stateObj = { url: settings.url, innerhtml: document.body.innerHTML };
window.history.pushState(stateObj, settings.url, settings.url);
});
window.onpopstate = function (event) {
var currentState = history.state;
document.body.innerHTML = currentState.innerhtml;
};
</script>

Categories

Resources