Multiple named router-outlet - component imported but not initialized and rendered - javascript

I'm using multiple named angular 8 router-outlet in a web app. All the routerLink seems to work as it changes the URL but components in my 2nd router-outlet are imported but not initialized nor rendered.
I made a Stackblitz available here : https://stackblitz.com/edit/ng-multiple-router-outlet?file=src/app/app.component.ts
As you can see, when you click on the sidebar, under photos you have a second navigation level by clicking on Google or Facebook but nothing is rendered.
In modules, components used in other modules and RouterModule are well exported to be accessible, I don't see what I've done wrong.
I tried to declare the routes with both forRoot and forChild methods, I put some logs, but I'm running out of clues.
Thanks for your help !

Angular router is pretty simple once you understand how nested routes works there.
Let's imagine a simple configuration:
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
children: [
{ path: 'child', component: ChildComponent }
]
}
])
How would you use router-outlet to cover all routes above?
app.component.html
\
contains
\
<router-outlet></router-outlet>
\/
renders
\
HomeComponent
home.component.html
\
contains
\
<router-outlet></router-outlet>
renders
\
ChildComponent
The main takeaway here is that router-outlet renders component depending on router context. Once it renders component a new context is created and all router-outlet's declared at this level will look at children configuration.
The same is true for named routes.
You've generated the link like:
(selection:facebook//sidebar:photos)
It means that these named routes should be at the same root level. But you defined <router-outlet name="selection"></router-outlet> at nested level inside rendered by router LibraryComponent.
Let's add this outlet at the same level as 'sidebar':
<router-outlet name="sidebar"></router-outlet>
<router-outlet name="selection"></router-outlet>
and it actually works stackblitz
Now let's come back to your attempt. If you want to render selection components inside selection.component.html then you should be using nested named routed links:
selection.component.html
[routerLink]="['.', { outlets: { selection: [routeName] } }]"
\/
relative path
The above binding will generate nested links like (sidebar:photos/(selection:facebook))
Now you need to move SelectionRoutes configuration to children property of photos path:
selection.module.ts
imports: [
CommonModule,
RouterModule, //.forChild(SelectionRoutes)
],
sidebar.routes.ts
import { SelectionRoutes } from '../selection/selection.routes';
...
export const SidebarRoutes: Route[] = [
{ path: 'photos', component: LibraryComponent, outlet: 'sidebar', children: SelectionRoutes },
Stackblitz Example
Update
In order to make facebook as a default subroute you create a route with redirectTo option like:
export const SelectionRoutes: Route[] = [
{ path: 'facebook', component: FacebookComponent, outlet: 'selection' },
{ path: 'google', component: GoogleComponent, outlet: 'selection' },
{ path: '', redirectTo: '/(sidebar:photos/(selection:facebook))', pathMatch: 'full', },
]
Stackblitz Example

Related

In Angular 8 Router parent route remains the same when navigating to the route with other parent

I'm working on a project written on Angular (v8.2.8) and use router with the same version. The architecture of the routing is the following:
I have app-routing.module.ts where I have 3 entries for routes array:
Shell.childRoutes([...array of routes]),
Case.childRoutes([...array of routes]),
{ path: '**', redirectTo: '/', pathMatch: 'full' }
Shell - that is parent component for app internal pages.
Case - that is parent component for app public pages.
Method child routes do almost the same for both components:
export class Shell {
static childRoutes(routes: Routes): Route {
return {
path: 'app',
component: ShellComponent,
children: routes,
canActivate: [AuthenticationGuard],
data: { reuse: true }
};
}
}
and
export class Case {
static childRoutes(routes: Routes): Route {
return {
path: '',
component: CaseComponent,
children: routes,
data: { reuse: true }
};
}
}
App have dashboard component for Shell parent and home component for Case parent.
User loads the page at home route and markup is the following:
<app-root>
<app-case>
<router-outlet></router-outlet>
<app-home></app-home>
</app-case>
</app-root>
And after redirect to the dashboard route I expect to have the following markup:
<app-root>
<app-shell>
<router-outlet></router-outlet>
<app-dashboard></app-dashboard>
</app-shell>
</app-root>
But I receive
<app-root>
<app-case>
<router-outlet></router-outlet>
<app-dashboard></app-dashboard>
</app-case>
</app-root>
So the exact issue is in test case:
User is on a route which exist in Shell parent.
Then if user will be redirected to any route in Case parent - the parent will stays the Shell. And the same situation works in other direction. If Case route was load first, after redirect to Shell route parent will stay the case.
I tried to edit different parameters in the childRoutes method, but no success, I just don't understand is it the issue in the engine, or I just need to specify some additional parameters.
Basically I resolved this issue. For those who had the same issue - for me issue was in custom route reusable strategy which was implemented. When I was switching from Case to Shell route-reusable-strategy function shouldReuseRoute returned true, so route was reused.

Angular Routes: Problem defining a NotFoundComponent with multiple routings files

I am creating a NotFoundComponent so that every non-existing url, a friendly page will apear to the user.
My Angular 6 project has 5 features(CRUDL):
CompanyComponent,
EmployeeComponent,
BranchComponent,
BenefitsComponent,
MainComponent
Each component have it own .module and .routing, for example the company.routing.ts defines the route like this:
export const routes: Routes = [
{
path: "branch",
component: EmptyComponent,
}
...
#NgModule({
imports: [
RouterModule.forChild(routes),
...
it also defines its childrens, like path: "branch/:id".
So, i have no problem with the way i built the routing.
The problem I am facing now is the way I can define a path to the NotFoundComponent.
Because I don't have a single file where I define my routes, if I put the definition of the /404 page on the on the bottom of routers definition in the main.routing.ts, every other route defined on the features(like the company.routing.ts) will be redirected to the /404, since angular uses the first match strategy.
Things i tried so far:
on the main.routing.ts:
export const routes: Routes = [
{
path: "main",
component: MainComponent,
},
{
path: "404",
resolve: {
routeTitle: TitleResolver,
},
component: NotFoundComponent,
},
{
path: "",
pathMatch: "full",
redirectTo: "/main",
},
{
path: "**",
redirectTo: "/404",
}
if I put this way, when I try accessing the route /company (defined in the company.routing.ts) it will be redirected to the /404.
I also tried defining it on any a routing of one of my features, like on the company.routing.ts
{
path: "**",
redirectTo: "/404",
}
Than, a funny thing happened, if I define this piece of code on the benefits.routing.ts, i can access /benefits but /branch, /employee and the rest of the routes will be redirected to /404.
if I define it on branch, I can access /benefits, /branch but /employee and the rest of the routes will be redirected to /404.
I could just place this code on the last feature loaded and it would work but I would like to know if I can solve this with another approach, can't I define a route that I want to be the last one loaded?
thanks in advance.

Angular 6: How to use multiple loadChildren with same route?

I have something like:
const routes: Routes = [
{
path: ':path', component: SiteRoot, children: [
{ path: '', loadChildren: '../modules/maple/template.module#TemplateModule' }
]
}
];
I wish to use this :path url to match multiple module dynamically. each module have there own internal Route.
Is there any way I can achieve this?
I tried ViewContainerRef with ResolveComponentFactory but it does not work with module only component. Event with NgModuleFactoryLoader, Routes cannot be applied.
EDIT, to make everything clear:
What I am trying to achieve is to have different module display on same route path. For example user can see user dashboard at "home" path, and admin can see admin dashboard at "home" path as well.
This feature is defined by business logic, so, I cannot change admin dashboard to another url
I think you are trying to create your routing module incorrectly. Anyway, you should write why you need this. I'll try to answer. Every module should have it's own path, so routing module should be strict and static. If you trying it for security, use guards and hide item from menu component.
If you need URLs like this: "/username1/profile", "/username2/profile" you can simply use code like yours, or use lazy loading. create routing file for parent module:
{ path: ':username', loadChildren: '../users/user.module#UserModule' }
Than create routing file for child module:
{ path: '', loadChildren: 'UserComponent', children: [
{ path: '', redirectTo: 'profile' },
{ path: 'profile', component: ProfileComponent}
]
}
Updated By your case:
by your case you can change your HTML file. For example in app.component.html if your code is:
<div>
<router-outlet></router-outlet>
</div>
You can change it with:
<div *ngIf="isLoggedIn | async">
<admin-panel></admin-panel>
</div>
<div *ngIf="(!isLoggedIn | async)">
<router-outlet></router-outlet>
</div>

Angular 4 lazy load module doesn't work with named child outlet

I am trying to implement lazy loading for a module. This module has a bunch of child routes with a unique outlet name. This doesn't seem to work when I try to visit the routes.
This can be seems from this example that I saved: https://plnkr.co/edit/NNXAoZItM00RIIxzemts?p=preview
You can see that I have the child route set to
{ path: 'list', component: HeroListComponent, outlet: 'abc' },
in hero-routing.module.ts
and router outlet to:
<router-outlet name="abc"></router-outlet>
in hero.component.ts
I should be able to visit localhost:3000/heroes/(abc:list) when I am running it locally, but it doesn't seem to work.
Note: You can run the plunker example locally by download the zip file and running npm install then npm start.
The child routes do not seem to work with default unamed routes.
Change the lazy loaded module routes to include a redirect from default unamed route to a named route.
const routes: Routes = [
{ path: '', redirectTo: 'start', pathMatch: 'full' },
{ path: 'start', component: HeroComponent,
children: [
{ path: 'list', component: HeroListComponent, outlet: 'abc' },
{ path: ':id', component: HeroDetailComponent }
]
}
];
Finally change the navigation link for 'heroes' lazy loaded module to include the named outlet information. Be sure to specify the complete url as '/heroes/start', do not leave it to the default '/heroes'.
<a [routerLink]="['/heroes/start',{outlets: {abc:['list']}}]"
routerLinkActive="active">Heroes</a>

When do you use React-Router getChildRoutes?

I'm confused about how and when you can use getChildRoutes because it's part of PlainRoute. How do you access PlainRoute in the first place? So instead of building <Route> components I can use <PlainRoute>s and then inside the component it was rendering it will have getChildRoutes? What does partialNextState refer to?
Plain routes are ordinary JavaScript objects, and can be used in <Router> like so:
const routes = {
path: '/',
component: App,
indexRoute: {
component: Home,
},
childRoutes: [
{ path: 'page1', component: Page1 },
{
path: 'page2',
component: SomeWrapper,
childRoutes: [
{ path: 'subpage1', component: Subpage1 },
],
},
],
};
ReactDOM.render(<Router history={ browserHistory } routes={ routes }/>, document.body);
That is, the indexRoute - if present - corresponds to adding an <IndexRoute> as a child of a <Route>, and childRoutes corresponds to adding child <Route>s. They both accept the same attributes as the corresponding JSX tags accept props.
Plain routes are useful for example for splitting your route definition up in multiple files. In a large app, it may be useful to decouple pages from their exact location in the route hierarchy, and build the route hierarchy up by importing childRoutes to immediate parent modules instead of having the entire route hierarchy hardcoded into the root module. It is also easy to build reusable navigation components like tab containers and breadcrumbs if you use plain routes, as the routes themselves can then be sent as props defining the links those components should include.
getChildRoutes and getIndexRoute are asynchronous variants of the childRoutes and indexRoute attributes, and allow for dynamic routing and code splitting. For example, you could for fun make getChildRoutes refer to itself recursively. I don't know what partialNextState is supposed to be, and I've never needed to use it.

Categories

Resources