Angular Tour of Heroes: ajout des routes et navigation

This commit is contained in:
Olivier DOSSMANN 2019-10-25 17:39:24 +02:00
parent 3f1898c529
commit 9c0ec4282d
15 changed files with 253 additions and 43 deletions

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HeroesComponent } from './heroes/heroes.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full'},
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule { }

View File

@ -0,0 +1,28 @@
/* AppComponent's private CSS styles */
h1 {
font-size: 1.2em;
margin-bottom: 0;
}
h2 {
font-size: 2em;
margin-top: 0;
padding-top: 0;
}
nav a {
padding: 5px 10px;
text-decoration: none;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #334953;
}
nav a:hover {
color: #039be5;
background-color: #cfd8dc;
}
nav a.active {
color: #039be5;
}

View File

@ -1,3 +1,7 @@
<h1>{{title}}</h1> <h1>{{title}}</h1>
<app-heroes></app-heroes> <nav>
<a routerLink="/dashboard">Dashboard</a>
<a routerLink="/heroes">Heroes</a>
</nav>
<router-outlet></router-outlet>
<app-messages></app-messages> <app-messages></app-messages>

View File

@ -6,17 +6,21 @@ import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component'; import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { MessagesComponent } from './messages/messages.component'; import { MessagesComponent } from './messages/messages.component';
import { AppRoutingModule } from './app-routing.module';
import { DashboardComponent } from './dashboard/dashboard.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
HeroesComponent, HeroesComponent,
HeroDetailComponent, HeroDetailComponent,
MessagesComponent MessagesComponent,
DashboardComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
FormsModule FormsModule,
AppRoutingModule
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -0,0 +1,63 @@
/* DashboardComponent's private CSS styles */
[class*='col-'] {
float: left;
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
}
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center;
margin-bottom: 0;
}
h4 {
position: relative;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 25%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #3f525c;
border-radius: 2px;
}
.module:hover {
background-color: #eee;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
@media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
@media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
}
}

View File

@ -0,0 +1,9 @@
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4"
routerLink="/detail/{{hero.id}}">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DashboardComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,23 @@
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}

View File

@ -0,0 +1,31 @@
/* HeroDetailComponent's private CSS styles */
label {
display: inline-block;
width: 3em;
margin: .5em 0;
color: #607D8B;
font-weight: bold;
}
input {
height: 2em;
font-size: 1em;
padding-left: .4em;
}
button {
margin-top: 20px;
font-family: Arial;
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
cursor: hand;
}
button:hover {
background-color: #cfd8dc;
}
button:disabled {
background-color: #eee;
color: #ccc;
cursor: auto;
}

View File

@ -9,4 +9,7 @@
</label> </label>
</div> </div>
<button (click)="goBack()">go back</button>
</div> </div>

View File

@ -1,5 +1,9 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { Hero } from '../hero'; import { Hero } from '../hero';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
import { HeroService } from '../hero.service';
@Component({ @Component({
selector: 'app-hero-detail', selector: 'app-hero-detail',
@ -8,9 +12,25 @@ import { Hero } from '../hero';
}) })
export class HeroDetailComponent implements OnInit { export class HeroDetailComponent implements OnInit {
@Input() hero: Hero; @Input() hero: Hero;
constructor() { }
ngOnInit() { constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) { }
ngOnInit(): void {
this.getHero();
}
getHero(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.heroService.getHero(id)
.subscribe(hero => this.hero = hero);
}
goBack(): void {
this.location.back();
} }
} }

View File

@ -16,4 +16,10 @@ export class HeroService {
this.messageService.add('HeroService: fetched heroes.') this.messageService.add('HeroService: fetched heroes.')
return of(HEROES); return of(HEROES);
} }
getHero(id: number): Observable<Hero> {
// TODO: send the message _after_ fetching the hero
this.messageService.add(`HeroService: fetched hero id=${id}`);
return of(HEROES.find(hero => hero.id === id));
}
} }

View File

@ -6,39 +6,26 @@
width: 15em; width: 15em;
} }
.heroes li { .heroes li {
cursor: pointer;
position: relative; position: relative;
left: 0; cursor: pointer;
background-color: #EEE; background-color: #EEE;
margin: .5em; margin: .5em;
padding: .3em 0; padding: .3em 0;
height: 1.6em; height: 1.6em;
border-radius: 4px; border-radius: 4px;
} }
.heroes li:hover { .heroes li:hover {
color: #607D8B; color: #607D8B;
background-color: #DDD; background-color: #DDD;
left: .1em; left: .1em;
} }
.heroes li.selected {
background-color: #CFD8DC; .heroes a {
color: white; color: #333;
} text-decoration: none;
.heroes li.selected:hover {
background-color: #BBD8DC;
color: white;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color:#405061;
line-height: 1em;
position: relative; position: relative;
left: -1px; display: block;
top: -4px; width: 250px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
} }

View File

@ -2,12 +2,9 @@
<ul class="heroes"> <ul class="heroes">
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes">
[class.selected]="hero === selectedHero" <a routerLink="/detail/{{hero.id}}">
(click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}}
<span class="badge">{{hero.id}}</span> {{hero.name}} </a>
</li> </li>
</ul> </ul>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

View File

@ -10,10 +10,6 @@ import { HeroService } from '../hero.service';
}) })
export class HeroesComponent implements OnInit { export class HeroesComponent implements OnInit {
heroes: Hero[]; heroes: Hero[];
hero: Hero = {
id: 1,
name: 'Windstorm'
};
constructor(private heroService: HeroService) { } constructor(private heroService: HeroService) { }
@ -21,11 +17,6 @@ export class HeroesComponent implements OnInit {
this.getHeroes(); this.getHeroes();
} }
selectedHero: Hero;
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
getHeroes(): void { getHeroes(): void {
this.heroService.getHeroes() this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes); .subscribe(heroes => this.heroes = heroes);