Multiple routers with vue - javascript

I am running a PHP application where I will need some pages to have the ability to completely swap out views. I need a fully fledged router because I need to take advantage of the history mode API.
It is easy enough to do something like this with the Vue router:
const router = new VueRouter({
routes: [
{ path: '/', component: DefaultView },
{ path: '/map', component: MapView }
]
});
Within PHP I simply load the router like so and pass the PHP generated backend data to both views:
<router-view data="<?= $data ?>"></router-view>
This works for one page, but what if I want to have another page with a completely different set of routes? The router needs to be made aware what page it is on in order to differentiate between different sets of routes.
I either would need to check the URL of pass in a prop like I am already doing with my data. I am unsure how to read the prop data from the router though.
What would be a good way to deal with this?

you simply make two named router-views
and pass different data to these router-views.
<router-view class="view one"></router-view> //default
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
},
{
path: '/map',
components: {
default: Foo2,
a: Bar2,
b: Baz2
}
}
]
Or use nested route views //children
routes: [
{ path: '/page1', component: page1,
children: [
{
path: 'route1',
component: route1
},
{
path: 'route2',
component: route2
}
]
},
{ path: '/page2', component: page2, ... }
]

Related

Angular navigate content without change component

I have 2 components: componentA and componentB
When I click a button in componentA, this will navigate to componentB, but componentA and componentB have same filter and left sidebar, the only thing different is content
ComponentA.html
<app-new-post></app-new-post>
<app-filter-forum></app-filter-forum>
<app-view-topic [topicData]="viewContent"
(showSubTopic)="onShowSubTopic($event)"></app-view-topic>
ComponentA.ts
onShowSubTopic() {
this.router.navigate([ComponentB])
}
ComponentB.html
<app-new-post></app-new-post>
<app-filter-forum></app-filter-forum>
<app-sub-topic></app-sub-topic>
Is there any ways to use 1 component to display both of them?
The above solution will definitely work, but ideally, you should be using the Angular router. Which is what I think you're trying to achieve here.
Here would are the changes you would need to implement:
someRootComponent.html
<app-new-post></app-new-post>
<app-filter-forum></app-filter-forum>
<router-outlet></router-outlet>
At this point you can get rid of ComponentA and componentB. Your routes would look like this:
const routes: Routes = [
{ path: 'view-topic', component: ViewTopicComponent },
{ path: 'sub-topic', component: SubTopicComponent },
{ path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page
];
The eventual problem you'll run into is managing state. There are many approaches to handling this. If you wanted to support deep linking, then I suggest doing this:
const routes: Routes = [
{ path: 'view-topic/:topicId', component: ViewTopicComponent },
{ path: 'sub-topic/:subTopicId', component: SubTopicComponent },
{ path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page
];
This is how you would link to a topic:
<a [routerLink]="['/view-topic', topic.id]">
The Angular router docs are excellent, it's available here:
Angular Router Docs
you can use ngIf to check to show the different dom
ComponentA.html
<app-new-post></app-new-post>
<app-filter-forum></app-filter-forum>
<app-view-topic [topicData]="viewContent" *ngIf="!showBComponent"
(showSubTopic)="onShowSubTopic($event)"></app-view-topic>
<app-sub-topic *ngIf="showBComponent "></app-sub-topic>
ComponentA.ts
let showBComponent: boolean = false;
onShowSubTopic(e: any): void {
this.showBComponent = true;
}

Named router outlet doesn't render template in lazy loaded route

I have a problem with my angular 8 app, not rendering into a named router-outlet.
The routes are:
routes.module:
const routes: Routes = [
...
{
path: 'settings', loadChildren: './settings/settings.module#SettingsModule', canActivate
},
]
settings.module
RouterModule.forChild([
{
path: '', component: SettingsComponent
},
{
path: 'profile', component: ProfileComponent, outlet: 'settings_o'
},
{
path: 'users', component: UsersComponent, outlet: 'settings_o'
}
])
settings.component.html
<nav mat-tab-nav-bar color="primary" class="bg-whitesmoke primary">
<span mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="[{outlets: {settings_o: [link.link]}}]"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{link.label}}
</span>
</nav>
<router-outlet name="settings_o"></router-outlet>
When I click a link, the url in the address bar changes (e.g. to http://localhost:4200/settings/(settings_o:profile)), but no content is rendered to settings_o, nor do the components get loaded. There is no error in the console.
link.link is, for example simply profile like in settings.module's routes.
What do I need to change?
This is a known bug which has been discussed a lot: https://github.com/angular/angular/issues/10981
As far as I know it hasn't been solved completely but there are workarounds: https://github.com/angular/angular/issues/10981#issuecomment-454425220
You should give the lazy loaded module a default route and define the child routes for the components that you would like to open in the named outlet, for example:
RouterModule.forChild([
{
path: "default",
component: SettingsComponent,
children: [
{ path: "profile", component: ProfileComponent,outlet: "settings_o" },
{ path: "users", component: UsersComponent, outlet: "settings_o" }
]
}
]);
Of course you have to change the navigation to the SettingsComponent accordingly: routerLink='/settings/default'
I made a Stackblitz which is not an exact copy of your code but which shows how it can be solved: https://stackblitz.com/edit/angular-nctjpv
By the way, in your original solution, if you placed the named router outlet in the root component, I think it would display the child component but in the wrong place.

How to use component-nesting with vue-router?

I'm pretty new to Vue and I just can't find a good way how to use nested components alongside with vue-router.
What I have so far (some not-important code omitted):
index.html
<body>
<div id="app">
<router-view></router-view>
</div>
app.js
const router = new VueRouter({
routes: [{ path: '/login', component: Login }]
})
const app = new Vue({
router,
}).$mount('#app')
components/Login.vue
<template>
<h1>Please log in</h1>
</template>
This works perfectly well - I navigate to /login and it shows me the message in h1 tag. If I create more components, like Register or ResetPassword and add them to the router, it still works well. But the problem is that there is some repeating code in those components (for example, I want all the auth-related pages to have blue background) so I'd like to somehow create a "parent" component, that would define stuff that is same for all the "children" components. Something like:
Auth component (makes the page-background blue)
-> Login component (shows the login form)
-> Register component (shows the registration form)
I know I can do this through route's "children":
const router = new VueRouter({
routes: [
{ path: '/', component: Auth, children: [
{ path: '/login', component: Login }
{ path: '/register', component: Register }
]}
]
})
But with this configuration, there is the main route path: '/', which is completely wrong - I don't want it here - I don't want the Auth component to be used "standalone" - I want it just as a "wrapper" for the nested components.
What is the best way to solve this problem?
The way I've solved this issue is to use a base path redirect.
{ path: '', redirect: '/to/path' },
in your case it would be
const router = new VueRouter({
routes: [
{
path: '/',
component: Auth,
children: [
{ path: '', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/register', component: Register }
]
}
]
})
This ensures that

Vue-Router Abstract Parent Routes

I am trying to migrate my current site to vuejs. The site map must be:
/login
/signup
/password-reset
/browse
/search
... dozens of other routes
As some of these routes share a lot of fx, I've made them the children of parent routes:
[{ // public routes
path: '/',
component: Auth,
children: [
{ path: '/login', component: Login },
{ path: '/signup', component: Signup },
{ path: '/password-reset', component: PasswordReset },
]
},
{ // routes behind Authentication
path: '/',
component: Home,
children: [
{ path: '/browse', component: Browse },
{ path: '/search', component: Search }
]
}]
The problem is obvious: The Auth and Home base components now are technically the same route path and I get routing errors. Since I will have a lot of routes sharing the same base component and fx, I'd like to have them be children of these abstract states.
Question 1: How can I implement these routes and their parent abstract states without conflict and without having to add all the wrapping logic to the children?
Question 2: How can I make it so the parent states () are not routeable or if they are, the default to a child state?
Whenever more than one route shares the same path, the first route in the array takes priority. So you need to put the Home route before the Auth route. That way, the / path will always match the Home route and not the Auth route. That also means that it is impossible to route directly to the Auth route, which is what you want.
If you do not want the Home route to be accessible, you can specify a redirect that should occur when it is matched exactly:
{
path: '/',
component: Home,
redirect: '/browse', // Redirect to path, or
redirect: { name: 'browse' }, // Redirect to named route
children: ...
}
If your Auth component has no auth-specific UI, you mightn't want to use "abstract" routes like this to enforce the authentication. There's plenty of information about how to achieve this in vue-router; here's one way:
// Routes
{
path: '/profile',
component: Profile,
meta: { auth: true },
}
// Router hooks
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.auth) && !authenticated) {
next('/login');
} else {
next();
}
});

vue-router won't render template on nested route

So I have a route like this:
const routes = [{
path: '/',
component: Home,
children: [
{
path: "/health"
children: [
{
path: 'overview'
component: Overview
},
{
path: 'blood',
component: Blood
}
]
}
]
}]
and in the Home component I have something like this:
<template>
<div id="home">
<router-view></router-view>
</div>
</template>
But when I navigate to the /health/overview and /health/blood routes, the templates corresponding to the components won't render. I checked the apps $route objects, they correctly detect the routes and the components. Just the template won't render. I also have a <router-view> in my App.vue if that helps.
Is it not possible to have multi nested routes? Or am I missing something?
The health route should be like this:
{
path: 'health', // not '/health'
component: Health, // this can just be a dummy component with a <router-view/>
children: [...],
},
If you don't need the Health component at all for any reason (i.e. you don't have any shared functionality or template across each child), you can just remove the health route completely and replace it with this instead:
{
path: 'health/overview',
component: Overview,
},
{
path: 'health/blood',
component: Blood,
},

Categories

Resources