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>
Related
I am working on an application that uses lazy-loaded modules for each main part of the app. I have one that I two router outlets in a primary one and one called details.
const routes: Routes = [
{ path: '', component: BooksComponent, resolve: {books: BooksResolver},
{ path: ':id', component: BookDetailsComponent, resolve: { book: BookResolver},outlet: "details"},
];
with the HTML like below
<router-outlet></router-outlet>
<router-outlet namme="details"></router-outlet>
Then each book item I have a router link like below
[routerLink]="['/', { outlets: { details: [book.id] } }]"
When I click on an item in I get the following error: ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: '53'. Currently I have the details displaying in the primary router outlet but I can not get the details to show when a user clicks on the book item. I am not sure why this is not working I looked in the documentation and This seems to be the correct way of doing it haveing all routes at the same level. ANy help would be appreciated.
I think you have a problem with multiple exits, so LET me give you a little example that I hope makes sense to you
{
path: 'a', component: AComponent, children: [
{path: 'd', component: DComponent},
{path: 'c', component: CComponent,outlet:'right'},
// a/(d//right:c)
]
},
In the component AComponent
<a [routerLink]="['./',{outlets:{primary:['d'],right:['c']}}]">d/c</a>
<router-outlet></router-outlet>
<router-outlet name="right"></router-outlet>
Multiple egress can be regarded as child routes
I am developing an ecommerce application, and one major feature is that this app should have multiple themes. The total number of themes could be 100 or even more. However, these themes all have the same data (For example: all home page have same banner images, new product, feature product data.) .
I know I can use ng-template or TemplateRef to determine which piece of HTML should display. But since I have over 100 themes, both ng-template or TemplateRef methods will load a lot of extra files. So I think I need some sort of lazy load, when a component loads the data then lazy loads the correct HTML template. So how can I have this work?
Looks like it is possible, all our routes are handled by lazy loaded modules. This is our out-of-the-box route config:
const routes: Routes = [
{ path: '', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
];
While module lazy has this route config:
const routes: Routes = [
{ path: 'home', component: HomeComponent },
]
While HomeComponent is taken from the declarations of module lazy.
Then define another module, called for example lazy-two with the same route config, and its own HomeComponent.
Finally, you can switch between the modules by using this code:
lazyLoad() {
const routes: Routes = [
{
path: '',
loadChildren: () => import('./lazy-two/lazy-two.module')
.then(m => m.LazyTwoModule)
}
];
this.router.resetConfig(routes);
this.router.navigateByUrl('/home');
}
This will lazy load module lazy-two and refresh the route to /home - you will see the component of the new module displayed.
I couldn't create a stackblitz, some errors occurred probably because of lazy loading. So I ran it locally on my machine and pushed the code to GitHub
EDIT I managed to make a StackBlitz
I recommend used ComponentFactoryResolver to create the components that you need to render.
this.templates = [
{
id: "template-1",
component: Template1,
},
{
id: "template-2",
component: Template2,
},
];
ngOnInit() {
this.templates.forEach((element) => {
this.containerReference.createComponent(
this.factoryResolver.resolveComponentFactory(element.component)
);
});
}
in the .html you should have
<ng-container #containerReference><ng-container>
what about using the same component and styling it different when you select the template?
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
I have a feature module that I load in the AppModule, the AppRoutingModule looks like
const appRoutes: Routes = [
...
{
path: 'move-request/:id',
loadChildren: 'app/modules/move_requests/move_requests.module#MoveRequestModule'
},
...
];
And the configuration of routing for the feature module looks like
const moveRequestRoutes: Routes = [
{
path: '',
component: MoveRequestFormComponent,
data: {title: 'Move Request'}
},
{
path: 'move-request-success',
component: RequestSuccessComponent,
data: {title: 'Move request success'}
},
];
I would like to navigate to MoveRequestFormComponent as the default component when move-request/:id is routed to, this works fine, but when I call
this.router.navigate(['/move-request-success', {}]);
In MoveRequestFormComponent after some response from the server, I get
zone.js:665 Unhandled Promise rejection: Cannot match any routes. URL Segment: 'move-request-success' ; Zone: <root> ;
This configuration was working before I switched to Angular 6, Is it because of the change in the AppModule, where I have excluded this feature module as an import?
Any assistance on what I am missing would be much appreciated. As I have also tried with having a third component which will be the default component and uses the router-outlet to render the children and have a children property on this route to have as children
{
path: '',
component: MoveRequestFormComponent,
data: {title: 'Move Request'}
},
{
path: 'move-request-success',
component: RequestSuccessComponent,
data: {title: 'Move request success'}
},
But that also did not work, it stayed on the MoveRequestFormComponent, when 'move-request-success' was navigated to.Or maybe I should change the approach?
You don't have to import the feature module in AppModule as it is lazily-loaded. When you navigate to move-request/:id/move-request-success, the path matches the default route with path:'', and then it will look for and children of that route. You should add pathMatch:'full' to the first route, which is the default in this case. Since the mentioned route matches the first route and is unable to find and match any children, it is showing the error.
this.router.navigate(['/move-request-success', {}]);. If you add a / to a route this means you use absolute path from root. Have you tried without / ?
EDIT:
I think I see your problem. You navigate to a module with multiple components, which means after lazy loading the router configuration from the loaded module is used. This means
move-request/:id
Is the root of your module and every subroute needs to include the modules root in the url:
Your route should be move-request/:id/move-request-success
Urls in lazy loaded modules are:
module root (in your case move-request/:id) + configured route of the specific component (in your case move-request-success)
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>