How do I change the URL without reloading the page? - javascript

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>

Related

how to refresh the page with original URL when URL has been changed via history.pushState()

I have used history.pushState() and now if the user refreshes the page then it is refreshing current URL which is not an original URL.
I tried detecting refresh page with a cookie, hidden filed but it is not working.
window.onload = function() {
document.cookie="PR=0";
var read_cookies = document.cookie;
var s = read_cookies;
s = s.substring(0, s.indexOf(';'));
if( s.includes("1"))
{
window.location.href = "https://www.google.com";
}
else{
document.cookie="PR=1";
}
loadURL();
};
function loadURL()
{
document.cookie="PR=1";
document.getElementById("visited").value="1";
var str="abc/b cd";
str=str.replace(/ /g, "-");
history.pushState({},"",str);
}
when user is refreshing the page I need original URL on that time.
This might be helpful. But you need control over the pushed url.
// this goes to your 'original' url
window.addEventListener('beforeunload', function (event) {
sessionStorage.setItem('lastPage', window.location.href)
}
// page with your pushed url
if (sessionStorage.getItem('lastPage') === 'PAGE_YOU_DONT_WANT_TO_BE_REACHABLE_DIRECTLY') {
window.location = 'PAGE_YOU_WANT'
}
I'm interested what the use case for this is. As far as my knowledge goes you can't suppress the refresh event completely.

Toggle between functions - only execute either one on pageload

I want to toggle between two jQuery functions. It has to be done on page load - and each page load should only execute one of the scripts.
This is what I got so far:
HTML:
<button class=".click">Click me</button>
Script:
$(function() {
if (window.location.href.indexOf("addClass") > -1) {
$("body").addClass("test");
}
else {
$("body").addClass("secondtest");
}
$('.click').on('click', function() {
console.log("Clicked");
var url = window.location.href;
if (url.indexOf('?') > -1) {
url += '?param=addClass'
} else {
url += '?param=1'
}
window.location.href = url;
});
});
This Gets me a bit on the way, the first click adds ?param=1 on the first click - nothing happens - second click it adds the ?param=addClass and the body gets the class. If I click again it adds ?param=addClass every time.
I want one of the script to run as default - then I want the first button click to reload and run the other script instead. If I click once more I want it to reverse the url so the first script loads, like a toggle.
I now there is an easy way to just toggle classes, but I specifically need to run one of two scripts on a new page load.
Update:
$(function() {
if (window.location.href.indexOf("addClass") > -1) {
$("body").addClass("test");
}
else {
$("body").addClass("secondtest");
}
$('.click').on('click', function() {
console.log("Clicked");
var url = window.location.pathname;
var url = window.location.href;
if (url.indexOf('?param=1') > -1) {
url = url.replace("param=1", "")+'param=addClass'
} else {
url = url.replace("?param=addClass", "")+'?param=1'
}
window.location.href = url;
});
});
This set the body class on first page load - then first click ads ?param=1 but doesnt change the body class. Second click replaces ?param=1 with ?param=addClass and changes the body class - after that the toggles works. So How do I make it work from the first click?
This will be the default functionality, if no query string is present then add ?param=1:
var url = window.location.href;
if(url.indexOf('?param=1')==-1 )
{
window.location.href = url+"?param=1";
}
This will be the onclick functionality to toggle the urls as it is replacing the existing functionality.
$('.click').on('click', function() {
var url = window.location.href;
if (url.indexOf('?param=1') > -1) {
url = url.replace("param=1", "")+'param=addClass'
} else {
url = url.replace("?param=addClass", "")+'?param=1'
}
window.location.href = url;
});
If you want to toggle the classes as well you can use .toggleClass("test secondtest")
The issue you have is in this if:
var url = window.location.href;
if (url.indexOf('?') > -1) {
url += '?param=addClass'
} else {
url += '?param=1'
}
Scenario 1: /test.html
indexOf('?') will be negative. You will then redirect the user to /test.html?param=1
Scenario 2: /test.html?param=1
indexOf('?') will then be positive. You will then redirect the user to /test.html?param=1?param=addClass
Scenario 3: /test.html?param=addClass
indexOf('?') will then be positive. You will then redirect the user to /test.html?param=addClass?param=addClass
So... what is wrong?
You are using window.location.href. Excellent for setting the path but bad if you want to actually manage the query parameters.
Solution
var url = window.location.pathname;
var hasParams = window.location.href.indexOf('?') > -1;
if (hasParams) {
url += '?param=addClass'
} else {
url += '?param=1'
}
window.location.href = url;
Since you are redirecting on the same host (seen with your code), you only need the pathname. pathname doesn't include parameters (?key=value&...) and can be used to redirect a user on the same domain.

Fix back button issue on load more pagination style

HTML
<div class="moreButton">
<a class="more" id="<?php echo htmlspecialchars($page);?>">More</a>
</div>
AJAX
$(function(){
$('.more').live('click', function(){
var page = $(this).attr('id'); //get the last id
$.ajax({
type : 'GET',
url : 'functionality/js/paginate.php',
data : { page : page, per_page : per_page, last_page : last_page },
beforeSend: function(){
$('.more').html(img);
if(history.pushState){
history.pushState(null, null, '#' + page);
}else{
location.hash = '#' + page;
}
},
success: function(data){
$('.more').remove();
$('.main-content').append(data);
}
});
});
});
I've implemented a load_more style of pagination. The problem here is the usual for infinite scrolls, when a user clicks a post and comes back with back button, he/she should get the previous number of loaded posts, but only initial posts are loaded. I'm trying to integrate the history.pushState functionality based on what I found googling, but doesn't seem to get it working. What am I missing here?
There are two key parts to saving states using browser history. The pushState function allows you to add to the history stack (essentially like going to a new page). It also allows you to store a javascript object as the "state". This will come in handy when the state is "popped" off the stack (e.g. the browser's "back" button is pressed).
Browsers throw a popstate event which you can use to determine if the browser is going back to a previous state. You can access it with window.onpopstate. To watch for a hash change you can use window.onhashchange.
if ("onpopstate" in window) {
window.onpopstate = function (event) {
if (event.state && event.state.pageID) {
fetchData(event.state.pageID);
}
};
}
if ("onhashchange" in window) {
window.onhashchange = function () {
if (location.hash) {
fetchData(location.hash.substr(1));
}
};
}
function fetchData(pageID) {
// Load some content
}
function saveState(pageID) {
if (history.pushState) {
history.pushState({ pageID: pageID }, null, "/page/" + pageID);
} else {
location.hash = pageID;
}
}
Here you need to define a function to check hash update as if hash updates(User clicks on back/forward button) it should update data of the page according to URL.

Using History API for Ajax div load

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.

Back button / backspace does not work with window.history.pushState

I have made a solution for my website which includes using ajax to present the general information on the website. In doing this, I am changing the URL every time a user loads some specific content with the window.history.pushState method. However, when I press backspace or press back, the content of the old url is not loaded (however the URL is loaded).
I have tried several solutions presented on SO without any luck.
Here is an example of one of the ajax functions:
$(document).ready(function(){
$(document).on("click",".priceDeckLink",function(){
$("#hideGraphStuff").hide();
$("#giantWrapper").show();
$("#loadDeck").fadeIn("fast");
var name = $(this).text();
$.post("pages/getPriceDeckData.php",{data : name},function(data){
var $response=$(data);
var name = $response.filter('#titleDeck').text();
var data = data.split("%%%%%%%");
$("#deckInfo").html(data[0]);
$("#textContainer").html(data[1]);
$("#realTitleDeck").html(name);
$("#loadDeck").hide();
$("#hideGraphStuff").fadeIn("fast");
loadGraph();
window.history.pushState("Price Deck", "Price Deck", "?p=priceDeck&dN="+ name);
});
});
Hope you guys can help :)
pushState alone will not make your page function with back/forward. What you'd need to do is listen to onpopstate and load the contents yourself similar to what would happen on click.
var load = function (name, skipPushState) {
$("#hideGraphStuff").hide();
// pre-load, etc ...
$.post("pages/getPriceDeckData.php",{data : name}, function(data){
// on-load, etc ...
// we don't want to push the state on popstate (e.g. 'Back'), so `skipPushState`
// can be passed to prevent it
if (!skipPushState) {
// build a state for this name
var state = {name: name, page: 'Price Deck'};
window.history.pushState(state, "Price Deck", "?p=priceDeck&dN="+ name);
}
});
}
$(document).on("click", ".priceDeckLink", function() {
var name = $(this).text();
load(name);
});
$(window).on("popstate", function () {
// if the state is the page you expect, pull the name and load it.
if (history.state && "Price Deck" === history.state.page) {
load(history.state.name, true);
}
});
Note that history.state is a somewhat less supported part of the history API. If you wanted to support all pushState browsers you'd have to have another way to pull the current state on popstate, probably by parsing the URL.
It would be trivial and probably a good idea here to cache the results of the priceCheck for the name as well and pull them from the cache on back/forward instead of making more php requests.
This works for me. Very simple.
$(window).bind("popstate", function() {
window.location = location.href
});
Have same issue and the solution not working for neither
const [loadBackBtn, setLoadBackBtn] = useState(false);
useEffect(() => {
if (loadBackBtn) {
setLoadBackBtn(false);
return;
} else {
const stateQuery = router.query;
const { asPath } = router;
window.history.pushState(stateQuery, "", asPath);
},[router.query?.page]

Categories