Accessing URL params in "href" when using "as" for Next Link? - next.js

I have a Link where I want to pass certain params in the URL but I don't want the browser to display the params.
I'm using Link's as for this:
<Link href={`/link?foo=bar`} as ={`/link`}>
<a>Link</a>
</Link>
But when I click this link and I try to access the params via router, I can't access foo=bar:
const router = useRouter()
console.log(router.query)
Returns
{
slug: ["link"],
}
And not
{
slug: ["link"],
foo: "bar",
}
So how can I access the URL params in href when using as for Link?

TL;DR You can't use as like that.
This is an incorrect usage of href and as. It would be cool if we could hide state from the end users to keep our URLs nice, clean, and compact, but obviously if you do that, you'll actually lose the state when copy/pasting the URL. That's why you can't hide query parameters in anyway (except for excluding them).
Here's the docs on href and as (dynamic routes, has little to do with hiding query params):
https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes
And to further bring up my point, imagine if we could hide state, and we redirect to this URL:
https://example.com/stateful/
Presumably there would be some behind-the-scenes browser action that persists the state.
Now we copy/paste the URL:
https://example.com/stateful/
Oops! We don't have the state anymore because the browser has no previous state to keep track of! That's why you use query parameters, because they keep the state in the URL itself.

Related

Nextjs <Link> not passing query params when using `as` [duplicate]

I have a Link where I want to pass certain params in the URL but I don't want the browser to display the params.
I'm using Link's as for this:
<Link href={`/link?foo=bar`} as ={`/link`}>
<a>Link</a>
</Link>
But when I click this link and I try to access the params via router, I can't access foo=bar:
const router = useRouter()
console.log(router.query)
Returns
{
slug: ["link"],
}
And not
{
slug: ["link"],
foo: "bar",
}
So how can I access the URL params in href when using as for Link?
TL;DR You can't use as like that.
This is an incorrect usage of href and as. It would be cool if we could hide state from the end users to keep our URLs nice, clean, and compact, but obviously if you do that, you'll actually lose the state when copy/pasting the URL. That's why you can't hide query parameters in anyway (except for excluding them).
Here's the docs on href and as (dynamic routes, has little to do with hiding query params):
https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes
And to further bring up my point, imagine if we could hide state, and we redirect to this URL:
https://example.com/stateful/
Presumably there would be some behind-the-scenes browser action that persists the state.
Now we copy/paste the URL:
https://example.com/stateful/
Oops! We don't have the state anymore because the browser has no previous state to keep track of! That's why you use query parameters, because they keep the state in the URL itself.

"Just Links" Event firing after "History Change" event

