Appending parameter to URL without refresh - javascript

I know this has been asked many times before but answers were not descriptive enough to solve my problem. I don't want to change the whole URL of page. I want to append a parameter &item=brand on button click without refresh.
Using document.location.search += '&item=brand'; makes the page refresh.
Using window.location.hash = "&item=brand"; append without refresh but with a hash # which eliminates the usage/effect of the parameter. I tried to remove the hash after appending but that didn't work.
This answer and many others suggest the use of HTML5 History API, specifically the history.pushState method, and for old browsers is to set a fragment identifier to prevent page from reloading. But how?
Assuming the URL is: http://example.com/search.php?lang=en
How can I append &item=brand using HTML5 pushState method or a fragment identifier so the output would be like this: http://example.com/search.php?lang=en&item=brand without a page refresh?
I hope someone can throw some light on how to use the HTML5 pushState to append a parameter to an existing/current URL. Or alternatively how to set a fragment identifier for the same purpose. A good tutorial, demo or piece of code with a little explanation would be great.
Demo of what I've done so far. Your answers would be greatly appreciated.

You can use the pushState or replaceState methods, i.e. :
window.history.pushState("object or string", "Title", "new url");
OR
window.history.replaceState(null, null, "?arg=123");
Example with argument:
var refresh = window.location.protocol + "//" + window.location.host + window.location.pathname + '?arg=1';
window.history.pushState({ path: refresh }, '', refresh);

You can also use URL API if you want to add and remove params at the same time:
const url = new URL(window.location.href);
url.searchParams.set('param1', 'val1');
url.searchParams.delete('param2');
window.history.replaceState(null, null, url); // or pushState

