import {Component} from '@angular/core';
@Component({
moduleId: module.id,
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<nav>
<a routerLink="/dashboard" routerLinkActive="active">ダッシュボード</a>
<a routerLink="/heroines" routerLinkActive="active">ヒロインたち</a>
</nav>
<router-outlet></router-outlet>
`,
styleUrls: ['app.component.css']
})
export class AppComponent {
title = 'ヒロイン一覧';
}
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {InMemoryWebApiModule} from 'angular-in-memory-web-api';
import {InMemoryDataService} from './in-memory-data.service';
import {AppComponent} from './app.component';
import {HeroineDetailComponent} from './heroine-detail.component';
import {HeroinesComponent} from './heroines.component';
import {HeroineService} from './heroine.service';
import {DashboardComponent} from './dashboard.component';
import {AppRoutingModule} from './app-routing.module';
import {HeroineSearchComponent} from './heroine-search.component';
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
InMemoryWebApiModule.forRoot(InMemoryDataService),
AppRoutingModule
],
declarations: [
AppComponent,
DashboardComponent,
HeroineDetailComponent,
HeroinesComponent,
HeroineSearchComponent
],
providers: [HeroineService],
bootstrap: [AppComponent]
})
export class AppModule {}
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
body {
margin: 2em;
}
body, input[text], button {
color: #888;
font-family: Cambria, Georgia;
}
a {
cursor: pointer;
cursor: hand;
}
button {
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: #aaa;
cursor: auto;
}
nav a {
padding: 5px 10px;
text-decoration: none;
margin-right: 10px;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #607D8B;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
}
nav a.active {
color: #039be5;
}
.items {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 24em;
}
.items li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.items li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.items li.selected {
background-color: #CFD8DC;
color: white;
}
.items li.selected:hover {
background-color: #BBD8DC;
}
.items .text {
position: relative;
top: -3px;
}
.items .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
* {
font-family: Arial, Helvetica, sans-serif;
}
<html>
<head>
<!-- <base href="/"> -->
<script>document.write('<base href="' + document.location + '" />');</script>
<title>Angular QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. ライブラリの読み込み -->
<!-- 古いブラウザへの対応 --><script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.7.2?main=browser"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.8"></script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
<!-- 2. SystemJSの設定 -->
<!--<script src="systemjs.config.js"></script>-->
<script src="https://cdn.rawgit.com/angular/angular.io/b3c65a9/public/docs/_examples/_boilerplate/systemjs.config.web.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. アプリケーションの表示 -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
export class Heroine {
id: number;
name: string;
}
import 'rxjs/add/operator/switchMap';
import {Component, Input, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from '@angular/router';
import {Location} from '@angular/common';
import {Heroine} from './heroine';
import {HeroineService} from './heroine.service';
@Component({
moduleId: module.id,
selector: 'my-heroine-detail',
templateUrl: 'heroine-detail.component.html',
styleUrls: ['heroine-detail.component.css']
})
export class HeroineDetailComponent implements OnInit {
@Input()
heroine: Heroine;
constructor(
private heroineService: HeroineService,
private route: ActivatedRoute,
private location: Location
) {}
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => this.heroineService.getHeroine(+params['id']))
.subscribe((heroine: Heroine) => this.heroine = heroine);
}
goBack(): void {
this.location.back();
}
save(): void {
this.heroineService.update(this.heroine)
.then(() => this.goBack());
}
}
import {Heroine} from './heroine';
export const HEROINES: Heroine[] = [
{ id: 11, name: 'シータ' },
{ id: 12, name: 'ナウシカ' },
{ id: 13, name: 'キキ' },
{ id: 14, name: '千尋' },
{ id: 15, name: 'さつき' },
{ id: 16, name: 'ソフィー' },
{ id: 17, name: 'マーニー' },
{ id: 18, name: '菜穂子' },
{ id: 19, name: 'サン' },
{ id: 20, name: 'フィオ' }
];
import {Injectable} from '@angular/core';
import {Headers, Http, Response} from '@angular/http';
import 'rxjs/add/operator/toPromise';
import {Heroine} from './heroine';
@Injectable()
export class HeroineService {
private headers: Headers = new Headers({'Content-Type': 'application/json'});
private heroinesUrl: string = 'api/heroines';
constructor(private http: Http) {}
getHeroines(): Promise<Heroine[]> {
return this.http.get(this.heroinesUrl)
.toPromise()
.then((response: Response) => response.json().data as Heroine[])
.catch(this.handleError);
}
getHeroine(id: number): Promise<Heroine> {
const url: string = `${this.heroinesUrl}/${id}`;
return this.http.get(url)
.toPromise()
.then((response: Response) => response.json().data as Heroine)
.catch(this.handleError);
}
create(name: string): Promise<Heroine> {
return this.http
.post(this.heroinesUrl, JSON.stringify({name: name}), {headers: this.headers})
.toPromise()
.then((response: Response) => response.json().data)
.catch(this.handleError);
}
delete(id: number): Promise<void> {
const url = `${this.heroinesUrl}/${id}`;
return this.http.delete(url, {headers: this.headers})
.toPromise()
.then(() => null)
.catch(this.handleError);
}
update(heroine: Heroine): Promise<Heroine> {
const url: string = `${this.heroinesUrl}/${heroine.id}`;
return this.http
.put(url, JSON.stringify(heroine), {headers: this.headers})
.toPromise()
.then(() => heroine)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occured', error);
return Promise.reject(error.message || error);
}
}
h1 {
font-size: 1.2em;
color: #999;
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: #607D8B;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
}
nav a.active {
color: #039be5;
}
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {HeroineDetailComponent} from './heroine-detail.component';
import {HeroinesComponent} from './heroines.component';
import {DashboardComponent} from './dashboard.component';
const routes: Routes = [
{
path: '',
redirectTo: '/dashboard',
pathMatch: 'full'
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: 'heroines',
component: HeroinesComponent
},
{
path: 'detail/:id',
component: HeroineDetailComponent
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule {}
[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: #607D8B;
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;
}
}
<h3>トップヒロイン</h3>
<div class="grid grid-pad">
<a *ngFor="let heroine of heroines" [routerLink]="['/detail', heroine.id]" class="col-1-4">
<div class="module heroine">
<h4>{{heroine.name}}</h4>
</div>
</a>
</div>
<heroine-search></heroine-search>
import {Component, OnInit} from '@angular/core';
import {Heroine} from './heroine';
import {HeroineService} from './heroine.service';
@Component({
moduleId: module.id,
selector: 'my-dashboard',
templateUrl: 'dashboard.component.html',
styleUrls: ['dashboard.component.css']
})
export class DashboardComponent implements OnInit {
heroines: Heroine[];
constructor(private heroineService: HeroineService) {}
ngOnInit(): void {
this.heroineService.getHeroines()
.then((heroines: Heroine[]) => this.heroines = heroines.slice(0, 4));
}
}
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;
}
<div *ngIf="heroine">
<h2>{{heroine.name}}の情報</h2>
<div><label>番号: </label>{{heroine.id}}</div>
<div>
<label>名前: </label>
<input [(ngModel)]="heroine.name" placeholder="名前">
</div>
<button (click)="goBack()">戻る</button>
<button (click)="save()">保存</button>
</div>
.selected {
background-color: #CFD8DC !important;
color: white;
}
.heroines {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
.heroines li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: 0.5em;
padding: 0.3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroines li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroines li:hover {
color: #607D8B;
background-color: #DDD;
left: 0.1em;
}
.heroines .text {
position: relative;
top: -3px;
}
.heroines .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
button.delete {
float:right;
margin-top: 2px;
margin-right: .8em;
background-color: gray !important;
color:white;
}
<h2>ヒロインたち</h2>
<div>
<label>ヒロイン名:</label> <input #heroineName />
<button (click)="add(heroineName.value); heroineName.value=''">
追加
</button>
</div>
<ul class="heroines">
<li *ngFor="let heroine of heroines"
[class.selected]="heroine === selectedHeroine"
(click)="onSelect(heroine)">
<span class="badge">{{heroine.id}}</span>
<span>{{heroine.name}}</span>
<button class="delete"
(click)="delete(heroine); $event.stopPropagation()">x</button>
</li>
</ul>
<div *ngIf="selectedHeroine">
<h2>
ヒロイン「{{selectedHeroine.name}}」
</h2>
<button (click)="gotoDetail()">詳細を見る</button>
</div>
import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';
import {Heroine} from './heroine';
import {HeroineService} from './heroine.service';
@Component({
moduleId: module.id,
selector: 'my-heroines',
templateUrl: 'heroines.component.html',
styleUrls: ['heroines.component.css']
})
export class HeroinesComponent implements OnInit {
heroines: Heroine[];
selectedHeroine: Heroine;
constructor(
private router: Router,
private heroineService: HeroineService
) {}
onSelect(heroine: Heroine): void {
this.selectedHeroine = heroine;
}
getHeroines(): void {
this.heroineService.getHeroines().then((heroines: Heroine[]) => this.heroines = heroines);
}
add(name: string): void {
name = name.trim();
if (!name) {return;}
this.heroineService.create(name)
.then((heroine: Heroine) => {
this.heroines.push(heroine);
this.selectedHeroine = null;
});
}
delete(heroine: Heroine): void {
this.heroineService
.delete(heroine.id)
.then(() => {
this.heroines = this.heroines.filter((_heroine: Heroine) => _heroine !== heroine);
if (this.selectedHeroine === heroine) {
this.selectedHeroine = null;
}
});
}
ngOnInit(): void {
this.getHeroines();
}
gotoDetail(): void {
this.router.navigate(['/detail', this.selectedHeroine.id]);
}
}
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
import {InMemoryDbService} from 'angular-in-memory-web-api';
import {Heroine} from './heroine';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
let heroines: Heroine[] = [
{id: 11, name: 'シータ'},
{id: 12, name: 'ナウシカ'},
{id: 13, name: 'キキ'},
{id: 14, name: '千尋'},
{id: 15, name: 'さつき'},
{id: 16, name: 'ソフィー'},
{id: 17, name: 'マーニー'},
{id: 18, name: '菜穂子'},
{id: 19, name: 'サン'},
{id: 20, name: 'フィオ'}
];
return {heroines};
}
}
import {Injectable} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import {Heroine} from './heroine';
@Injectable()
export class HeroineSearchService {
constructor(private http: Http) {}
search(term: string): Observable<Heroine[]> {
return this.http
.get(`app/heroines/?name=${term}`)
.map((response: Response) => response.json().data as Heroine[]);
}
}
<div id="search-component">
<h4>ヒロイン検索</h4>
<input #searchBox id="search-box" (keyup)="search(searchBox.value)" />
<div>
<div *ngFor="let heroine of heroines | async"
(click)="gotoDetail(heroine)" class="search-result" >
{{heroine.name}}
</div>
</div>
</div>
.search-result {
border-bottom: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
width: 195px;
height: 16px;
padding: 5px;
background-color: white;
cursor: pointer;
}
.search-result:hover {
color: #eee;
background-color: #607D8B;
}
#search-box {
width: 200px;
height: 20px;
}
import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import {HeroineSearchService} from './heroine-search.service';
import {Heroine} from './heroine';
@Component({
moduleId: module.id, // [*1]
selector: 'heroine-search',
templateUrl: './heroine-search.component.html',
styleUrls: ['./heroine-search.component.css'],
providers: [HeroineSearchService]
})
export class HeroineSearchComponent implements OnInit {
heroines: Observable<Heroine[]>;
private searchTerms = new Subject<string>();
constructor(
private heroineSearchService: HeroineSearchService,
private router: Router) {}
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit(): void {
this.heroines = this.searchTerms
.debounceTime(300)
.distinctUntilChanged()
.switchMap((term: string) => term
? this.heroineSearchService.search(term)
: Observable.of<Heroine[]>([]))
.catch(error => {
console.log(error);
return Observable.of<Heroine[]>([]);
});
}
gotoDetail(heroine: Heroine): void {
let link = ['/detail', heroine.id];
this.router.navigate(link);
}
}