In Vue3 app, I have a situation in which a parent component with a vue-router route is connected to a child component and its route route. The child component represents a visualisation of multiple data attributes (essentially each child is a tab and the parent hosts those tabs).
I'd like the parent route to redirect to the first child route (the first tab), when there is a first tab available, otherwise, I'd like no redirect to occur. It works fine for the redirect, but preventing the redirect is posing to be difficult, as I can't find a way to not redirect (when redirect returns to, it will go into "infinite" redirects).
Is it possible? Has anyone done this before?
The redirect is fairly straight forward:
redirect: to => {
tab = Tabs.getFirstTab()
if (!tab) {
// this leads to an "infinite" redirect (eventually it will be caught)
return to;
// I tried return null, throw Error() and return undefined too, but that
// results in an error because (in case of null/undefined) that's not a
// valid path and in case of `throw Error()`, well, the `Error`
}
return {name: 'tabmenu', params: {tabId: tab.id}}
}
I'm using version 4.0.11 of vue-router, but I also tried the latest 4.1.5.
Any help is appreciated. Maybe I need to do this entirely differently...
Related
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.
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.
In a Next.js app (full-featured, not next export) that uses React Context for state management and the file-system based router, how can you implement advanced routing?
I want to have preconditions for certain pages, so for instance if you try to load /foo but the Context doesn't have a given property set correctly, it'll route you to /bar.
The actual logic is complex and varies by page, so I'm looking for an approach that's easy to maintain.
Note that these preconditions are not authorization-related, so they do not need to be enforced server-side. It's more like "you need to fill out this form before you can go here."
The use of Context imposes some constraints:
Context must be accessed in a React component or in a custom Hook
Using a custom server for routing is not an option, as that would lose the Context - it has to use client-side routing
The current Context has to be checked (I tried decorating useRouter, but if the Context was changed right before router.push, the custom Hook saw the old values)
Update: It's also good to avoid a flash when the page loads before rerouting happens, so a side goal is to return a loading indicator component in that case.
I believe you can create a HOC and wrapped every pages with you HOC that takes arguments e.g. { redirects: '/foo' }
// pages/bar.tsx
const Page = () => {...}
export default RouteHOC({ redirects: '/foo' })(Page)
the HOC file will be something like this
// hoc/RouteHOC.tsx
const RouteHOC = ({ redirects }) => (WrappedComponent) => {
// you can do your logic here with the context.. even filling up a form here
// too also can.. (like returning a modal first before the real Component).
// useEffect work here too..
const { replace } = useRouter()
// then after you want to replace the url with other page
replace(redirects)
return WrappedComponent
}
This is pretty okay to be maintainable I think. You just create all the logic in HOC and when you want to update the logic - you just have to edit it in 1 file.
Well this is one option I can think of when reading your question - sorry if I misunderstood it in any way. There will always be a better way out there as we all know we can improve and adapt to new situation every seconds :D. Cheers 🥂!!
You can do this.
const Component = () => {
const example = useExample()
return <div id='routes'>
<a href='/example1'>Example 1</a>
{example.whatever && <a href='/example2'>Example 1</a>}
</div>
}
I have a very simple navigation stack consisting of a root page and then a model page on top of it. My root page is being set as the root by being the first page to be registered with Shell.
public AppShell()
{
InitializeComponent();
// opening view
Regester<LoginPage>();
Regester<SignUpPage>();
...
}
private void Regester<T>()
{
System.Diagnostics.Debug.WriteLine($"Regestering with shell : {typeof(T).Name} - {typeof(T)}");
Items.Add(new ShellContent { Route = typeof(T).Name, ContentTemplate = new DataTemplate(typeof(T)) });
Routing.RegisterRoute(typeof(T).Name, typeof(T));
}
}
Then I am navigating to the model sign up page using relative routing
Shell.Current.GoToAsync("SignUpPage");
or I will use absolute routing
Shell.Current.GoToAsync("///LogInPage/SignUpPage");
then I will attempt to navigate back in the stack using
Shell.Current.GoToAsync("..");
But I get this exception
Global routes currently cannot be the only page on the stack, so absolute routing to global routes is not supported. For now, just navigate to: LoginPage/
At the time of exception the CurrentState.Location property is this
Location = {///LoginPage/SignUpPage}
I don't understand why this is happening. This will also happen if I am further into the stack and doing something like trying to navigate back from a detail page. What do I need to do to be able to use GoToAsync("..") properly?
Cause:
Your path ///LogInPage is invalid . Global routes currently can't be the only page on the navigation stack. Therefore, absolute routing to global routes is unsupported.
Solution:
Navigation can also be performed by specifying a valid relative URI as an argument to the GoToAsync method. The routing system will attempt to match the URI to a ShellContent object. Therefore, if all the routes in an application are unique, navigation can be performed by only specifying the unique route name as a relative URI:
await Shell.Current.GoToAsync("SignUpPage");
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!