If anyone wants to add a parameter to a more complex url (I mean, https://stackoverflow.com/questions/edit?newParameter=1), the following code worked for me:
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?newParameter=1';
window.history.pushState({ path: newurl }, '', newurl);
Hope this helps!

Modified Medhi answer and this did the trick
const insertParam = (key: string, value: string) => {
key = encodeURIComponent(key);
value = encodeURIComponent(value);
let kvp = window.location.search.substr(1).split('&');
if (kvp[0] === '') {
const path = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + key + '=' + value;
window.history.pushState({ path: path }, '', path);
} else {
let i = kvp.length; let x; while (i--) {
x = kvp[i].split('=');
if (x[0] === key) {
x[1] = value;
kvp[i] = x.join('=');
break;
}
}
if (i < 0) {
kvp[kvp.length] = [key, value].join('=');
}
const refresh = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + kvp.join('&');
window.history.pushState({ path: refresh }, '', refresh);
}
}

export function getHash(hash: string, key: string): string | undefined {
return hash
.split("#")
.find((h) => h.startsWith(key))
?.replace(`${key}=`, "");
}
export function setHash(hash: string, key: string, value: string): string {
let hashArray = hash.split("#").filter((h) => !h.startsWith(key));
hashArray.push(`${key}=${value}`);
return hashArray.length > 0
? hashArray.reduce((s1, s2) => `${s1}#${s2}`)
: "";
}
export function deleteHash(hash: string, key: string): string {
let hashArray = hash.split("#").filter((h) => !h.startsWith(key));
return hashArray.length > 0
? hashArray.reduce((s1, s2) => `${s1}#${s2}`)
: "";
}

Related

how pass and change url with query [duplicate]

I am creating a photo gallery, and would like to be able to change the query string and title when the photos are browsed.
The behavior I am looking for is often seen with some implementations of continuous/infinite page, where while you scroll down the query string keeps incrementing the page number (http://x.com?page=4) etc.. This should be simple in theory, but I would like something that is safe across major browsers.
I found this great post, and was trying to follow the example with window.history.pushstate, but that doesn't seem to be working for me. And I'm not sure if it is ideal because I don't really care about modifying the browser history.
I just want to be able to offer the ability to bookmark the currently viewed photo, without reloading the page every time the photo is changed.
Here is an example of infinite page that modifies query string: http://tumbledry.org/
UPDATE found this method:
window.location.href = window.location.href + '#abc';
If you are looking for Hash modification, your solution works ok. However, if you want to change the query, you can use the pushState, as you said. Here it is an example that might help you to implement it properly. I tested and it worked fine:
if (history.pushState) {
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?myNewUrlQuery=1';
window.history.pushState({path:newurl},'',newurl);
}
It does not reload the page, but it only allows you to change the URL query. You would not be able to change the protocol or the host values. And of course that it requires modern browsers that can process HTML5 History API.
For more information:
http://diveintohtml5.info/history.html
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
I want to improve Fabio's answer and create a function which adds custom key to the URL string without reloading the page.
function insertUrlParam(key, value) {
if (history.pushState) {
let searchParams = new URLSearchParams(window.location.search);
searchParams.set(key, value);
let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams.toString();
window.history.pushState({path: newurl}, '', newurl);
}
}
// to remove the specific key
export function removeUrlParameter(paramKey) {
const url = window.location.href
console.log("url", url)
var r = new URL(url)
r.searchParams.delete(paramKey)
const newUrl = r.href
console.log("r.href", newUrl)
window.history.pushState({ path: newUrl }, '', newUrl)
}
Old question, modern answer to help future devs; using the URL interface:
const url = new URL(window.location);
url.searchParams.set('key', value);
window.history.pushState(null, '', url.toString());
This makes sure you really only change the desired query-parameter.
Building off of Fabio's answer, I created two functions that will probably be useful for anyone stumbling upon this question. With these two functions, you can call insertParam() with a key and value as an argument. It will either add the URL parameter or, if a query param already exists with the same key, it will change that parameter to the new value:
//function to remove query params from a URL
function removeURLParameter(url, parameter) {
//better to use l.search if you have a location/link object
var urlparts= url.split('?');
if (urlparts.length>=2) {
var prefix= encodeURIComponent(parameter)+'=';
var pars= urlparts[1].split(/[&;]/g);
//reverse iteration as may be destructive
for (var i= pars.length; i-- > 0;) {
//idiom for string.startsWith
if (pars[i].lastIndexOf(prefix, 0) !== -1) {
pars.splice(i, 1);
}
}
url= urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : "");
return url;
} else {
return url;
}
}
//function to add/update query params
function insertParam(key, value) {
if (history.pushState) {
// var newurl = window.location.protocol + "//" + window.location.host + search.pathname + '?myNewUrlQuery=1';
var currentUrlWithOutHash = window.location.origin + window.location.pathname + window.location.search;
var hash = window.location.hash
//remove any param for the same key
var currentUrlWithOutHash = removeURLParameter(currentUrlWithOutHash, key);
//figure out if we need to add the param with a ? or a &
var queryStart;
if(currentUrlWithOutHash.indexOf('?') !== -1){
queryStart = '&';
} else {
queryStart = '?';
}
var newurl = currentUrlWithOutHash + queryStart + key + '=' + value + hash
window.history.pushState({path:newurl},'',newurl);
}
}
I've used the following JavaScript library with great success:
https://github.com/balupton/jquery-history
It supports the HTML5 history API as well as a fallback method (using #) for older browsers.
This library is essentially a polyfill around `history.pushState'.
If we simply want to update the query parameter without touching other parts of URL, there is no need to build the URL again. This is what I use:
const addQueryParam = (key, value) => {
const url = new URL(window.location.href);
url.searchParams.set(key, value);
window.history.pushState({}, '', url.toString());
};
const getQueryParam = (key) => {
const url = new URL(window.location.href);
return url.searchParams.get(key) || '';
};
Since everyone answering this seems to forget the hash, I want to add the code I'm using to keep all URL parameters:
const urlParams = new URLSearchParams(window.location.search);
/// Change some part of the URL params
if (history.pushState) {
const newurl =
window.location.protocol +
"//" +
window.location.host +
window.location.pathname +
"?" +
urlParams.toString() +
window.location.hash;
window.history.replaceState({ path: newurl }, "", newurl);
} else {
window.location.search = urlParams.toString();
}
Then the history API is exactly what you are looking for. If you wish to support legacy browsers as well, then look for a library that falls back on manipulating the URL's hash tag if the browser doesn't provide the history API.
I thought I'd add a bit to Fabio and Aram's answers. I thought I might sometimes like to preserve the hash in the url. But usually not, so I set that parameter to default to false.
replaceState still does not set the page title on Chrome. So I added a couple lines to change the title, if one is provided.
function insertUrlParam(key, value, title = '', preserve_hash = false) {
if (history.pushState) {
let searchParams = new URLSearchParams(window.location.search);
searchParams.set(key, value);
let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname
+ '?' + searchParams.toString();
if(preserve_hash) newurl = newurl + window.location.hash;
let oldTitle = document.title;
if(title !== '') {
window.history.replaceState({path: newurl}, title, newurl);
if(document.title !== title) { // fallback if above doesn't work
document.title = title;
}
} else { // in case browsers ever clear titles set with empty string
window.history.replaceState({path: newurl}, oldTitle, newurl);
}
}
}

JavasScript method to redirect most urls: (www., http://, https://)

Is there a JavaScript method that would redirect both of these:
url = 'www.google.com';
url = 'https://www.google.com';
As it seams window.open(url) requires to have the http in front of it or it would redirect to mysite.com/wwwgoogle.com
Or should I use another method to redirect?
The solution would be used for user inputted urls so I need to facilitate for as much input "styles" as possible.
You can even override window.open() function as below so any url which does not starts with http or https this function append http and redirect
please find below code
window.open = function (open) {
return function (url, name, features) {
url = addhttp(url);
return open.call(window, url, name, features);
};
}(window.open);
function addhttp(url) {
if (!/^(f|ht)tps?:\/\//i.test(url)) {
url = "http://" + url;
}
return url;
}
window.open("google.com");
window.open("https://www.google.com");
if (!url.startsWith('http://') && !url.startsWith('https://'))
url = window.location.protocol + '//' + url;
Thanks Rajesh for the comment
An alternate approach would be to use regex
/^http(s?):\/\//
Sample:
function hasProtocol(url) {
var regex = /^http(s?):\/\//;
return regex.test(url)
}
function appendProtocol(url) {
console.log("parsing url: ", url)
// Take your site's protocol instead of any default value
return window.location.protocol + "//" + url;
}
function parseURL(url) {
return hasProtocol(url) ? url: appendProtocol(url);
}
console.log(parseURL('www.google.com'))
console.log(parseURL('http://www.google.com'))
console.log(parseURL('https://www.google.com'))

Get subsection of redirect uri in query string

So I have a URL that looks like this:
localhost:9031?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcallback&scope=test
I want to redirect to the URL localhost:8080/something which makes use of part of the redirect uri but drops the /callback from it.
In order to get the redirect uri I have a method that does the following and I pass it the string redirect_uri:
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (decodeURIComponent(pair[0]) == variable) {
return decodeURIComponent(pair[1]);
}
}
}
This gives me back the string http://localhost:8080/callback. Then to get the index of callback I use the following function.
function getPosition(string, subString, index) {
return string.split(subString, index).join(subString).length;
}
Then when the button is clicked I put it all together and do:
$('.button').click(function(e) {
var query = window.location.search.slice(1);
var redirect = getQueryVariable('redirect_uri');
var index = getPosition(redirect, '/', 3);
var baseUrl = redirect.slice(0, index);
window.location.href = baseUrl + '/something';
});
This all works as intended but it doesn't seem particularly foolproof or efficient. Looking for optimizations or suggestions to use functionality of JavaScript or JQuery that I don't know of. Looking to avoid 3rd party libraries but if they are good enough I will definitely still use them.
I would recommend letting the browser do the heavy lifting of parsing the URL. Assuming you have the decoded redirect URI from the query string, you can do the following:
var myUrl = 'http://localhost:8080/callback&scope=test';
function parseURL(url) {
var a = document.createElement("a");
a.href = url;
return {
protocol: a.protocol,
hostname: a.hostname,
port: a.port,
pathname: a.pathname
};
}
var parsedURL = parseURL(myUrl);
console.log(parsedURL.protocol + '//' + parsedURL.hostname + ':' + parsedURL.port + '/something');
You can build the base url from the results and, optionally, parse the pathname if necessary.
This is based on a well known Gist to parse URLs in JavaScript, which was introduced by John Long.
function parseURL(url) {
var parser = document.createElement('a'),
searchObject = {},
queries, split, i;
// Let the browser do the work
parser.href = url;
// Convert query string to object
queries = parser.search.replace(/^\?/, '').split('&');
for( i = 0; i < queries.length; i++ ) {
split = queries[i].split('=');
searchObject[split[0]] = decodeURIComponent(split[1]);
}
// return all fragments
return {
protocol: parser.protocol,
host: parser.host,
hostname: parser.hostname,
port: parser.port,
pathname: parser.pathname,
search: parser.search,
params: searchObject,
hash: parser.hash
};
}
// using the method
(function() {
// your first url
var temp = parseURL('localhost:9031?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcallback&scope=test');
// second (the redirect_uri param);
var url = parseURL(temp.params.redirect_uri);
// now you could do:
window.location.href = url.protocol + '://' + url.host + '/whateverYoWant';
})();

window Location - only protocol, hostname and pathname

Say I have this URL:
http://www.domain.com/subpage/?somsearch#somehash?
Is there a standard way to get the following result, without hash and search:
http://www.domain.com/subpage/
This is how I do it now:
var windowLocation = window.location;
alert(windowLocation.protocol + '//' + windowLocation.hostname + windowLocation.pathname);
Thanks to Bergi, this is pretty simple:
http://jsfiddle.net/8Vr7n/3/
var url = "http://google.com/?search=bob#asdf";
var shorterUrl = url.split("#")[0].split("?")[0];
alert(shorterUrl);

JavaScript: Completing relative URL to own site

Is there a better way to write this procedure that completes a relative url for my website?
if (!url.startsWith('http')) {
url = + location.protocol + '//' + location.host + (url.startsWith('/') ? '' : '/') + url
});
You might want to consider having the server side supply the base url to your web site. The reason being, that it is typically easier to get access to the base url of the site on the server. All you need to do is have a server-side script/action that generates a script that looks like:
var siteBaseUrl = 'http://example.com/';
// use string replacement to remove any leading slash on the incoming url.
function makeAbsoluteUrl( url )
{
if (!url.match(/^http/)) {
url = siteBaseUrl + url.replace(/^\//,'');
})
return url;
}
You can refer to it in your web page as:
<script type="text/javscript" src="/scripts/baseUrl.php"> // adjust for platform
</script>
And use it as
url = makeAbsoluteUrl( url );
i think the following would handle all possible urls correctly
lstrip = function(str, prefix) {
return str.indexOf(prefix) == 0 ?
str.substring(prefix.length) :
str;
}
completeURL = function(url, host) {
url = lstrip(url, "http://");
url = lstrip(url, host);
url = lstrip(url, "/");
return "http://" + host + "/" + url
}
//test
urls = [
"http://host.com/foo/bar",
"host.com/foo/bar",
"/foo/bar",
"foo/bar",
"foo.php",
"host.com",
""
]
for(var n = 0; n < urls.length; n++)
console.log(completeURL(urls[n], "host.com"))
On first there can be for example ftp://
You should check if there is any // in url.
And instead of 'location.host' you should use 'location' with cut off the last word after the last: "/". I mean www.page.com/file.html -> www.page.com

Categories

Resources