Reputation: 2388
I'm having a weird issue with pushState/popstate where it seems my initial page is saved twice.
It's a bit hard to explain without an example.
something like this:
As you can see, I need to press the back button twice to get me back to www.bing.com when it should have only needed 1.
a short explanation of my page (code is at the bottom of the page):
when the page loads, initial list for the dropdown selection is retrieved via AJAX and populates the select tag.
user has option to click on 3 links which determine the contents of the dropdown selection. Example: If I click on Option B link, this fires the same AJAX from step1 but only retrieves data suitable for Option B.
The user makes a selection from the dropdown and presses search. This triggers another AJAX function which retrieves the relevant data and displays the formatted information inside the mysearchresults div.
I tried playing around with placement (e.g. before or after AJAX call) of pushState and the placement now seems the one that give me the least problem. Although I do encounter the issue I mentioned above.
Here's my code. I had to strip out a lot of code/functions to make it short and readable but please be assured the AJAX calls/data display are working.
<div id="content">
<p>
<a class="coursetype" href="#" data-type="B">Option B</a>
| <a class="coursetype" href="#" data-type="H">Option H</a>
| <a class="coursetype" href="#" data-type="BG">Option BG</a>
</p>
<form id="myform">
<label class="formlabel" for="course">Select your course</label>
<br /><select id="course" name="course"></select>
<button id="searchbutton" type="button">Search Me</button>
</form>
<div id="mysearchresults"></div>
</div>
$(document).ready(function() {
var onClickCourseTypeHandler = function(event) {
event.preventDefault();
getCourses({ type:$(event.target).data("type") });
window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", main?type="+pagevars.type);
}
var onClicksearchbuttonHandler = function(event) {
if ($("#coursecode").val().length > 0) {
searchDB({ course:$("#course").val() });
window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", "/main?&course="+$("#course").val());
}
};
$(document).on("click", ".coursetype", onClickCourseTypeHandler);
$(document).on("click", "#searchbutton", onClicksearchbuttonHandler);
try {
window.addEventListener("popstate", function(event) {
if (event.state) {
$("#content").html(event.state.html);
if (event.state.coursecode.length > 0) {
if ($("#course option[value='" + event.state.course + "']").length > 0) {
$("#course").val(event.state.course);
} else {
$("#course option:first-child").attr("selected", "selected");
}
}
}
});
} catch(exception) {
}
onLoad();
function onLoad() {
getCourses({ type:"" });
window.history.pushState({ html:$("#content").html(), course:dbvars.course }, "", "/main");
}
function searchDB(parameters) {
$.ajax({
url: baseurl+"/searchDB"
, cache: false
, dataType: "json"
, data: { format:"json", course:parameters.course }
, success: function(data, status) {
parameters.data = data;
displaySearchResults(parameters);
}
});
}
function getCourses(parameters) {
if (typeof(parameters.cacheflag) === "undefined") { parameters.cacheflag = false; };
$.ajax({
url: baseurl+"/getCourses"
, cache: parameters.cacheflag
, dataType: "json"
, data: { format:"json", coursetype:parameters.type }
, success: function(data, status) {
parameters.data = data;
populateCourses(parameters);
}
});
}
});
Upvotes: 8
Views: 5888
Reputation: 1
I found this worked great for a single page application
I decided to use this handy little function which allows pushing an item into the history if its empty or only if it has not been recalled from pressing the back button
(eliminates duplicates, so you dont have to hit the back button twice)
function historyPush(siteLocation){
if (!history.state || history.state.sitelocation != siteLocation){
var stateObj = { sitelocation: siteLocation };
history.pushState(stateObj, (siteLocation + " page"), ("index.html"));
}
}
Use: historyPush("Page1")
I then used switch case in the popstate listener function to load content back into the page:
window.addEventListener('popstate', function(e) {
console.log(e.state.sitelocation);
if (e.state.sitelocation){
switch (e.state.sitelocation){
case "Page1":
pageOne.loadContent();
break;
case "Page2":
pageTwo.loadContent();
break;
default:
console.log('Unknown Page');
}
}
});
It's not perfect for every situation such as if your site is 300 different cases you may want to head another route with the popstate listener. But for small sites, it gets the job done nicely.
Upvotes: 0
Reputation: 6678
When you load your page, it gets added to the History, so when you do history.pushState
it's added a second time.
Try replacing history.pushState
with history.replaceState
in the onload function.
Upvotes: 8
Reputation: 7059
Pass an object literal to pushState() on page load. This way you can always go back to your first created pushState.
Add to DOM ready
var obj = { html: '', coursecode: '' };
try {
window.history.pushState({
html: $("#content").html(),
coursecode: $("#coursecode").val()
}, 'just content or variable', window.location.href);
} catch (e) {
console.log(e);
}
In your eventhandler to push state:
var onClicksearchbuttonHandler = function(event) {
if ($("#coursecode").val().length > 0) {
searchDB({ course:$("#course").val() });
obj.html = $("#content").html();
obj.coursecode = $("#coursecode").val();
window.history.pushState(obj, "", "/main?&course="+$("#course").val());
}
};
When going back to your original pushstate:
$(window).on('popstate', function (ev) {
var originalState = ev.originalEvent.state || obj.html;
if (!originalState) {
// no history
// do something
return;
} else {
// do something
}
});
Upvotes: 2
Reputation: 1471
I noticed your using hashes (#) in your hrefs. Try changing the hashes (#) in your a hrefs to Javascript:void(0).
Javascript:void(0);
Hashes(#) in href will have an effect your pushState/popState.
Upvotes: 4