How to ignore search queries when pushing a new path? - javascript

Problem
I want to push a new path as an addition to the URI where search queries are set.
Example:
Current location: https://example.com/foo?bar=123&foobar=123
When I call history.push('newPath') I will end up with https://example.com/newPath. What I want to get, however, is https://example.com/foo/newPath.
One solution would be to call history.push('foo/newPath') or if I would save the current path and add the wanted path (newPath) on top, but I was hoping that history.push might have a way to handle this?

I want to push a new path as an addition to the URI where search
queries are set.
To change/append the path you can use URL which won't affect your query parameters.
// maybe from window.location.href?
const href = 'https://example.com/foo?bar=123&foobar=12'
let url = new URL(href)
url.pathname = url.pathname + '/newPath'
console.log(url) // https://example.com/foo/newPath?bar=123&foobar=12

Related

What's the best way to return a clean URL by removing unwanted query params while keeping others?

I need to have redirect rules for this page's routes that has unwanted query params. So this is what it looks like with the default unwanted query params.
https://some-test-url.com/b/laptops/1117?clubId=6612&offset=0&rootDimension=pcs_availability%253AOnlinepipsymbBrand%253ADell&searchCategoryId=1117&selectedFilter=all&sortKey=relevance&sortOrder=1
It should redirect to the cleaned URL. It should clean these from the URL under these conditions which are the default values. For the limit it should be removing both 48 and 20. I'm assuming that any other query params should be left that aren't listed below since they're not defaults.
searchCategoryId=all
selectedFilter=all
sortKey=relevance&sortOrder=1
limit=48 on desktop or limit=20 on mweb
clubId ever
offset=0
So the cleaned URL from above should look something like this
https://some-test-url.com/b/laptops/1117?rootDimension=pcs_availability%253AOnlinepipsymbBrand%253ADell
But for example if it's not a default query params for example
www.test.com/blah?offset=40&selectedFilter=online&clubId=3422
it should return
www.test.com/blah?offset=40&selectedFilter=online
What would be the best way to handle this? I tried doing it with regex but I wasn't able to get the expected result since it's a bit more complicated. Thanks for the help!
You can use URLSearchParams which is supported on all major browsers: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
Something like:
const params = new URLSearchParams(window.location.href);
for (var key of params.keys()){
// do something with logic from your allow/block list
// such as removing it:
params.delete(key);
}

get raw value from URL parameter in reactjs

I've got a react component that allows users to unsubscribe from an email, and there's a hash being passed along with the unsubscribe link so we know what mail item the request is associated with. Unfortunately the hash sometimes has some URL-specific characters in it, like + and /. Right now I'm doing something like this to get the data from the hash to pass to the unsubscribe service:
const query = new URLSearchParams(useLocation().search);
const campaignId = query.get('campaign') ?? '';
the problem is that when I pass the campaign in to the unsubscribe, and (for example) the campaig hash has a + in it, that gets converted to a space.
Is there a better way to get this string, or a way to "un-encode" it?
I ended up doing something fairly inelegant-- but it works. I used the decodeURIComponent() as suggested by #ofri in the comments above, but the spaces were not being converted back to +. So this is what I came up with:
const query = new URLSearchParams(useLocation().search);
const campaignId = query.get('campaignId') ?? '';
// then when we create the axios payload:
campaignId : decodeURIComponent(campaignId.replace(/ /g, '+'))

Is there any workaround for "NavigationDuplicated" exception in Vue.js when pushing query parameters in the url while remaining on the same path

Current url is
/search
New url should be
/search?foo=bar
I just want to update my query params being on the same route as a result of application of some filters on the page
My code:
this.$router.push({query: params})
There is a way to handle the "NavigationDuplicated" error using a catch block but that only supresses the error, the query parameters in the route are still not updated.
Related issue:
How to use router.push for same path, different query parameter in Vue.js
But this gives the path '/' but i need to remain on the same page
You can add catch to workaround this error:
this.$router.push({query:params}).catch(() => {})
You can use history.pushState(), it will modify the URL without pushing the router.
https://stackoverflow.com/a/71042001/19222560

Add or update current URL parameter using angular's $location

