update parameters in URL with history.pushState() - javascript

I am using history.pushState to append few params to current page URL after making an AJAX call on my page. Now on same page based on user action, I want to update the page URL again with same or additional set of params. So my code looks like this:
var pageUrl = window.location.href + "?" + queryString;
window.history.pushState('','',pageUrl);
queryString is my list of query params.
For example, My Default page URL: http://sample.com/
After First AJAX call on same page URL should be: http://sample.com?param1=foo&param2=bar
After Second AJAX call on same page URL can be:
http://sample.com/?param1=foo,foo1&param2=bar&param3=another_foo
But with the above code my params are getting appended to URL with the params and they look like below after second AJAX call:
http://sample.com?param1=foo&param2=bar&param1=foo,foo1&param2=bar&param3=another_foo
So the params appear twice in the URL, is there any way of replacing the params in URL before pushing to History or any other better way to achieve this in javascript(jquery) ?

I think what you need is remove window.location.href and leave '?' +.
var pageUrl = '?' + queryString;
window.history.pushState('', '', pageUrl);

This function might be helpful
function updateUrlParameter(param, value) {
const regExp = new RegExp(param + "(.+?)(&|$)", "g");
const newUrl = window.location.href.replace(regExp, param + "=" + value + "$2");
window.history.pushState("", "", newUrl);
}
Edit: The following solution is simpler, and it also works if the parameter is not yet part of the URL. However, it's not supported by Internet Explorer (you don't say?).
function setQueryStringParameter(name, value) {
const params = new URLSearchParams(window.location.search);
params.set(name, value);
window.history.replaceState({}, "", decodeURIComponent(`${window.location.pathname}?${params}`));
}

In order to keep the last part of the url and just play with parameters, you can create a new URL object like so:
// e.g url: sample.com/testpage/test
var url = new URL(window.location);
url.searchParams.set('foo', 'bar');
window.history.pushState({}, '', url);
// outcome: sample.com/testpage/test?foo=bar
// you can remove, just the param part, like so:
url.searchParams.delete('foo');

Manage query parameters in the current URL
This function is similar to the other answers, but without using RegExp and string concatenations.
Args:
name - string name of the query parameter.
value - string value of the parameter.
append - if true: this function always adds a new parameter. This is very useful when you need to add two parameters with the same name, e.g.: localhost:8080/some_page?foo=100500&foo=ABC. Otherwise, the parameter will be changed (or added if absent).
function setQueryStringParameter(name, value, append=false) {
const url = new URL(window.document.URL);
if (append) url.searchParams.append(name, value);
else url.searchParams.set(name, value);
window.history.replaceState(null, "", url.toString());
}

Related

Building a window.location.href passing a query string

I'm trying to build window.location.href passing a 1 entry query string.
The MVC action method expects that entry to be an integer.
I can hardcode a '2' and it works. Of course I do not want to hardcode.
So I get the value and set a variable and attempt to pass that variable using either of the 2 cases below but it fails. I get:
{0}The parameters dictionary contains a null entry for parameter 'blogCategoryId' of non-nullable type
'System.Int32' for method 'System.Web.Mvc.ActionResult BlogsForMaintIndex(Int32)' in
'GbngWebClient.Controllers.AdminFunctions.BlogMaint.BlogMaintController'. An optional parameter must
be a reference type, a nullable type, or be declared as an optional parameter.
How do I build it properly?
Here is the JavaScript:
$(function () {
$('#buttonClose').on('click', function () {
$('#modalView').modal('hide');
// The action method expects an integer.
var blogCategoryId = #Convert.ToInt32(Session["BlogCategoryId"]);
alert('blogCategoryId: ' + blogCategoryId);
// WORKS!
//window.location.href = "/BlogMaint/BlogsForMaintIndex/?blogCategoryId=2";
// Neither of these 2 work.
//window.location.href = "/BlogMaint/BlogsForMaintIndex/?blogCategoryId=blogCategoryId";
window.location.href = "/BlogMaint/BlogsForMaintIndex/?blogCategoryId=' + blogCategoryId + '";
})
})
Here is the simplified action method:
[HttpGet]
public ActionResult BlogsForMaintIndex(int blogCategoryId)
{
}
Try this
let myurl = "/BlogMaint/BlogsForMaintIndex/?blogCategoryId=" + blogCategoryId;
window.location.href = myurl;