Google Tag Manager (GTM) has a built in trigger called "Just Links". In my VueJS application, using Vue Router, GTM fires a "History Change" event before firing the "Just Links" trigger.
(the "History Change" event has nothing to do with page view events)
Because of this, the Page Path GTM data-layer variable, which is supposed to be the path that the event was triggered on, is the same value as the Click URL GTM data-layer variable, which is the href value in the <a/> tag.
For instance:
User is on /support
User clicks on link to /about
Vue Router update browsers history
History Change event fires and updates all the internal values of Google Tag Manager data layer (including location and page path)
"Just Links" event fires, Page Path and Click URL values are now both /about
I'm assuming GTM/Google Analytics have some type of built in deferment strategy in place to not interfere with other things running on the main Javascript thread. So Vue Router changes routes (hence triggering the history change) before GTM/Google Analytics fire the "Just Links" trigger event.
(Strangely enough, when you use the built in Click - All Elements in GTM, the events fire in the right order.)
Has anyone else encountered this issue and come up with any type of solution? There might be a solution with just using Click - All Elements but that by default doesn't traverse the DOM tree with <a/> and strip the href for the Click URL value, which means extracting the href value on nested elements within an <a/> doesn't work. However, Just Links does do this.
Thanks!
You can look at tag firing priority. Adjust the click tag to have higher priority than the tag that's dependent on the history change trigger.
I just ran into this problem due to a site update. Instead of switching all of my "Just Links" to "All Elements" and dealing with the many headaches, I created a new Variable to reference for the page path instead of the built-in "Page Path" Variable. This Variable is basically storing what "gtm.linkClick" now treats as the previous page path because of the History Change. I'm just at beginner-level JS, so I'm sure there is a better way to write the code, but it works.
The first step is to create a new Custom HTML Tag (name it whatever you want) set to fire on All Pages and History Changes. The Tag will first attempt to store the current page path into Session Storage, or fallback to a cookie if Session Storage is not accessible. I used the {{JS - setCookie}} Variable method that was created by Simo Ahava to set cookies. There is a 2 second delay before writing the page path to storage, which is plenty of time for the "Just Links" Trigger to fire and receive the "correct" value before it is overwritten on the next pageview or history change. I gave the sessionStorage and cookie the same name "gtm.truepage".
Custom HTML Tag
<script>
function truePage() {
try {
var page = document.location.pathname;
var storage = window.sessionStorage;
if(storage) {
setTimeout(function() {
storage.setItem("gtm.truepage", page);
},2000);
} else {
setTimeout(function() {
{{JS - setCookie}}("gtm.truepage",page,1800000,"/",window.location.hostname);
},2000);
}
} catch (e) {
}
}
truePage();
</script>
Custom HTML Tag Screenshot
1st Party Cookie Variable
The next step is to create a new 1st Party Cookie Variable named "gtm.truepage". This Variable will be used as a reference for the Custom Javascript Variable. Therefore, if you change the name, you will also need to change the name in the next part.
Cookie Variable Screenshot
Custom Javascript Variable
The final step is to create a Custom Javascript Variable (whatever name you want) that you will use for your "Clicks - Just Links" Trigger. The script will first attempt to retrieve the page path that was set by the Custom HTML Tag from Session Storage and then try the 1st Party Cookie Variable.
function() {
return window.sessionStorage.getItem('gtm.truepage') || {{gtm.truepage}};
}
Custom Javascript Variable Screenshot
You can add an after hook to your router to create a custom path variable like this:
router.afterEach((to) => {
window.vuePath = to
}
Then in Google Tag Manager create a new User-Defined Variable with the JavaScript Variable type called Vue Path. Set Global Variable Path to window.vuePath.
Now you can use Vue Path instead of Page Path in your Triggers to get the correct page path.

tabs value change in url (edit url hash value), onRendered does not trigger in meteor Blaze FlowRouter

I want to get the URL # value after editing the URL link and press keyboard Enter button.
(Environment:- Meteor, Blaze, FowRouter).
from
http://localhost:3000/api/information#feedback
to
http://localhost:3000/api/information#reviews
I'm certain you can get the hash from flow router for the url. Although Flow-Router might not give it straight to you, you could parse the url for it.
You could access it in Meteor.startup() for instance.
Meteor.startup(function () {
console.log(FlowRouter.current());
});

How can I change Angular2 route query parameters without navigating to the route?

I have an angular2 page shows a list of items. I restrict the list initially by using the route parameters so my URL is something like:
http://localhost:54675/#/listing?filter={"Country":[6, 7]}
This will show items in the country with an ID of 6 or 7.
Then the users adds a third country (let's say 8) and I make a service call which updates the list. Since the list items are bound to an observable the list then updates on the screen.
This is exactly the behavior I want. But if the user bookmarks this page they only get the original route parameters and not the filtered results.
To fix this, I use:
this._router.navigate(['listing', { filter: newfilter }]);
This reloads the page with this route:
http://localhost:54675/#/listing?filter={"Country":[6,7,8]}
This keeps everything in sync and bookmarks work. However, there is a full page refresh. Other items load again - not just the filtered results. I also like the visual results better when it's just a single service call.
I need a way to change the route parameters without reloading the page.
You can use the Router only to create the URL and then use the Location to change the URL without navigating.
Something like this:
import { Location } from '#angular/common';
import { Router } from '#angular/router';
// Generate the URL:
let url = this.router.createUrlTree(['listing', { filter: newfilter }]).toString();
// Change the URL without navigate:
this.location.go(url);
For anyone who still didn't find a proper solution, try this:
this._router.navigate([], {
relativeTo: this.activatedRoute,
queryParams: {
filter: newfilter
},
queryParamsHandling: 'merge'
});
When navigating to the same route, the site doesn't reload!

How to set querystring or parameters dynamically with iron-router?

I've seen this thread on how to append/modify query parameters without duplicating, but I can't make it work.
I have a page in my Meteor application that lists items and allows filtering. I would like the filtering to be URL-based, so every change to a filter should reflect in the URL.
I use iron-router to then update the subscription accordingly.
For some reason, I can't modify the querystring though. This code doesn't trigger any action if called from a Template.templateName.events(...):
# valuePairs = ["foo=bar", "bar=foo"]
newUrl = Router.current().route.path {}, { query: valuePairs.join('&') }
Router.go newUrl
But if I call Router.go(newUrl) from the commandline, the expected result happens, i.e. the URL updates.
Is there another, preferred method to modify the query?
If not, how can I make above code work?
UPDATE - I just found that after running the event, if I go back in my browser history I can see the correct URL. It looks like something (?) triggers another page load to go back to original page.
Just based on
if I go back in my browser history I can see the correct URL
Do you suppress the actual link event? An <a href='#'> would flip flop you right back.
Template.tempyTheTemplate.events({
'click awesomeButton': function() {
// URL stuff
Router.go(magicURL);
return false; // <-- suppresses the event
}
});

Resources