Reputation: 16567
I'm working on an Angular 2 app using @angular in ASP.NET Core. I have a landing page located at the base url with its own Layout file, Index page, and controller.
What I want to add is an entire section of my website at /toolkit. To start it off, I made a MyProfileComponent
to rest at /toolkit using my internal Layout, Index, and Controller. I have also created a ProfileComponent to reside at /toolkit/profile/:uniquename
The problem is that when I run the app since adding my internal routes, I get an error.
/toolkit throws this error
Exception: Call to Node module failed with error: Error: Uncaught (in promise): Error: Cannot find primary outlet to load 'ProfileComponent'
Error: Cannot find primary outlet to load 'ProfileComponent'
at getOutlet (D:\Projects..\node_modules\@angular\router\bundles\router.umd.js:3018:23)
and /toolkit/profile/sdfsad throws this error
Exception: Call to Node module failed with error: Error: Uncaught (in promise): [object Object]
I'm new to angular 2 and everything I've seen wants you to use the now obsolute Directives property on components, but that has gone away in this version of angular 2 (@angular is version 2.0.0). I'm probably doing something wrong, but here are the pieces:
_InternalLayout (extra stuff stripped out)
<head>
<base href="/toolkit" />
</head>
<body class="menubar-top menubar-dark theme-primary">
@RenderBody()
@RenderSection("scripts", required: false)
</body>
/Toolkit/Index.cshtml
@{
Layout = "~/Views/Shared/_InternalLayout.cshtml";
}
<app asp-prerender-module="@Url.Content("ClientApp/dist/main-server")">Loading...</app>
<script src="@Url.Content("~/dist/vendor.js")" asp-append-version="true"></script>
@section scripts {
<script src="@Url.Content("~/dist/main-client.js")" asp-append-version="true"></script>
}
app.component.html
<router-outlet></router-outlet>
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app',
template: require('./app.component.html'),
})
export class AppComponent {
}
app.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { UniversalModule } from 'angular2-universal';
import { AppComponent } from './components/app/app.component'
import { LandingPageLayoutComponent } from './components/landing/landing-page-layout.component';
import { SignInComponent } from './components/account/sign-in.component';
import { RegisterComponent } from './components/account/register.component';
import { ProfileComponent } from './components/profile/profile.component';
import { MyProfileComponent } from './components/profile/my-profile.component';
@NgModule({
bootstrap: [ AppComponent ],
declarations: [
AppComponent,
LandingPageLayoutComponent,
SignInComponent,
RegisterComponent,
ProfileComponent,
MyProfileComponent
],
imports: [
UniversalModule, // Must be first import. This automatically imports BrowserModule, HttpModule, and JsonpModule too.
RouterModule.forRoot([
{ path: 'signin', component: SignInComponent },
{ path: 'register', component: RegisterComponent },
{
path: 'toolkit',
component: MyProfileComponent,
children: [
{ path: '' },
{ path: 'profile/:uniquename', component: ProfileComponent },
]
},
{ path: '', component: LandingPageLayoutComponent },
{ path: '**', redirectTo: 'error' }
])
]
})
export class AppModule {
}
The root page, sign in, and register all work, although I had the same issue when I tried making sign in and register children under /account. I'm sure I am doing something silly, and once we figure it out I will try some other nesting with those pages.
EDIT
I am using this Visual Studio 2015 template if it matters. It was working fine until I started trying to add nested routes.
Upvotes: 0
Views: 687
Reputation: 96
Based on your error and what I see in your RouterModule code in in app.module.ts
, there are two possible resolutions depending on what your goal is.
1) If at the route '/toolkit', you want to see MyProfileComponent and at the route '/toolkit/profile/:uniquename' (showing full paths here) you want to see ProfileComponent instead of MyProfileComponent then the code for your router needs to look like:
RouterModule.forRoot([
{ path: 'signin', component: SignInComponent },
{ path: 'register', component: RegisterComponent },
{
path: 'toolkit',
children: [ // change here
{ path: '', component: MyProfileComponent }, // both components are siblings within 'toolkit' path
{ path: 'profile/:uniquename', component: ProfileComponent }
]
},
{ path: '', component: LandingPageLayoutComponent },
{ path: '**', component: ErrorComponent } // this also needs to be changed to match a component
])
2) If at the route 'toolkit/profile/:uniquename' you want to see MyProfileComponent and ProfileComponent nested inside it then your router code should look like
RouterModule.forRoot([
{ path: 'signin', component: SignInComponent },
{ path: 'register', component: RegisterComponent },
{
path: 'toolkit',
component: MyProfileComponent,
children: [
// this line needs to be removed { path: '' },
{ path: 'profile/:uniquename', component: ProfileComponent }
]
},
{ path: '', component: LandingPageLayoutComponent },
{ path: '**', component: ErrorComponent } // this also needs to be changed to match a component
])
(2) cont'd- Then inside my-profile.component.ts
your template
must have a <router-outlet></router-outlet>
to handle the nested child routes
In both cases your path: **'
needs to have a component associated with it. When doing redirects, you must include the pathMatch property e.g. pathMatch: 'full'
Upvotes: 1