Angular 2 Warning: Router-Outlet in Templates

Mike BerrymanA quick warning to those using the tag in their Angular 2 app: Don’t do it inside of a template (including conditional blocks, such as an *ngIf).

I was working on an Angular 2 application that allowed the user to select an item to view details for.  At the top of the details page I wanted to show some general details about the selected item, and the main body of the page would basically be a set of tabs to show different information based on the selected tab.  For example, when viewing information about a user I wanted to always show general information about the user at the top of the page (stuff like first and last name, username, user id, etc.) and then the body of the page would display different information depending on the selected tab (contact info, social media info, that kind of stuff).  To ease the data load overhead I separated each tab into its own route in the app.  This way each tab was actually a different route that would load its own data and since each tab had its own unique route, we could deep-link to the proper tab from anywhere in the link.

To accomplish this I set up what I call a “sub-route” for the details page.  The main details page consisted of the top section of the page (where the general details are) then a <router-outlet> tag in the body, where the selected tab’s content will load. The route to one of the “tabs” would look something like this: /user/{id}/contact.  Since theoretically the user could put an invalid {id} in the route, I wanted to make sure the id returned valid data before displaying anything in the page.  So I wrapped the majority of the page in an *ngIf conditional, and then started getting this error message:

Error: Uncaught (in promise): Error: Cannot find primary outlet to load ‘SomeComponent’

Basically when the page loads it notices that there’s a child route that needs to be loaded as well.  It looks for the <router-outlet> tag to insert the child route into but since the chunk of the HTML that contains that tag hasn’t been loaded yet (because it’s inside an *ngIf), it cannot find a place to put the child route and crashes.

I put together a quick Plunkr to demo this issue.  Remove *ngIf=”itemLoaded” from the div in the Master component’s template to fix the error.

The takeaway for this is that any child routes must always have a <router-outlet> available when the parent route loads.  For my situation, instead of putting my <router-outlet> inside of an *ngIf block I just hid that chunk of the page until the data has been verified.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s