Angular2 - No provider for LoggedInGuard - javascript

I'm making a Anuglar2 rc-4 web application. I'm trying to restrict routes but when i add my login guard, it tells me there is no provider. My normal login service code works fine, its just when i try to add the login guard and canActive routes. Any ideas on how to fix this error?
routes.ts
import { RouterConfig } from '#angular/router';
import { Home } from './components/home/home';
import { Login } from './components/login/login';
import { DashBoard } from './components/dashboard/dashboard';
import { User } from './components/user/user';
import { Store } from './components/store/store';
import { LoggedInGuard } from './models/logged-in.guard.ts';
export const routes: RouterConfig = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home, canActivate: [LoggedInGuard] },
{ path: 'login', component: Login },
{ path: 'dashboard', component: DashBoard },
{ path: 'user', component: User },
{ path: 'store', component: Store },
{ path: '**', redirectTo: 'home' }
];
boot.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
import { FormBuilder } from '#angular/common';
import { provideRouter } from '#angular/router';
import { HTTP_PROVIDERS, JSONP_PROVIDERS } from '#angular/http';
import { App } from './components/app/app';
import { routes } from './routes';
bootstrap(App, [
HTTP_PROVIDERS,
FormBuilder,
provideRouter(routes)
]);
logged-in.guard.ts
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router';
import { LoginService } from '../services/login.service';
#Injectable()
export class LoggedInGuard implements CanActivate {
constructor(private ls: LoginService) {}
canActivate() {
return this.ls.isLoggedIn();
}
}

You have to inject your LoggedInGuard service inside your application bootstrap function
bootstrap(App, [
HTTP_PROVIDERS,
FormBuilder,
provideRouter(routes),
LoggedInGuard // injected LoggedInGuard service provider here
]);
Note: This answer would not be the same for the current angular 2 updated version(rc.6), When you upgrade you need to create a
NgModule where you are going to wrap up all the dependencies in
single place, that time LoggedInGuard will go inside providers option
of `NgModule
`

Related

Using Angular's ```location.back()``` redirecting me out of my angular application

My angular application opens at http://localhost:4200/scheduler. I have provided a button on homepage which on getting clicked redirect user to http://localhost:4200/cr?crId={{MONGODB_ID}}. The opened page has a Back button on it, on clicking on it I am calling this method.
backClicked() {
this._location.back();
}
this method is redirecting me out of my angular application. I am not able to understand what I am doing wrong.
The routing done in app-routing.module.ts is given below as
import { NgModule } from '#angular/core';
import { PreloadAllModules, RouterModule, Routes } from '#angular/router';
import { environment } from 'src/environments/environment';
import { AuthGuard, LoginGuard } from './guard/';
import { AccessRightsGuard } from './guard/access-rights.guard';
import { UnauthorizedComponent } from './unauthorized/unauthorized.component';
export const APP_ROUTES: Routes = [
{ path: '', redirectTo: 'scheduler', pathMatch: 'full' },
{
path: 'scheduler',
canActivate: [AuthGuard, AccessRightsGuard],
loadChildren: () => import('src/app/scheduler/scheduler.module').then(m => m.SchedulerModule),
data: { rightsId: environment.accessRights['Home Page'] }
},
{
path: 'cr',
canActivate: [AuthGuard, AccessRightsGuard],
loadChildren:() => import('src/app/cr/cr.module').then(m => m.CrModule),
data: { rightsId: environment.accessRights['CrewRequiremensComponent'] }
},
{
path: '401',
component: UnauthorizedComponent,
},
{ path: '**', redirectTo: 'scheduler', pathMatch: 'full' },
The code in the routing module of scheduler module is
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { SchedulerHomeComponent } from './scheduler.component';
const SCHEDULER_ROUTES: Routes = [
{
path: '',
component: SchedulerComponent
}
];
#NgModule({
imports: [RouterModule.forChild(SCHEDULER_ROUTES)],
exports: [RouterModule]
})
export class SchedulerRoutingModule {}
The code in the routing module of cr module is
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { CrComponent } from './cr.component';
const CR: Routes = [
{
path: '',
component: CrComponent
}
];
#NgModule({
imports: [RouterModule.forChild(CR)],
exports: [RouterModule]
})
export class CrModule { }