capturing and updating variable values after ajax request in url

I would really appreciate some help on this. I have a page that shows products in a store using laravel pagination. I have filters on the page based on brands, category, and available products. for filtering the products I am using a checkbox. if a checkbox is checked I use ajax get request and send status via URL to a controller to filter available products.
status = 1 is for available products, and status = 0 is for all products.Url is looks like this:
/Collections/Newest_Items?status=1&page=2
Here is the situation. I want to know if is it possible to change the variable value in URL and regenerate the URL base on the page number and new filters dynamically? Is it a way to get the URL of the page using jquery and change the values and then change the Url with window.history.pushState("", "", URL);?
Here is my ajax:
$(document).on('click', "#only_available", function () {
if ($('#only_available').is(':checked')) {
var status = 1;
url = '/Collections/Newest_Items?status='+status;
} else {
var status = 0;
url = '/Collections/Newest_Items';
}
window.history.pushState("", "", url);
$.ajax({
url: '/Collections/Newest_Items',
type: "GET",
data: {status: status},
cash: false,
success:
function (response) {
$('#products-load').html(response);
}
});
});
});
I do this by writing the URL by myself. In this situation, I must write the URL after every filter applied to the page. this way I cant get the page the user currently in and it goes back to the first page. But what I want to achieve here is, I want to make the Url dynamically with page number the user currently on with all filters applied to it.
You can use window.location.search which will give you something like: status=1&page=2 in your example. Then you will need to parse out those variables to get the page number you're looking for.
Ok I think I understand what you are asking for. So with each unique filter event that you are firing you need to query the current url before pushstate and get the values with something like this.
For instance if someone clicks Brand then you would get the new brand variable as well as the current status and page variables to pass with ajax like this
also just POST it instead of GET
$(document).on('click', ".brand", function () {
var brand = $(this).attr('id);
//Example how to use it:
var params = parseQueryString();
var status = params["status"]);
var page = params["page"]);
// if you have more variables than this then you would add them here and make sure you pass them along to the ajax data.
url = '/Collections/Newest_Items?status='+status+'&page='+page+'&brand='+brand;
window.history.pushState("", "", url);
$.ajax({
url: '/Collections/Newest_Items',
type: "POST",
data: {status: status, page: page, brand: brand},
cash: false,
success:
function (response) {
$('#products-load').html(response);
}
});
});
var parseQueryString = function() {
var str = window.location.search;
var objURL = {};
str.replace(
new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
function( $0, $1, $2, $3 ){
objURL[ $1 ] = $3;
}
);
return objURL;
};
tnx to #CesarBielich and #Sokies I finally manage to solve the problem. they give me part of the answer but not all.I made it unique to my question:
what we need here is the path and the parameters that nested in URL. so for getting the path of the route, we must use window.location.pathname and for getting all the parameters must use window.location.search. after that, we must combine the path and params so that the URL comes out of it. then we must add the new parameter like status after that. So that all the parameters can be accessed by the controller. both the old params and the new one. this way laravel pagination knows what url to make, in the href links to other pages.
$(document).on('click', "#only_available", function () {
if ($('#only_available').is(':checked')) {
var status = 1;
} else {
var status = 0;
}
var params = window.location.search;
var path = window.location.pathname;
var old_url = path+params;
var url = old_url+'&status=' + status;
window.history.pushState("", "", url);
$.ajax({
url: url,
type: "GET",
cash: false,
success:
function (response) {
$('#products-load').html(response);
}
});
});
});

How can I extract and then change the url path using javascript?

