Using History API for Ajax div load - javascript

In my WP site I have post content loaded into a div with ajax on a click event.
I need it now to change the url for the current post, would prefer not using hashes.
How would I implement this using my js?
JS:
jQuery(document).ready(function() {
jQuery('#main-content').on('click', '.page a', function(e) {
e.preventDefault();
var url = jQuery(this).attr('href');
jQuery('#main-content').html('<h4>Loading...</h4>').load(url+ ' #main-content');
});
});
I have researched History API but I'm not sure how to implement it with my js.

I haven't done this yet myself, but this should be very simple using the pushState: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
var stateObj = { foo: "bar" };
history.pushState(stateObj, "New Page Title", "newPath.html");
Here's an extended example, where you would replace the content, path, and title with the results from your WordPress query that would grab the next post.
<!doctype html>
<html>
<head>
<title>Push State Testing</title>
<script type='text/javascript'>
var i = 1;
function goToPage( pageNumber, pushState ) {
var content = "Hello World " + pageNumber,
path = "hello_world_" + pageNumber,
title = content,
stateObj = {"content":content}
;
document.title = title;
document.getElementById('content').innerHTML = content;
if( pushState ) {
history.pushState({index:pageNumber}, title, path);
}
i = pageNumber;
}
function nextPage() {
goToPage( i+1, true );
}
window.onload = function() {
goToPage(1);
history.replaceState({index:1}, "Hello World 1", "hello_world_1");
}
window.onpopstate = function(event) {
goToPage(event.state.index, false);
}
</script>
</head>
<body>
<div id='content'>Push State Testing</div>
<button type='button' onclick='nextPage()'>Next</button>
</body>
</html>
In answer to the question in the comments. No, you don't need to know the path of the URL until you know the content. You replace the content and do the pushState at the exact same time:
$('#mainContent').html( contentFromWp );
history.pushState( state, titleFromWp, pathFromWp );
Okay, so to take the above and try to write it for you, which I can't test, so I can't guarantee that this will be working like my above examples...it would be something like this:
jQuery(document).ready(function() {
jQuery('#main-content').on('click', '.page a', function(e) {
e.preventDefault();
var url = jQuery(this).attr('href'),
title = jQuery(this).attr('title')
;
jQuery('#main-content').html('<h4>Loading...</h4>').load(url+ ' #main-content');
document.title = title;
history.pushState({url:url,title:title}, title, url );
});
});
window.onpopstate = function(event) {
document.title = event.state.title;
jQuery('#main-content').html('<h4>Loading...</h4>').load(event.state.url+ ' #main-content');
}
Note the need for onpopstate to make the back button work. You will also want to call a history.replaceState when your webpage first loads like I did in my example so that when users go back to the very first page the first page they were on will reload...otherwise, the user will only be able to go back to the second page they navigated to since going back to the first won't have a stateObj.

Related

How do I change the URL without reloading the page?

On two different pages I'm trying to change the URL without reloading the page. I also need the forward and back browser buttons to go to the original URL, not the new URL.
I created a switch to determine if I am on one of the pages which needs to change the URL.
And then I put together a snippet for changing the URL based on this this answer. But this is where I'm stuck.
Because I'm not sure how I should be calling processAjaxData, which I assume is where I pass in the new URL slug. Also what should I be passing in for response?
<script>
var windowLoc = jQuery(location).attr('pathname'); //jquery format to get window.location.pathname
switch (windowLoc) {
case "/the-old-url-I-want-to-change/":
function processAjaxData(response, urlPath) {
document.getElementByClass("page").innerHTML = response.html;
document.title = response.pageTitle;
window.history.pushState({"html": response.html, "pageTitle": response.pageTitle}, "", urlPath);
}
window.onpopstate = function(e) {
if (e.state) {
document.getElementByClass("page").innerHTML = e.state.html;
document.title = e.state.pageTitle;
}
};
break;
case "/another-old-url-I-want-to-change/":
function processAjaxData(response, urlPath) {
document.getElementByClass("page").innerHTML = response.html;
document.title = response.pageTitle;
window.history.pushState({"html": response.html, "pageTitle": response.pageTitle}, "", urlPath);
}
window.onpopstate = function(e) {
if (e.state) {
document.getElementByClass("page").innerHTML = e.state.html;
document.title = e.state.pageTitle;
}
};
break;
}
</script>
If all you're actually trying to do is change the url, and you don't mind the page reloading when the user clicks the back button, then you can remove most of the example code. The only part of this whole business that you need is the pushstate. So just pull that out and place it directly in your switch. Something like:
<script>
var windowLoc = jQuery(location).attr('pathname');
switch (windowLoc) {
case '/the-old-url-I-want-to-change/':
window.history.pushState(null, '', 'YOUR-MODIFIED-URL')
break
case '/another-old-url-I-want-to-change/':
window.history.pushState(null, '', 'YOUR-MODIFIED-URL')
break
}
</script>

