I have set up my app so that I have a Recipe Book
which has a list of Recipies
which when I click on a Recipe it then shows the Recipe Details
in a nested route. This then also has a button that when clicked loads the ingredients in a nested route inside the Recipes Details
.
So far the routing seems to work, except when I try to navigate to another Recipe
. If the Ingredients
tray(route) is active then it will change Recipe and collapse the Ingredients
Route, If I then try and navigate (without opening the Ingredients) I get the following error:
Uncaught (in promise): Error: Outlet is not activated
Error: Outlet is not activated
It looks like I the router needs Ingredients
to be active or else it doesn't understand the nested route. Thats my take on it but not sure how to fix it or when I went wrong.
single-recipe-book-page.component.html
<app-tray class="recipe-list">
<app-recipe-list [recipe]="recipe"></app-recipe-list>
</app-tray>
<router-outlet></router-outlet>
recipe-detail.component.html
<app-tray class="recipe">
The routing has worked and loaded recipe.
</app-tray>
<router-outlet></router-outlet>
ingredients-list.component.html
<app-tray class="ingredients-list">
Recipe Ingredients have loaded.
</app-tray>
app.routes.ts (updated)
export const routerConfig : Route[] = [
{
path: 'recipe-books',
children: [
{
path: ':id', component: SingleRecipeBookPageComponent,
children: [
{
path: 'recipes',
children: [
{ path: ':id', component: RecipeDetailComponent,
children: [
{ path: '', component: IngredientsListComponent },
{ path: 'ingredients', component: IngredientsListComponent }
]
},
{ path: 'new', component: IngredientsListComponent },
{ path: '', component: RecipeDetailComponent }
]
},
{ path: '', redirectTo: 'recipes', pathMatch: 'full' }
]
},
{ path: '', component: RecipeBooksPageComponent }
]
},
{ path: 'ingredients', component: IngredientsComponent },
{ path: '', redirectTo: 'recipe-books', pathMatch: 'full' },
{ path: '**', redirectTo: 'recipe-books', pathMatch: 'full' }
];
This route is invalid and you should get an error for it.
{ path: '' },
A route either needs to have a component
, a redirectTo
, or children
.
If an empty path route has no children it also should have pathMatch: 'full'
.
I guess what you want is
{ path: '', component: DummyComponent, pathMatch: 'full' },
Where DummyComponent
is a component with an empty view.
You can reuse the same DummyComponent
for all these paths.
TLDR; answer :
{
path: ':question',
runGuardsAndResolvers: GUARDS_RESOLVERS_DISABLED // blocks component creation
}
Where GUARDS_RESOLVERS_DISABLED
is a global function (to avoid issues with AOT).
export function GUARDS_RESOLVERS_DISABLED() { return false; }
There's a new feature in Angular router that sounds related to this problem, but isn't - as far as I can tell - a direct solution for it. The new option is runGuardsAndResolvers = 'pathParamsChange'
and it affects when Angular checks guards and resolvers - and crucially whether it runs this outlet check.
So before I found the new option:
context.outlet.component
(where component
is a getter that throws).So to fix I'd just need to make shouldRun == false
somehow.
And shouldRun
is simply shouldRunGuardsAndResolvers(...)
so if that can be made to return false then it won't try to create a component in the 'wrong' place.
So the solution is quite simple:
{
path: 'contactus',
component: ContactUsComponent,
children: [
{
path: 'topics',
pathMatch: 'full'
},
{
path: 'faq',
component: FaqPanelComponent
},
{
path: 'test',
component: ContactusTopicListComponent
},
{
path: ':category',
children:
[
{
path: ':question',
runGuardsAndResolvers: () => false // blocks component creation
}
]
}
]
},
Currently runGuardsAndResolvers
has quite a few options, but the one I'm using just always returns false
which is equivalent to never
which really ought to be made into an option. But that's how I found out about the new router features :-)
Also if you have two levels you need to put this at both (or possibly just the highest) level:
{
path: ':category',
runGuardsAndResolvers: () => false,
children:
[
{
path: ':question',
runGuardsAndResolvers: () => false
}
]
}
Further reading on resolvers: https://blog.angularindepth.com/new-in-angular-v7-1-updates-to-the-router-fd67d526ad05
Edit: To make this work properly with AOT / Angular 9/10+ you can create a global function to avoid the issue mentioned by Sunil.
export function GUARDS_RESOLVERS_DISABLED() { return false; }
Then use this syntax
runGuardsAndResolvers: GUARDS_RESOLVERS_DISABLED
This might help someone else.
I was getting this error. I have checked all my defined routes
in my route file,
the path
and components
are defined correctly.
The reason of getting this error was that I forgot to add reference of my service
in app.module.ts
which was being used in one of my component to get data from RestApi
.
So, always add service reference in app.module.ts in providers
section, immediately after creating service.
imports: [
BrowserModule,
HttpModule,
......
],
providers: [
AuthService,
........ // Here, service reference
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With