I am trying to extract part of the url and replace it with custom text using javascript.
For example, I want to fetch the current url such as:
mydomain.com/url_part_to_change/some-other-stuff
and then change that url to insert so that new new url is:
mydomain.com/new_url_part/some-other-stuff
Here is what I have:
function changeURL() {
var theURL = window.location.pathname;
theURL.replace("/url_part_to_change/", "/new_url_part/");
//Set URL
}
However, when I try to call the function changeURL(), it returns undefined instead of the new url.
For example if I do this:
alert(changeURL());
then what alerts is undefined
TL;DR
// update the pathname that will reload the page
window.location.pathname = myNewPathname;
Further Explanation:
Window.location ( image attached below ) provides you an object containing all the uri parts information. So, you can get this object via window.location and access the property pathname then do your stuffs. For example:
var locationObject = window.location;
var pathnameToChange = locationObject.pathname;
// do stuffs to "copy" of pathname, this will not reload the page
var myNewPathname = doSomethingMyPathname( pathnameToChange );
Additional Examples:
Alternatively, set new url using location.href. Check the MDN documentation for examples on location.assign(), location.replace(), location.reload() and notes on the different available functions
// ie.myNewUrl is something I created -> www.blah.com/updated/path
window.location.href = myNewUrl;
// or
window.location.assign(myNewUrl)
A window.location Object in Console
There are three references to further understand URI components
URI_scheme
Standards written by Tim Berners-Lee
MDN Location
Hope this helps.
This should work for you correctly:
function changeURL() {
// Get the url, just as you did
var theURL = window.location.pathname;
// Return the url
return theURL.replace("/url_part_to_change/", "/new_url_part/");
}
you are not returning any thing in function, Please make function like
function changeURL() {
var theURL = window.location.pathname;
return theURL.replace("/url_part_to_change/", "/new_url_part/");
//Set URL
}
As the others said, you don't return anything. What they are forgetting is that String.replace() just makes a copy of theURL and doesn't change theURL.
Try this:
function changeURL() {
var theURL = window.location.pathname;
theURL = theURL.replace("/url_part_to_change/", "new_url_part/");
//Set URL
return theURL;
}
alert(changeURL());
function changeURL() {
//set new path
window.location.pathname = "/new_url_part/";
//get new url
const newURL = window.location.href;
return newURL;
}
You forgot to return
function changeURL() {
var theURL = window.location.pathname;
var newURL = theURL.replace("/url_part_to_change/", "/new_url_part/");
//Set URL
return newURL;
}
alert(changeURL())//Now you won't see undefined.
This is quite an old post but just to add:
modifying window.location causes page navigations so if thats not desired create a new URL object and then you can modify the parts as needed.
in my case i needed to change the path to a value from a value in the querystring.
eg.
/*
* http://something.com/some/path?redirect=/some/other/path
* ->
* http://something.com/some/other/path
*/
let u = new URL(window.location.href)
u.pathname=u.searchParams.get("redirect")
u.searchParams.delete("redirect")
console.log(u.href)

What would the toQueryParams() will return when the url http://www.google.com in prototype

I have a scenario to get Query Params from the URL. There is a method called toQueryParams() which will get all params.
But when the URL is http://www.google.com the same method returning the same URL as query param, URL as key and undefined as value.
var param = window.location.href.toQueryParams()
This is the code I have used.
When the URL has no query parameters ie no ? or & part of the URL then there are no query parameters except for the URL.
So how I usually use this method on a given URL http://www.mywebsite.com/index.php?arg=2500&search=Smith
var param = window.location.href.toQueryParams();
if(param.arg != undefined)
{
//do things with the arg parameter
}
if(param.search != undefined)
{
//do things with the search param
alert('User has selected '+param.search+' as the search parameter');
}
So if the given param does not exist then I don't try and handle it. The method toQueryParam() is giving you a error you can handle instead of an Exception or full on JS error that stops your JS execution.
I tried in the following way, to resolve this issue.
if (window.location.search != "") { // this means the url has no query params
var param = window.location.href.toQueryParams(); // param Object will holds queryparams in key and value form
} else {
var param = new Object(); // param will has no queryParmas but, it is an empty object
}

Modifying a query string without reloading the page

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);
}
}
}

Categories