Angular feature routing module - Child component not loaded - javascript

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)

Related

In Angular, how can one component to have multiple HTML templates?

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?

Lazy loading angular modules but not using the route prefix

I have an app where I'm lazy loading a module called lazy. That module is lazy loaded via this:
{
path:'lazy',
loadChildren:
'./lazy/lazy.module#LazyModule'
}
The lazy module has the following routes in it:
const routes = [
{
path: '',
component: LazyComponent
},
{
path: 'faq',
component: FaqComponent
},
{
path: 'details',
component: DetailsComponent
},
]
The above works fine but I can only access the routes of my lazy loaded module via /lazy/faq or /lazy/details. But what I really want is to not use the route prefix lazy and access the routes of my lazy loaded module directly via /faq and /details.
Is this possible to do? I have not been able find a solution for this.
The url of components within lazy loaded modules is a combination of the url to the module e.b 'lazy'-> LazyLoadedModule plus the relative path within that module e.g 'faq->FaqComponent.
So the url is path/to/lazy-module + 'relative/path'. In your case lazy/faq. You cannot omit the prefix.
What you can do is to add a redirect in your routing config:
path: 'faq',
pathMatch: 'full,
redirectTo: 'lazy/faq'
When you use routing within your lazy module you can use relative routes: this.router.navigate(['faq']) but the url in the browser would be lazy/faq though.
Another option would be to use empty route for loading your module:
path:'',
loadChildren: ...
But that would load your module immediately when your application starts.

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>

How can Vue router get current route path of lazy-loaded modules on page load?

I have a vue app with router set up like:
import index from './components/index.vue';
import http404 from './components/http404.vue';
// module lazy-loading
const panda= () => import(/* webpackChunkName: "group-panda" */ "./components/panda/panda.vue");
// ...
export const appRoute = [
{
path: "",
name: "root",
redirect: '/index'
},
{
path: "/index",
name: "index",
component: index
},
{
path: "/panda",
name: "panda",
component: panda
},
//...
{
path: "**",
name: "http404",
component: http404
}
];
So the panda module is lazy-loaded. However, when I navigate to panda page, a console.log() of this.$route.path in App.vue's mounted() lifecycle only outputs
"/"
instead of
"/panda"
But index page works well, it shows exactly
"/index"
as expected.
So how can Vue router get current path correctly of a lazy-loaded page, when page is initially loaded? Did I miss something?
Edit:
It can, however, catch the correct path after Webpack hot-reloads. It catches "/" on first visit of panda, but after I change something in source code, webpack-dev-server hot-reloads, then it gets "/panda".
So I guess it has something to do with Vue life-cycle.
There is a currentRoute property that worked for me:
this.$router.currentRoute
May be you need to use $route not $router
check here : https://jsfiddle.net/nikleshraut/chyLjpv0/19/
You can also do it by $router this way
https://jsfiddle.net/nikleshraut/chyLjpv0/20/
Use this.$route.path.
Simple and effective.
Hide Header in some components using the current route path.
get current route path using this.$route.path
<navigation v-if="showNavigation"></navigation>
data() {
this.$route.path === '/' ? this.showNavigation = false : this.showNavigation = true
}
If You have similar problem the correct answer is to use router.onReady and then calling your logic concerning path. Below the official Vue router docs:
router.onReady
Signature:
router.onReady(callback, [errorCallback])
This method queues a callback to be called when the router has completed the initial navigation, which means it has resolved all async enter hooks and async components that are associated with the initial route.
This is useful in server-side rendering to ensure consistent output on both the server and the client.
The second argument errorCallback is only supported in 2.4+. It will be called when the initial route resolution runs into an error (e.g. failed to resolve an async component).
Source: https://v3.router.vuejs.org/api/#router-onready
For vue 3 (Composition API)
It can be as simple as route.path if you define the variable route as: const route = useRoute()
Usage example
If you try the following, each time your route path changes it will console log the current path:
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute()
watchEffect(() => console.log(route.path))
</script>

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