twitter share button quirk

Link to my in codepen: codepen.io/neel111/pen/dRBQNY?editors=1010
When the tweet button is clicked then it redirect to the page to tweet in the twitter, with a preselected text to tweet.
The JavaScript code used there is given below just for a quick look:
//-------------quotes--------
(function(){
window.addEventListener("load", makeRequest);
function makeRequest(mk){
document.getElementsByClassName("buttonQ")[0].addEventListener("click", makeRequest);
function reqListener(rl) {
if(httpR.readyState === XMLHttpRequest.DONE) {
var quote;
if(httpR.status === 200) {
quote = JSON.parse(httpR.responseText);
document.getElementsByClassName("quote")[0].innerHTML = quote[0].body;
} else {
alert("There was a problem with the request!")
}
}
}
var httpR;
httpR = new XMLHttpRequest();
httpR.onreadystatechange = reqListener
httpR.open("GET", "https://quote-api.glitch.me/pull/1", true);
httpR.send();
}
//----------------------tweet-------------------
window.addEventListener("load", function() {
document.getElementsByClassName("buttonT")[0].addEventListener("click", tweetEvent);
})
function tweetEvent(twt) {
//twt.preventDefault();
document.getElementsByClassName("quote")[0].normalize();
var tweetBody = document.getElementsByClassName("quote")[0].childNodes[0].nodeValue;
var URLBase = document.getElementsByClassName("twitter-share-button")[0].getAttribute("href");
var URLExtended = URLBase + "?hashtags=quotes&text=" + encodeURIComponent(tweetBody);
document.getElementsByClassName("twitter-share-button")[0].setAttribute("href", URLExtended);
}
})();
Quirk:
when the tweet button is clicked for the first time after the page is loaded/refreshed then the preselected text in the redirected page to tweet is
Preselected_text(quote)_from_the_main_page #tweet
But after the first click, everytime the tweet button is click the preselected text in the redirected page to tweet is
Preselected_text(quote)_from_the_main_page?hashtags=quotes #quotes
Where i am doing wrong?
So I think the problem is that you are modifying the href of the anchor tag and inserting the modified href into the dom. What I would do instead is to get rid of the in the button and build the url like you are but instead of modifying something in the dom just call window.open(extendedUrl);
Something like this should get you started:
window.addEventListener("load", function() {
document.getElementsByClassName("buttonT")[0].addEventListener("click", tweetEvent);
})
function tweetEvent(twt) {
//twt.preventDefault();
document.getElementsByClassName("quote")[0].normalize();
var tweetBody = document.getElementsByClassName("quote")[0].childNodes[0].nodeValue;
var url = "https://twitter.com/intent/tweet?hashtags=quote&text="+encodeURIComponent(tweetBody);
return window.open(url);
}
})
As you can see I have simplified the url building and then passed the resulting url to window.open which will open the url in a new window/tab (depending on user preference in their browser... find more on that here).

Difficulty Loading New Page w/ Javascript