Infinite console.logging using Ionic 4 Angular Fire Auth guard

I followed the direction in this tutorial to implement a simple auth guard in my Ionic app. It should redirect someone to the 'login' page if they are not logged in.
The problem arises when I go into my 'settings' page and try to log out a current user.
As you can see, there is a 'throttling history state changes to prevent the browser from hanging' that goes on infinitely. In fact, I had to shut down my laptop because the tab wouldn't close. Luckily, I grabbed a troubleshoot screenshot right before I shut it off.
My auth guard code, under app/services/user:
import { Injectable } from '#angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router,
} from '#angular/router';
import { Observable } from 'rxjs';
import * as firebase from 'firebase/app';
import 'firebase/auth';
import { AngularFireModule } from '#angular/fire';
import { environment } from '../../../environments/environment';
firebase.initializeApp(environment.firebase);
#Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> | Promise<boolean> {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged((user: firebase.User) => {
if (user) {
resolve(true);
} else {
this.router.navigateByUrl('/login');
resolve(false);
}
});
});
}
}
The settings.page code, under app/settings:
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { AlertController } from '#ionic/angular';
// Firebase imports
import * as firebase from 'firebase';
import { AngularFireAuth } from '#angular/fire/auth';
import { auth } from 'firebase/app';
#Component({
selector: 'app-settings',
templateUrl: './settings.page.html',
styleUrls: ['./settings.page.scss'],
})
export class SettingsPage implements OnInit {
constructor(
public alertCtrl: AlertController,
private afAuth: AngularFireAuth,
private router: Router
) { }
ngOnInit() {
}
async logOut() {
const confirm = await this.alertCtrl.create({
header: 'Logging out?',
buttons: [
{
text: 'Yes',
handler: () => {
this.afAuth.auth.signOut();
console.log('Signed out');
}
},
{
text: 'Wait, no',
handler: () => {
console.log('Not clicked');
}
}
]
});
return await confirm.present();
}
}
And, finally, my app-routing.module.ts, under app:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AuthGuard } from './services/user/auth.guard';
const routes: Routes = [
{ path: '', redirectTo: 'landing', pathMatch: 'full' },
{ path: 'home/:id', loadChildren: './home/home.module#HomePageModule', canActivate: [AuthGuard] },
{ path: 'landing', loadChildren: './landing/landing.module#LandingPageModule', canActivate: [AuthGuard] },
{ path: 'login', loadChildren: './login/login.module#LoginPageModule', canActivate: [AuthGuard] },
{ path: 'signup', loadChildren: './signup/signup.module#SignupPageModule', canActivate: [AuthGuard] },
{ path: 'settings', loadChildren: './settings/settings.module#SettingsPageModule', canActivate: [AuthGuard] },
{ path: 'add-list', loadChildren: './add-list/add-list.module#AddListPageModule', canActivate: [AuthGuard] },
{ path: 'clicked-list', loadChildren: './clicked-list/clicked-list.module#ClickedListPageModule', canActivate: [AuthGuard] },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
I really can't make sense of it at all. Any help would be much appreciated.
The problem is your AuthGuard is redirecting the route to /login, and on your /login route you have AuthGuard again, this causes an infinite redirection from /login to /login and so on. Remove AuthGuard from /login route it will be fine.

Getting the current URL gives the static injector error for Router

I am building an Angular and Ionic application where I need the URL of my current page, the url that is showing in the address bar of the browser. To do so, I am using router.url, But I am getting an error:
Error: Uncaught (in promise): Error: StaticInjectorError[Router]:
StaticInjectorError[Router]:
NullInjectorError: No provider for Router! Error: StaticInjectorError[Router]: StaticInjectorError[Router]:
NullInjectorError: No provider for Router!
at NullInjector.get (http://localhost:8100/build/vendor.js:1277:19)
at resolveToken (http://localhost:8100/build/vendor.js:1565:24)
at tryResolveToken (http://localhost:8100/build/vendor.js:1507:16)
at StaticInjector.get (http://localhost:8100/build/vendor.js:1378:20)
at resolveToken (http://localhost:8100/build/vendor.js:1565:24)
at tryResolveToken (http://localhost:8100/build/vendor.js:1507:16)
at StaticInjector.get (http://localhost:8100/build/vendor.js:1378:20)
at resolveNgModuleDep (http://localhost:8100/build/vendor.js:10939:25)
at NgModuleRef.get (http://localhost:8100/build/vendor.js:12160:16)
at resolveDep (http://localhost:8100/build/vendor.js:12656:45)
at c (http://localhost:8100/build/polyfills.js:3:19752)
at Object.reject (http://localhost:8100/build/polyfills.js:3:19174)
at NavControllerBase._fireError (http://localhost:8100/build/vendor.js:50002:16)
at NavControllerBase._failed (http://localhost:8100/build/vendor.js:49995:14)
at http://localhost:8100/build/vendor.js:50042:59
at t.invoke (http://localhost:8100/build/polyfills.js:3:14976)
at Object.onInvoke (http://localhost:8100/build/vendor.js:4983:33)
at t.invoke (http://localhost:8100/build/polyfills.js:3:14916)
at r.run (http://localhost:8100/build/polyfills.js:3:10143)
at http://localhost:8100/build/polyfills.js:3:20242
Component code is:
import {Component, Pipe, PipeTransform} from '#angular/core';
import {IonicPage, NavController, NavParams, Platform, ViewController, ToastController} from 'ionic-angular';
import {ScreenOrientation} from '#ionic-native/screen-orientation';
import {DomSanitizer, SafeUrl, SafeResourceUrl} from "#angular/platform-browser";
import { ApiProvider } from './../../providers/api/api';
import { Router } from '#angular/router';
#IonicPage()
#Component({
selector: 'page-play',
templateUrl: 'play.html',
providers: [ScreenOrientation]
})
export class PlayPage {
constructor(platform: Platform,private router: Router, public navCtrl: NavController, public navParams: NavParams, public viewCtrl: ViewController, private screenOrientation: ScreenOrientation, public toastCtrl: ToastController, private sanitizer: DomSanitizer, public apiProvider: ApiProvider) {
this.location=this.router.url;
console.log("LOCATION"+this.location);
}
}
My module.ts is:
import { BrowserModule } from '#angular/platform-browser';
import { ErrorHandler, NgModule, Pipe } from '#angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '#ionic-native/splash-screen';
import { StatusBar } from '#ionic-native/status-bar';
import { SuperTabsModule } from 'ionic2-super-tabs';
import { MyApp } from './app.component';
import { TabPage } from '../pages/tab/tab';
import {VgCoreModule} from 'videogular2/core';
import {VgControlsModule} from 'videogular2/controls';
import {VgOverlayPlayModule} from 'videogular2/overlay-play';
import {VgBufferingModule} from 'videogular2/buffering';
import { ApiProvider } from '../providers/api/api';
//import { Databaseservice } from '../providers/api/Databaseservice';
import {GetstartedPage} from '../pages/getstarted/getstarted'
import { HttpClientModule } from '#angular/common/http';
import {LoginPage} from '../pages/login/login';
import {LoginPageModule} from '../pages/login/login.module'
import {SongsPage} from '../pages/songs/songs'
import {SongsPageModule} from '../pages/songs/songs.module'
import {VideosPage} from '../pages/videos/videos'
import {VideosPageModule} from '../pages/videos/videos.module'
import {EmbedvideoPage} from '../pages/embedvideo/embedvideo'
import {EmbedvideoPageModule} from '../pages/embedvideo/embedvideo.module'
import {PlayPage} from '../pages/play/play'
import {PlayPageModule} from '../pages/play/play.module'
import {EventsPage} from '../pages/events/events'
import {EventsPageModule} from '../pages/events/events.module'
import {ProfilePage} from '../pages/profile/profile'
import {ProfilePageModule} from '../pages/profile/profile.module'
import {SettingsPage} from '../pages/settings/settings'
import {SettingsPageModule} from '../pages/settings/settings.module'
import {AudioplayertwoPage} from '../pages/audioplayertwo/audioplayertwo'
import {AudioplayertwoPageModule} from '../pages/audioplayertwo/audioplayertwo.module'
import {ViewAllPage} from '../pages/view-all/view-all'
import {ViewAllPageModule} from '../pages/view-all/view-all.module'
import {PricePage} from '../pages/price/price'
import {PricePageModule} from '../pages/price/price.module'
import { GetstartedPageModule } from '../pages/getstarted/getstarted.module';
import { IonicStorageModule } from '#ionic/storage';
import { AngularFireModule } from 'angularfire2';
import * as firebase from 'firebase';
import 'firebase/messaging'; // only import firebase messaging or as needed;
import { firebaseConfig } from '../environment';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { LocationStrategy, PathLocationStrategy } from '#angular/common';
import { RouterModule,Router } from '#angular/router';
firebase.initializeApp(firebaseConfig);
var database = firebase.database();
//.............
#NgModule({
declarations: [
MyApp,
TabPage,
// SingleMediaPlayer
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp, {}, {
links: [
{ component: LoginPage, name: 'LoginPage', segment: 'login' },
{ component: SongsPage, name: 'SongsPage', segment: 'songs' },
{ component: VideosPage, name: 'VideosPage', segment: 'm/videos' },
{ component: EventsPage, name: 'EventsPage', segment: 'm/events' },
{ component: PlayPage, name: 'PlayPage', segment: 'm/watch/:name' },
{ component: EmbedvideoPage, name: 'EmbedvideoPage', segment: 'embed' },
{ component: ProfilePage, name: 'ProfilePage', segment: 'profile' },
{ component: SettingsPage, name: 'SettingsPage', segment: 'settings' },
{ component: PricePage, name: 'PricePage', segment: 'price' },
{ component: AudioplayertwoPage, name: 'AudioplayertwoPage', segment: 'Audioplayer' },
{ component: TabPage, name: 'TabPage', segment: 'tab' } ,
{ component: ViewAllPage, name:'ViewAllPage',segment:'m/viewAll/:name'}
]
}),
SuperTabsModule.forRoot(),
VgCoreModule,
VgControlsModule, PlayPageModule, ProfilePageModule, SettingsPageModule, PricePageModule, AudioplayertwoPageModule,
VgOverlayPlayModule, GetstartedPageModule, LoginPageModule, SongsPageModule, VideosPageModule, EventsPageModule, EmbedvideoPageModule,
VgBufferingModule, VideosPageModule, HttpClientModule, ViewAllPageModule, AngularFireModule.initializeApp(firebaseConfig), IonicStorageModule.forRoot(), AngularFireDatabaseModule
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
VideosPage, GetstartedPage
],
providers: [
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler }, { provide: LocationStrategy, useClass: PathLocationStrategy }, ApiProvider
]
})
export class AppModule { }
I know something I have to add in my module.ts. But I am not figuring out it.
You have to import RouterModule into your own module.
EDIT also put an access modifier in your first constructor parameter :
constructor(public platform: Platform, ...)
Or put it last in your parameters.
You have to do this in your module imports?
RouterModule.forRoot(
[
{ path: "", component: PlayPage}
]
)
https://angular.io/guide/router says:
A routed Angular application has one singleton instance of the Router service.
...
A router has no routes until you configure it. The following example creates four route definitions, configures the router via the RouterModule.forRoot method, and adds the result to the AppModule's imports array.
const appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },
{ path: 'hero/:id', component: HeroDetailComponent },
{
path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
{ path: '',
redirectTo: '/heroes',
pathMatch: 'full'
},
{ path: '**', component: PageNotFoundComponent }
];
#NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } // <-- debugging purposes only
)
// other imports here
],
...
})
export class AppModule { }
So in order to use Router instance, you need to create it first in your root module using RouterModule.forRoot method. You can follow the official guide - it's quite simple.
Add import { HttpModule } from '#angular/http'; in app.module.ts for Http
Or
Add import {HttpClientModule} from '#angular/common/http'; in app.module.ts for httpclient

Cannot read property 'path' of undefined in Angular 2

I'm getting error:
Cannot read property 'path' of undefined
when I go to login page.Login page is separate template from home layout.then I created login.component.ts as <router-outlet> and auth.component.ts for my login page.
But home page working fine. error occur only load separate login page:
This is my folder structure:
login.component.ts:
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
login.route.ts:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule, Routes } from '#angular/router';
import { NoAuthGuard } from '../no-auth-guard.service';
import { AuthComponent } from '../login/auth.component';
export const AUTH_ROUTES: Routes = [
{
path: '', component: AuthComponent,// canActivate: [NoAuthGuard]
},
{
path: 'login', component: AuthComponent,// canActivate: [NoAuthGuard]
},
{
path: 'register', component: AuthComponent,// canActivate: [NoAuthGuard]
}
]
login.route.html:
<router-outlet></router-outlet>
auth.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { Errors, UserService } from '../../shared';
import { UserLogin } from '../../shared/models';
#Component({
selector: 'auth-page',
styleUrls: ['./auth.component.css'],
templateUrl: './auth.component.html'
})
export class AuthComponent implements OnInit {
authLoginForm: FormGroup;
authRegisterForm: FormGroup;
constructor(private route: ActivatedRoute, private router: Router, private userService: UserService, private fb: FormBuilder) {
// use FormBuilder to create a form group
-- some code here
// end use FormBuilder to create a form group
}
ngOnInit() {}
userLogin() { }
userRegister() {}
}
app-routing.module.ts:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule, Routes } from '#angular/router';
import { NoAuthGuard } from './auth/no-auth-guard.service';
import { HomeAuthResolver } from './layout/home-auth-resolver.service';
import { LoginComponent, AUTH_ROUTES } from './auth/index';
import {LayoutComponent, PUBLIC_ROUTES } from './layout/index';
const routes: Routes = [
{ path: 'login', component: LoginComponent,data: { title: 'Public Views' }, children: AUTH_ROUTES },
{ path: 'register', component: LoginComponent,data: { title: 'Public Views' }, children: AUTH_ROUTES },
{ path: '', component: LayoutComponent, data: { title: 'Secure Views' }, children: PUBLIC_ROUTES },
{ path: '**', redirectTo: 'home' }
];
#NgModule({
imports: [
CommonModule,
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }
This problem lies in the ambiguity of your routing scheme. It's also worth noting the Routes is an array and thus ordered. Routes are evaluated in order they are defined in that array.
So move your empty route (path: '') in login.route.ts to the last position in the AUTH_ROUTES array.

Angular 2 sub apps, parent/child, nested components, nested router-outlet, design/coding

I have an Angular 2 app. The main screen (app?) looks like this...
When you click items in the top menu routerLinks, new Components load into the main view router outlet. One of those links loads up an new "Admin" Module/Component with it's own routes and new router outlet...
Then when you click the routerLinks in the left nav, new admin Components will load in the new router outlet.
But...
Angular 2 does not allow more than 1 router outlet. So clicking on any routerLink in left nav simply replaces the entire inital router outlet view.
I've seen some SO posts (older, maybe deprecated) on using "bootstrap" to load subsequent Components, but I can't get that to work. I can't even import { bootstrap } from 'anywhere at all, nothing works'. So maybe that's not the way to do this.
How can I get the Admin sub app part to work?
Thank you very, very much for sharing your Angular 2 expertise :-)
EDIT: Trying suggested solutions below. No matter where I put the routes, in the base app.routes.ts or in the sub-app admin.routes.ts, no matter how I format the routerLinks, I keep getting this error...
EDIT AGAIN: Here is the code in the routers and the template...
<!--
============================================================================
/src/app/component/admin/admin.component.html
-->
<!-- Row for entire page columnar dispaly -->
<div class="row">
<!-- Column 1: Left navigation, links to all admin components -->
<div class="col col-md-4">
<app-admin-nav></app-admin-nav>
</div>
<!-- Column 2: Rows of records, click to edit -->
<div class="col col-md-8">
<router-outlet name="admin-app"></router-outlet>
</div>
</div>
// ============================================================================
// /src/app/app.routes.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';
// import { AdminWorldComponent } from './component/admin/world/admin-world.component';
// import { AdminModuleComponent } from './component/admin/module/admin-module.component';
// import { AdminRegionComponent } from './component/admin/region/admin-region.component';
export const router: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' }
, { path: 'home', component: HomeComponent }
, { path: 'game', component: GameComponent, canActivate: [AuthGuard] }
, { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
// , {
// path: 'admin', component: AdminComponent, canActivate: [AuthGuard],
// children: [
// { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' },
// { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' },
// { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
// ]
// },
, { path: 'login', component: LoginComponent }
, { path: 'signup', component: SignupComponent }
, { path: 'login-email', component: EmailComponent }
, { path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];
export const routes: ModuleWithProviders = RouterModule.forRoot(router);
// ============================================================================
// /src/app/component/admin/admin.routes.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';
export const router: Routes = [
{
path: 'admin', component: AdminComponent,
children: [
{ path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
, { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
, { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
]
}
];
export const routes: ModuleWithProviders = RouterModule.forRoot(router);
EDIT 3: Tried changing RouterModule.forRoot to RouterModule.forChild, sadly, same error :-/
EDIT 4: Converted routing to use 2 routing modules. Was hoping maybe that would make a difference, but same error.
New routers...
// ============================================================================
// /src/app/app-routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';
export const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' }
, { path: 'home', component: HomeComponent }
, { path: 'game', component: GameComponent, canActivate: [AuthGuard] }
, { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
// , {
// path: 'admin', component: AdminComponent, canActivate: [AuthGuard],
// children: [
// { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' },
// { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' },
// { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
// ]
// },
, { path: 'login', component: LoginComponent }
, { path: 'signup', component: SignupComponent }
, { path: 'login-email', component: EmailComponent }
, { path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
// ============================================================================
// /src/app/admin/admin-routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';
export const adminRoutes: Routes = [
{
path: 'admin', component: AdminComponent,
children: [
{ path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
, { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
, { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
]
}
];
#NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [
RouterModule
]
})
export class AdminRoutingModule { }
EDIT 5: IT'S WORKING!
Removed the routing modules, returned to exporting routes config per Tyler's suggestion. He is right, the routing modules do not work. Tyler worked with me a lot so I'm accepting his answer. Thank you Tyler for your help!
Here is how you can setup a parent app with it's own router-outlet, then on the parent click a link to load up a child app with it's own new router-outlet. The child app loads/replaces the parent app router-outlet.
There is really nothing special in the parent app module or routes. They're just how I had them before this post.
The important points to note, at least in my case today, do not use a name="" attrib in the child router-outlet. This will cause "Error: Cannot match any routes...". Do not use routing modules like I tried above, this also causes "Error: Cannot match any routes...". Do not use outlet: 'blah' in the routes, this also causes "Error: Cannot match any routes...". Make sure you set up the child route config children: [] exactly as you see below in admin.routes.ts. Also, note the RouterModule.forChild(router) in the child routes. These things fixed the issue for me today.
PARENT APP
// ============================================================================
// src/app/app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { AngularFireModule } from 'angularfire2';
import { firebaseConfig } from '../environments/firebase.config';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
// import { AppRoutingModule } from './app-routing.module';
import { routes } from './app.routes';
// Components
import { AppComponent } from './app.component';
import { HomeComponent } from './component/home/home.component';
import { GameComponent } from './component/game/game.component';
import { PlayerComponent } from './component/player/player.component';
import { LoginComponent } from './component/login/login.component';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
// Admin Module
import { AdminModule } from './component/admin/admin.module';
// Services
import { AuthGuard } from './service/auth/auth.service';
import { AuthPlayerService } from './service/auth/auth-player.service';
import { MdbService } from './service/mongo/mdb.service';
import { PlayerMdbService } from './service/mongo/player-mdb.service';
#NgModule({
declarations: [
AppComponent
, HomeComponent
, GameComponent
, PlayerComponent
, LoginComponent
, SignupComponent
, EmailComponent
],
imports: [
BrowserModule
, FormsModule
, HttpModule
, AdminModule
, AngularFireModule.initializeApp(firebaseConfig)
, NgbModule.forRoot()
// , AppRoutingModule
, routes
],
providers: [
AuthGuard
, AuthPlayerService
, MdbService
, PlayerMdbService
],
bootstrap: [AppComponent]
})
export class AppModule { }
// ============================================================================
// /src/app/app.routes.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';
export const router: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'game', component: GameComponent, canActivate: [AuthGuard] },
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent },
{ path: 'login-email', component: EmailComponent },
{ path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];
export const routes: ModuleWithProviders = RouterModule.forRoot(router);
CHILD APP
// ============================================================================
// /src/app/admin/admin.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { CommonModule } from '#angular/common';
import { routes } from './admin.routes';
// import { AdminRoutingModule } from './admin-routing.module';
import { AdminComponent } from './admin.component';
import { AdminRecsComponent } from './admin-recs.component';
import { AdminFormComponent } from './admin-form.component';
import { AdminNavComponent } from './admin-nav.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';
#NgModule({
imports: [
CommonModule
, FormsModule
// , AdminRoutingModule
, routes
]
, declarations: [
AdminComponent
, AdminNavComponent
, AdminRecsComponent
, AdminFormComponent
, AdminWorldComponent
, AdminModuleComponent
, AdminRegionComponent
]
, schemas: [CUSTOM_ELEMENTS_SCHEMA]
, exports: [
AdminRecsComponent
, AdminFormComponent
, AdminNavComponent
// , AdminWorldComponent
// , AdminModuleComponent
// , AdminRegionComponent
]
// , bootstrap: [AdminComponent]
})
export class AdminModule { }
// ============================================================================
// /scr/app/admin/admin.routes.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';
export const router: Routes = [
{
path: 'admin', component: AdminComponent,
children: [
{ path: 'world', component: AdminWorldComponent },
{ path: 'module', component: AdminModuleComponent },
{ path: 'region', component: AdminRegionComponent },
]
}
];
export const routes: ModuleWithProviders = RouterModule.forChild(router);
Not sure where you heard that Angular2 does not allow more than 1 router-outlet. I am using several in a large application.
Your main app.component will have a router-outlet to handle the root routes. If one of your routes lazy-loads the Admin Module, that admin module will have it's root component that contains the side menu bar and a router-outlet for all the children routes.
Example:
//app.routes
export const ROUTES: Routes = [
// Main redirect
{ path: '', component: MainViewComponent },
{
path: 'admin',
loadChildren: './admin/admin.module#AdminModule'
}
]
Your MainViewComponent can contain the top navbar and a router-outlet.
Then the Admin router config may look like this:
export const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{ path: '', component: Component1},
{ path: 'component2', component: Component2}
]
}
];
Your root component in the Admin module may contain the side bar menu and a router-outlet to show the children components.
You can also do named router-outlets. An example of this is having two router-outlets side-by-side:
<router-outlet></router-outlet>
<router-outlet name="popup"></router-outlet>
Your router config would look like this:
{
path: 'compose',
component: ComposeMessageComponent,
outlet: 'popup'
},
And you would use it like this:
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
Or clear the content with this:
this.router.navigate([{ outlets: { popup: null }}]);
See the docs or this article for more details.
Hope that helps.
Edit
When using the route config for a lazily loaded child, make sure your route configs are loaded properly in your modules. The root route config will be loaded in the root AppModule with RouterModule.forRoot(routes) and the child routes are in the Child module with RouterModule.forChild(routes).
Your route config and modules need to look like this(don't create a separate module just to hold routing config):
//Admin Routes
export const adminRoutes: Routes = [
{
path: 'admin', component: AdminComponent,
children: [
{ path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
, { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
, { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
]
}
];
//Admin Module:
import { adminRoutes } from './admin.routes';
#NgModule({
imports: [
...
RouterModule.forChild(adminRoutes),
]
...
//App Routes(lazy load Admin module)
export const appRoutes: Routes = [
{ path: 'admin', loadChildren: './admin/admin.module#AdminModule' },
....
//App Module
import { appRoutes } from './app.routes';
#NgModule({
imports: [
...
RouterModule.forRoot(appRoutes),
]
...
Hope that helps.
Yes, there is a way to do this.
You need to name your router outlet like:
<router-outlet name="child1"></router-outlet>
<router-outlet name="child2"></router-outlet>
And inside your router you need to define what router-outlet should route use:
{
path: 'home', // you can keep it empty if you do not want /home
component: 'appComponent',
children: [
{
path: '',
component: childOneComponent,
outlet: 'child1'
},
{
path: '',
component: childTwoComponent,
outlet: 'child2'
}
]
}
Original post:
Angular2 multiple router-outlet in the same template

Categories

Resources