My Routing isn't working in Angular2, to demonstrate the point, I have put the same component as the destination for both the root of my site and /login. The component works at http://localhost:3000, but at http://localhost:3000/login, I just get a notice "Cannot GET /login".
app.component.ts:
import { Component } from 'angular2/core';
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router';
import {TodoService} from './todo/services/todo.service';
import { TodoCmp } from './todo/components/todo.component';
import { LoginComponent } from './user/components/login.component';
import { UserService } from './user/services/user.service';
#Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<router-outlet></router-outlet>
`,
styleUrls: ['client/dev/todo/styles/todo.css'],
directives: [ROUTER_DIRECTIVES],
providers: [
ROUTER_PROVIDERS,
TodoService
]
})
#RouteConfig([
{
path: '/',
name: 'TodoCmp',
component: TodoCmp,
useAsDefault: true
},
{
path: '/login',
name: 'TodoCmp',
component: TodoCmp
}
])
export class AppComponent {
title = 'ng2do';
}
Here is a link to my index file.
What have I done wrong?
Two routes in one #RouteConfig(...) can't have the same name:
#RouteConfig([
{
path: '/',
name: 'TodoCmp',
component: TodoCmp,
useAsDefault: true
},
{
path: '/login',
name: 'TodoCmp', <!-- <<<== should be 'Login' instead of 'TodoCmp'
component: TodoCmp
}
])
You should move ROUTER_PROVIDERS to bootstrap() (like HTTP_PROVIDERS)
Related
how can I make sure to have at least 2 router-outlets and manage them at the routing level?
can link me a working jsfillde or stackblitz or similar?
edited re open problem
APP COMPONENT HTML
<main [#fadeInAnimation]="o.isActivated ? o.activatedRoute : ''">
<router-outlet #o="outlet" name="main"></router-outlet>
<router-outlet #o="outlet" name="second"></router-outlet>
</main>
APP MODULE
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { HttpClientModule } from '#angular/common/http';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
// components
import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component';
// models
import { Permissions } from '../app/models/permissions';
// guards
import { CanAccess } from '../app/guards/canaccess';
import { OtherComponent } from './components/other/other.component';
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
const permissions: Permissions = new Permissions();
const appRoute: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'main' },
{ path: 'other', component: OtherComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'second' },
{ path: 'pageNotFound', component: PageNotFoundComponent, data: { permission: permissions }, canActivate: [CanAccess], outlet: 'main' },
{ path: '**', redirectTo: 'pageNotFound', pathMatch: 'full' },
];
export function appConfigFactory() {
try {
return () => true;
} catch (e) {
console.log(`catch load: ${e}`);
}
}
#NgModule({
declarations: [
AppComponent,
HomeComponent,
OtherComponent,
PageNotFoundComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
RouterModule.forRoot(appRoute)
],
providers: [
CanAccess,
{
provide: APP_INITIALIZER,
useFactory: appConfigFactory,
deps: [],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
ERROR
ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'home'
Error: Cannot match any routes. URL Segment: 'home'
can view on editor
https://stackblitz.com/edit/angular-ghusfs
thanks
You may define parent child component to use multiple router-outlets like this.
{
path: 'shop', component: ParentShopComponent,
children : [{
path: 'hello', component: ChildShopComponent
}]
}
Your first <router-outlet> will be in app component & second in ParentShopComponent rest of components can lend in child level or parent.
But if your relationship is child parent than check this out Named Router Outlets
Example
This is main Router OUtlet
These are named ones
<div class="columns">
<md-card>
<router-outlet name="list"></router-outlet>
</md-card>
<md-card>
<router-outlet name="bio"></router-outlet>
</md-card>
</div>
And here's how you use them
{ path: 'speakersList', component: SpeakersListComponent, outlet: 'list' }
Yesterday I asked a question about an another specific thing of angular 2 routing and the answer was satisfying for me Angular 2 — navigate through web pages without reloading a component that is common for those pages . But when I got back to examining these things, I encountered a problem again. Here's the new version of the app: http://ivan-khludov.com/ . What if I want the pages of the private section to have a shared component (a counter in my example), don't reload it each time I navigate withing the section and at the same time display different components at different pages - the dashboard component at private/dashboard and the inbox component at private/inbox? Is it possible to do without reloading the counter and without storing the last value of the counter in memory? This is the entry point of the application and the root module:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { HttpModule } from '#angular/http';
import { RouterModule } from '#angular/router';
import { BrowserModule } from '#angular/platform-browser';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { ROUTES } from './routes';
import { AppWrapper } from './components/app-wrapper';
import { PublicSection } from './components/public';
import { PrivateSection } from './components/private';
import { Counter } from './components/counter';
import { Dashboard } from './components/private/dashboard';
import { Inbox } from './components/private/inbox';
#NgModule({
imports: [
BrowserModule,
CommonModule,
HttpModule,
RouterModule.forRoot(ROUTES)
],
declarations: [
AppWrapper,
PublicSection,
PrivateSection,
Counter,
Dashboard,
Inbox
],
providers: [
],
bootstrap: [
AppWrapper
]
})
class RootModule {}
platformBrowserDynamic().bootstrapModule(RootModule);
Routing:
import { Routes } from '#angular/router';
import { AppWrapper } from '../components/app-wrapper';
import { PublicSection } from '../components/public';
import { PrivateSection } from '../components/private';
export const ROUTES: Routes = [
{
path: '',
redirectTo: '/public/1',
pathMatch: 'full'
},
{
path: 'section-1',
redirectTo: '/public/1',
pathMatch: 'full'
},
{
path: 'public/:page',
component: PublicSection
},
{
path: 'private',
redirectTo: '/private/dashboard',
pathMatch: 'full'
},
{
path: 'private/:page',
component: PrivateSection
}
];
The private section component:
import { Component } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'private',
template: `
<h2>Private section — {{page}}</h2>
<counter></counter>
<dashboard></dashboard>
<inbox></inbox>
`
})
export class PrivateSection {
private page: string;
private sub: any;
constructor(
private route: ActivatedRoute
) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.page = params['page'];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
The dashboard component:
import { Component } from '#angular/core';
#Component({
selector: 'dashboard',
template: `
<div>dashboard text: lorem ipsum</div>
`
})
export class Dashboard {
}
The inbox component:
import { Component } from '#angular/core';
#Component({
selector: 'inbox',
template: `
<div>inbox text: dolor sit amet</div>
`
})
export class Inbox {
}
Thanks in advance for your answers.
I am a beginner in angular2.
I try to use routes in a CRUD app. My problem are the nested routes. Chart example :
AppComponent
/ \
MealListComponent DishListComponent
\
DishEditComponent <--- Must have DishList template
The link / and \ respresent routes.
Problem : I want my DishEditComponent template is not include on DishListComponent template.
You can test app on http://plnkr.co/edit/g7NaoVd5BkGtSmr8ZkFW?p=preview go to Liste Dish link, then to Add dish link.
You'll see both Dish List title and Dish Edit orr Add title because DishEditComponent template is included in DishListComponent template by router-outlet tag, but I want that only Dish Edit or Add title displayed.
Do you know a way to avoid nested routes ?
You can try using asyncRoute.
Here is explanation for it.
import {Component, View, bootstrap} from 'angular2/angular2';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router';
import {Home} from './components/home/home';
import {About} from './components/about/about';
#Component({
selector: 'app'
})
#RouteConfig([
{ path: '/', component: Home, name: 'home' },
{ path: '/about', component: About, name: 'about' }
])
#View({
templateUrl: './app.html',
styleUrls: ['./app.css'],
directives: [ROUTER_DIRECTIVES]
})
class App {}
bootstrap(App, [ROUTER_PROVIDERS]);
Here’s the implementation of the About component:
import {Component, View, CORE_DIRECTIVES} from 'angular2/angular2';
import {NameList} from '../../services/NameList';
#Component({
selector: 'about',
providers: [NameList],
templateUrl: './components/about/about.html',
directives: [CORE_DIRECTIVES]
})
export class About {
constructor(public list: NameList) {}
addName(newname):boolean {
this.list.add(newname.value);
newname.value = '';
return false;
}
}
The class, which implements RouteDefinition and allows asynchronous loading of the component associated with given route. This allows on demand loading of the component’s dependencies as well. Here’s now our definition will look like with AsyncRoute:
#RouteConfig([
{ path: '/', component: Home, name: 'home' },
new AsyncRoute({
path: '/about',
loader: () => System.import('./components/about/about').then(m => m.About),
name: 'about'
})
])
Basically we register two routes: - A regular route - Async route. The async route accepts as argument a loader. The loader is a function that must return a promise, which needs to be resolved with the component that needs to be rendered.
I found the solution.
1. I must remove this line in DishListComponent template :
<router-outlet></router-outlet>
2. Replace line :
<a [routerLink]="['DishEdit']">Add dish</a>
by this line :
<button (click)="addDish()">Add dish</button>
3. Add import :
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, Router } from '#angular/router-deprecated';
4. Update DishListComponent constructor :
constructor(private router: Router) {
}
5. Add this method in DishListComponent :
addDish() {
let link = ['DishEdit', {}];
this.router.navigate(link);
}
6. Remove PROVIDERS in DishListComponent
Final code
Final DishListComponent
#Component({
selector: 'dish-list',
directives: [ROUTER_DIRECTIVES],
template:`
<h1>Dish List</h1>
<button (click)="addDish()">Add dish</button>
<main>
</main>
`
})
export class DishListComponent {
constructor(private router: Router) {
}
addDish() {
let link = ['DishEdit', {}];
this.router.navigate(link);
}
}
The final RouteConfig
#RouteConfig([
{
path: '/dish-list',
name: 'DishList',
component: DishListComponent
//useAsDefault: true
},
{
path: '/dish-edit',
name: 'DishEdit',
component: DishEditComponent
},
{
path: '/meal-list',
name: 'MealList',
component: MealListComponent
}
])
The plunker link : http://plnkr.co/edit/LsLdc0efJtPaEbASWPek?p=preview
I hope it will help !
I've been trying out Angular 2 since beta, and now with rc.0+ some things have changed.
One of those are RouteParams which cannot be imported from #angular/router. And when I try with #angular/router-deprecated I get an error message:
ORIGINAL EXCEPTION: No provider for RouteParams!
app.component:
#Routes([
{ path: '/', component: StartComponent },
{path: '/:projId/:userName', component: ProjectListComponent},
{ path: '*', component: StartComponent },
])
project-list.component:
import {Component, OnInit} from '#angular/core';
import {RouteParams} from '#angular/router-deprecated';
#Component({
...
})
export class ProjectListComponent implements OnInit {
userName:string;
projId:string;
constructor(private params:RouteParams) {
this.userName = params.get('userName');
this.projId = params.get('projId');
}
}
Where can I import the RouteParams from now, or is it something else I'm doing wrong?
Thanks!
One way is
routerOnActivate(curr: RouteSegment) {
this.userName = curr.getParam('userName');
this.projId = curr.getParam('projId');
}
You have to use RouteSegment instead of using RouteParams in angular2 RC. like this :-
import { Component } from '#angular/core';
import { Routes, RouteSegment, ROUTER_DIRECTIVES } from '#angular/router';
#Component({
selector: 'about-item',
template: `<h3>About Item Id: {{id}}</h3>`
})
class AboutItemComponent {
id: any;
constructor(routeSegment: RouteSegment) {
this.id = routeSegment.getParam('id');
}
}
#Component({
selector: 'app-about',
template: `
<h2>About</h2>
<a [routerLink]="['/about/item', 1]">Item 1</a>
<a [routerLink]="['/about/item', 2]">Item 2</a>
<div class="inner-outlet">
<router-outlet></router-outlet>
</div>
`,
directives: [ROUTER_DIRECTIVES]
})
#Routes([
{ path: '/item/:id', component: AboutItemComponent }
])
export class AboutComponent { }
Angular 2 - Is it possible to store my routes in another file and import them into the app.ts file (because over time the routes will build up)
Here is an example of my current app.ts that works. I basically want to move the route config routes to another file to make it cleaner:
import {Todo} from './components/todo/todo';
import {About} from './components/about/about';
import {AuthService} from './authService';
import {Component, View, bootstrap, bind, provide} from 'angular2/angular2';
import {Router, ROUTER_BINDINGS, RouterOutlet, RouteConfig, RouterLink, ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';
import {Location, LocationStrategy, HashLocationStrategy} from 'angular2/router';
#Component({
selector: 'app'
})
#View({
template: `
<div class="container">
<nav>
<ul>
<li><a [router-link]="['/Home']">Todo</a></li>
<li><a [router-link]="['/About']">About</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
`,
directives: [RouterOutlet, RouterLink]
})
#RouteConfig([
{ path: '/', redirectTo: '/home' },
{ path: '/home', component: Todo, as: 'Home' },
{ path: '/about', component: About, as: 'About' }
])
export class AppComponent {
constructor(router: Router, _authService: AuthService, _location: Location){
//Subscribe - watches routes pop state events.
router.subscribe((val) => {
_authService.isUserLoggedIn().then((success) => {
router.parent.navigate(['/About']);
});
})
}
}
bootstrap(AppComponent, [ROUTER_PROVIDERS, provide(APP_BASE_HREF, {useValue: '/'}), AuthService]);
i personally have created an route.interface.ts and a route.ts files.
Routes file
import {Route} from './route.interface'
import {AuthComponent} from './auth/auth.component'
export const Routes: Route[] = [
{
path: '/auth',
name: 'Authenticate',
component: AuthComponent
},
];
Route Interface
export interface Route {
path: string,
name: string,
component: any,
}
Usage in main component.
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'
import {Routes} from './routes'
#Component({
selector: 'app',
templateUrl: './angular2/app/layout.component.html',
directives: [
ROUTER_DIRECTIVES
],
providers: [
HTTP_PROVIDERS,
ROUTER_PROVIDERS
],
})
#RouteConfig(Routes)
Hope that helps. you can even create a route service and inject it you main component. Enjoy coding!
You can add your RouteConfig per component
Lets say you have home and about as in your example, then you would define the routing from that specific component in the component itself.
So in your about component you can add
// './components/about/about'
#RouteConfig([
{ path: '/about', component: About, as: 'About' }
])
And in your home component you can do the same
// './components/home/home'
#RouteConfig([
{ path: '/home', component: Todo, as: 'Home' }
])