I'm writing a basic Flask app. I have a page called /searchByCollege that consists of a bunch of buttons, each with a team name as their text, and .college as their class.
I've written some JS so that, when the user clicks on a button, it'll load /searchByCollege/collegeName, where collegeName is the text of the button they just clicked on. Here's what I have:
<script>
$('.college').on('click', function() {
var baseURL = $('#baseURL').text();
var finalURL = baseURL + "/" + this.text();
window.location.href = finalURL;
return false;
})
</script>
I didn't originally include return false; and nothing happened upon clicking a button. Then I added return false; and I got the same result. I've inspected the HTML and the base URL is correct (it's just /searchByCollege). I've looked at the requests as I click on the button and none are being made.
I've loaded jQuery above this through Google's CDN so that's not the issue.
Any other ideas?
Thanks for the help,
bclayman
this.text()
needs to be changed to
$(this).text()
You need to wait for the document to load by using $(document).ready:
<script>
$(document).ready(function(){
$('.college').on('click', function() {
var baseURL = $('#baseURL').text();
var finalURL = baseURL + "/" + this.text();
window.location.href = finalURL;
return false;
});
});
</script>
I could not figure out where you were getting the 'baseURL' Since you are using just JQuery you need to call .value and not .text()
<button class="college" value="CSU">CSU</button>
$('.college').on('click', function(){
var baseURL = "/searchByCollege";
var finalURL = baseURL + "/" + this.value;
return false;
});
you can try this
window.location.hostname = finalURL;
window.location.pathname = '';

history.js stops firing statechange event after pressing back button 2 times

One of my customer has a lot of webistes based on lots of CMS (Wordpress, Drupal and so on). He wanted a generic directory, where professionals can register and share information. It is "generic", as it can be installed on any website (declined according to the website's business).
I developed it inside an iframe, as this can be installed on any CMS, and there were other good reasons to do it this way (CSS, SEO...). But as iframe-browsing is transparent for the navigation bar, I needed to do some tricks to allow visitors to copy/paste professionals's urls, share and fav them. I used history.js to update the navbar's URL, and when direct-accessing the iframe I redirect the user to the right "main website"'s page.
But my problem come when clicking the "back" button. For some reasons, the "statechange" event is not properly fired when clicking "back" a second time.
I developed a demo, you can see my problem live here, and you can download it here.
As you can see on the log div, when you click B and C, you'll get:
Push: /a.html
Push: /b.html
statechange trigered
Push: /c.html
statechange trigered
If you go back once, you'll get:
statechange trigered
Pop: /b.html
And if you go back a second time, you'll get:
Push: /c.html
statechange trigered
Instead of:
statechange trigered
Pop: /a.html
So my question:
What is going on here ?
main.html
<iframe id="my-test" src="a.html" width="500" height="500"></iframe>
<div id="log"></div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-browser/0.0.6/jquery.browser.min.js"></script>
<script src="history.js/scripts/bundled/html4+html5/jquery.history.js"></script>
<script type="text/javascript">
var test_url = 'http://so.ocarina.fr/test';
// used to avoid listening events trigered by the script itself
var manual_state_change = true;
// used to avoid pushing the previous page
var is_back = false;
$(document).ready(function () {
$('#my-test').load(function () {
// when iframe has loaded, we replace the navbar's url by
// the one from iframe's source.
if (!window.is_back) {
window.manual_state_change = false;
var History = window.History;
if (History.enabled) {
var url = $('#my-test').get(0).contentWindow.location.href;
if (url.indexOf('blank') > 0) {
return;
}
if (url.indexOf('test') > 0) {
url = url.substring(url.indexOf('test') + 4);
if (url.length === 0) {
url = '/';
}
}
$('#log').append('Push: ' + url + '<br/>');
var title = $("#my-test").contents().find("title").html();
document.title = title;
History.pushState({url: decodeURIComponent(url + '')}, title, window.test_url + decodeURIComponent(url + ''));
window.manual_state_change = true;
}
}
window.is_back = false;
}).trigger('load'); // triggered once to replace main.html by a.html
var History = window.History;
if (History.enabled) {
History.Adapter.bind(window, 'statechange', function () {
// if user clicks back, we should change the iframe's location
// to the backward url from history stack.
$('#log').append('statechange trigered <br/>');
if (window.manual_state_change === true) {
window.manual_state_change = false;
var state = History.getState();
var url = state.data.url;
$('#log').append('Pop: ' + url + '<br/>');
window.is_back = true;
$('#my-test').attr('src', window.test_url + url);
$('#my-test')[0].contentWindow.location = window.test_url + url;
window.manual_state_change = true;
}
});
}
});
</script>
a.html
<title>Test A</title>
<script type="text/javascript">
if (top.location === self.location) {
window.location = 'main.html';
}
</script>
<div id="content">
<p>This is test A</p>
Go to test B
</div>
b.html
<title>Test B</title>
<script type="text/javascript">
if (top.location === self.location) {
window.location = 'main.html';
}
</script>
<div id="content">
<p>This is test B</p>
Go to test C
</div>
c.html
<title>Test C</title>
<script type="text/javascript">
if (top.location === self.location) {
window.location = 'main.html';
}
</script>
<div id="content">
<p>This is test C</p>
<p>Go back to A using your backward button...</p>
</div>
I finally found my mistake: when clicking on my iframe's links, browser already add an entry to the history, so I shouldn't add an entry using pushState, but simply replace the current history entry using replaceState.
Bonus: we don't need to handle statechange, browser does anything as naturally as usual. Cool!
See the working demo here.
My code becomes:
<iframe id="my-test" src="a.html" width="500" height="500"></iframe>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-browser/0.0.6/jquery.browser.min.js"></script>
<script src="history.js/scripts/bundled/html4+html5/jquery.history.js"></script>
<script type="text/javascript">
var test_url = 'http://so.ocarina.fr/test2';
$(document).ready(function () {
$('#my-test').load(function () {
// when iframe has loaded, we replace the navbar's url by
// the one from iframe's source.
var History = window.History;
if (History.enabled) {
var url = $('#my-test').get(0).contentWindow.location.href;
if (url.indexOf('blank') > 0) {
return;
}
if (url.indexOf('test') > 0) {
url = url.substring(url.indexOf('test2') + 5);
if (url.length === 0) {
url = '/';
}
}
var title = $("#my-test").contents().find("title").html();
document.title = title;
History.replaceState({}, title, window.test_url + decodeURIComponent(url + '')); // YES!
}
}).trigger('load'); // triggered once to replace main.html by a.html
});
</script>

How to restore original content after window.popstate?

The following code goes on pushing a new URL to the state object, while dynamically changinf the page's content as well. However, when I start pressing the Back button and return to the original page, the original content is not shown, instead the next page's content is retained. How do I achieve it?
<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<script>
$(document).ready(function(){
a = 0;
$("p").click(function(){
var stateObj = { note : ++a };
history.pushState(stateObj, "page 2", "http://localhost/foo/"+a);
$(this).text(a);
});
window.addEventListener('popstate', function(e){
if (history.state){
$("p").text(e.state.note);
if (location.href == 'http://localhost/hist.php') { $('p').text('If you click on me, I will disappear.'); }
}
}, false);
$("div").click(function() { alert(e.state.note); });
});
</script>
</head>
<body>
<p>If you click on me, I will disappear.</p>
<div>Hi</div>
</body>
</html>
It is your responsability to update the page content on popstate. The browser only handles the state.
I had an application, where I replace the main content of a page while navigation through an menu tree. I also updated the page title according to the new content.
When I just go back an forth in AJAX loaded pages, I can save the url to load in the StateObj. But on going back to the initial page, there is no state, and no saved title to restore.
I decided to reload the whole page, when I go back to the initial history state:
var doc_state={'title': ''};
var popped = ('state' in window.history && window.history.state !== null), initialURL = location.href;
function loadDocument(path,title){
$('#document_area').html('<img src="spinner.gif" />');
$('#document_area').load(path+'?ajax=true');
document.title = title;
}
$(document).ready(function(){
$('a.ajax_link').click(function(event){
var path=$(this).attr('href');
var title=$(this).text();
doc_state['title']=title;
event.preventDefault();
loadDocument(path,title);
window.history.pushState(doc_state,document.title,path);
});
$(window).bind('popstate', function(event){
// Ignore inital popstate that some browsers fire on page load
var initialPop = !popped && location.href == initialURL;
popped = true;
if ( initialPop ) return;
var state = event.state;
if (!state){
state=history.state; // FF
}
if (state){
var title= state.title;
loadDocument(location.pathname, title);
}
else window.location.reload();
});
}

Categories