I have a page with multiple parameters in my URL. I am trying to write a function to use on the click of an element. I want it to check if parameter pthree exists. If it does, update it to a new value (not duplicate it). If it does not exist, append it to my current URL and reload the page.
I am running into an issue when I try to update the current URL.
My current URL structure:
mypage?pone=99.9999999&ptwo=-44.4444444&pthree=1&pfour=1&pfive=1
Controller snippet:
$scope.test = function (){
$location.search('pthree', 0);
}
This partially works. It updates my URL, but it adds #?pthree=0 to the end of my current URL.
The result I would like instead is:
mypage?pone=99.9999999&ptwo=-44.4444444&pthree=0&pfour=1&pfive=1
Any thoughts on what I could do to get my desired result? Thanks in advance!
Here is what worked for me. I found that I needed to set the HTML5 mode of my app. Read more about HTML5 mode here: https://docs.angularjs.org/guide/$location.
After this, I ran into another issue when calling $location.search({ pThree: '0' }. It started writing over all of my other parameters. For example, the URL structure was changing to ?pThree=0. To solve this I had to read all parameters, update pThree, and then write all back.
I hope this helps someone else.
You can do this pretty easily by just doing:
// existing url with params
// http://myurl.com/path/view/etc?param1=abc&param2=def
// add your new param to the search() object
$location.search().param3 = 'ghi';
// set your search again with the updated search object
$location.search( $location.search() );
This will update your url like so:
// http://myurl.com/path/view/etc?param1=abc&param2=def&param3=ghi

When I push a new URL to Backbone.history, the query params stays?

Let's say I'm using Backbone pushstate and I navigate to a page with query params:
domain.com/user/111?hello=123
When I execute this:
Backbone.history.navigate('/settings', true);
My settings page loads perfectly, but the ?hello=123 stays in the URL...
domain.com/settings?hello=123
And that query param stays in the URL everywhere I navigate the site...
Backbone routing and query parameters are an unhappy marriage. Problems are well documented in this GitHub issue.
The core problem is that Backbone.Router is designed to work with URL hash fragments as well as the pushState API. When using hash URLs the query string precedes the hash, and is never matched in the route. With pushState the query string is part of the URL fragment, and requires a different route expression.
Let's say you'd have a route search, and that route would optionally take parameters q, sort and type. As a query string that would look something like:
search?q=kittens&sort=asc&type=images
The problem is, that for users of older browsers, Backbone will revert to hashchange based routing, and the route will become:
?q=kittens&sort=asc&type=images#search
The plugin you use tries to work around this problem, but doesn't resolve the core issue.
If possible, you should consider not using query strings, and pass any state information using optional fragments in your route expressions. The previous example routes would then become:
//pushState
search/q/kittens/sort/asc/type/images
//hash fragment
#search/q/kittens/sort/asc/type/images
Using (optional) route parts and :captures (docs), you could represent this URL with the following expression:
var Router = Backbone.Router.extend({
routes: {
"search(/q/:query)(/sort/:sort)(/type/:type)": "search"
},
search: function(query, sort, type) {
console.log(query, sort, type); //-> "kittens", "asc", "images"
}
});
As long as the route fragments are in the specified order, this will match urls with none, any and all parameters, for example:
search //-> undefined, undefined, undefined
search/q/kittens/type/images //-> "kittens", undefined, "images"
search/sort/asc/type/images //-> undefined, "asc", "images"
This way you don't have to worry about third-party query string libraries or browser compatibility. And if you ask me, the latter type of URL looks cleaner as well.
You don't have to use the backbone-query-parameters plugin to deal with this anymore, just make sure that you have the latest version of Backbone and then overwrite the loadUrl method inside History.prototype.
// Regex to match search query strings
var searchStripper = /\?.*$/g;
// Attempt to load the current URL fragment. If a route succeeds with a
// match, returns `true`. If no defined routes matches the fragment,
// returns `false`.
loadUrl: function(fragmentOverride) {
var fragment = this.fragment = this.getFragment(fragmentOverride);
fragment = fragment.replace(searchStripper, ''); // remove the search query parameter
var matched = _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
return true;
}
});
return matched;
},
Not sure if it's too late. I came to the same problem and I can say it with confidence: it's a bug caused by backbone-query-parameters.
I actually inspired by your post. In the early stage of my current project, I introduced backbone-query-parameters, it worked well. But later on, backbone made some changes so backbone-query-parameters cannot grap the parameters any more. Not until recently, I found the author upgraded backbone-query-parameters. I pulled it in again, and it worked.
Then, you know. I cam to the same problem and feel really frustrated. I never doubted about backbone-query-parameters, not until I saw your post.
I removed the plugin and equipped with my own code, now my history works like a charm.
There are numerous ways to fetch the get parameters. Mine is just one of them, but it does the job for me. Just for your reference I post it here.
getParams: ->
rtn = {}
if window.location.search.length > 0
queryStringRegex = /^\?(.*)/
match = queryStringRegex.exec window.location.search
param_string = match[1]
if param_string.length > 0
params_array = param_string.split("&")
for value in params_array
temp = value.split("=")
rtn[temp[0]] = decodeURI(temp[1])
rtn
Just in case, my routes will be like this
"path(?*queryString)" : "pathAction"

Categories

Resources