Node.js 若しくは Python、 Ruby で簡易サーバが利用出来るように準備します
$ npm install live-server -g
$ live-server
$ npm install http-server -g
$ http-server
$ ruby -run -e httpd -- -p 8000
or
$ ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start'
$ python -m SimpleHTTPServer
- Install Visual Studio Code 0.10.1 or higher
- Launch Code
- From the command palette Ctrl-Shift-P (Windows, Linux) or Cmd-Shift-P (OSX)
- Select Install Extension
- Choose the extension
- Reload Visual Studio Code
Angular v2 TypeScript Snippets
はじめに任意のプロジェクト用フォルダーを作成し、作成したフォルダーへに移動します
$ mkdir angular-handson && cd $_
SPA の起点となる HTML ファイル等を作成します
$ touch index.html
$ touch style.css
$ touch config.js
それぞれファイルの中身は次の通りです
index.html
<!DOCTYPE html>
<html>
<head>
<base href="." />
<title>Angular PlayGround</title>
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/zone.js/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>
style.css
(empty)
config.js
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': './src',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs',
'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
Angular のコマンドラインツール
angular-cli
を利用した場合にはこうした設定は不要です。angular-cli
はスカッフォールドツールで開発に必要なテンプレートを簡単に生成することが可能だからです。
Angular のコードは src ディレクトリへ格納します
$ mkdir src
準備はここまでですが、まだ動きません。 Angular を実行するためのコードを src ディレクトリの中に記述します。
$ touch src/main.ts
$ touch src/app.ts
それぞれ
main.ts
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';
platformBrowserDynamic().bootstrapModule(AppModule);
app.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'my-app',
template: 'feature.component.html'
})
export class App implements OnInit {
constructor() { }
ngOnInit() { }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [BrowserModule],
exports: [],
declarations: [App],
providers: [],
bootstrap: [App]
})
export class AppModule { }
app.ts ではスニペットを利用します。Component では a-com
を、 Module では a-mo
とタイプしエンターキーを押すとテンプレートが出力されます。若干内容を修正すれば完了です。
Node の http-server や lite-server を起動し実行されることを確認してください。
Angular の基本的な機能であるビルトインディレクティブ(Angular が提供しているディレクティブを指しています)について触れていきます。
ngModel を利用するための準備として FormsModule を登録します
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
BrowserModule,
FormsModule
],
exports: [],
declarations: [App],
providers: [],
bootstrap: [App]
})
export class AppModule { }
template を次のように書き換えます。ブラウザにテキストボックスが表示され入力すると即座に入力した値が表示されると思います。Angular の特徴であるバインディングを利用しています。
<input type="text" [(ngModel)]="hoge">
<span>{{hoge}}</span>
[value]を利用しデータバインドしますが、こちらは片方向のバインドです。
<input type="text" [(ngModel)]="hoge">
<input [value]="hoge">
もう少しプログラムチックな動きをさせるために ngIf を利用してみます。テキストボックスに入力した値が 1 のときにメッセージを出力するというロジックを記述してみます。
<input type="text" [(ngModel)]="hoge">
<span *ngIf="hoge==='1'">1が入力されました<span>
テキストボックスに対して必須チェックを実装することが可能です。先ほどのサンプルはテキストボックスに required を入れることでその項目が必須項目となります。
<input type="text" [(ngModel)]="hoge" required>
画面上、警告も何も表示されないので何が起きているのか確認できませんが、カスケードスタイルシートを定義するとよく理解できます。
input.ng-invalid {
border-color: #ff0000;
}
何も入力されていないときにはテキストボックスの縁が赤くなっていることが確認できます。ただ、これだと入力前から赤いので UI としてはイマイチといった感じなので、ここで ng-dirty を利用します。カスケードスタイルシートを次のように変更してください。
input.ng-invalid.ng-dirty {
border-color: #ff0000;
}
こうすることで入力前は警告なしで、入力後、空欄にした場合は赤くなることが確認できます。
入力されてなかった場合、赤くなりましたがメッセージも表示します。警告メッセージは「必須入力です」にしましょう。
<form #f="ngForm" novalidate>
<input type="text" name="hoge" ngModel required>
<p [hidden]="!f.form.dirty || f.form.valid">必須入力です</p>
</form>
コンストラクタでデータを定義し ngFor で定義したデータを表示します。
<form #f="ngForm" novalidate>
<input type="text" name="hoge" ngModel required>
<p [hidden]="!f.form.dirty || f.form.valid">必須入力です</p>
</form>
<ul>
<li *ngFor="let data of demoData">{{data.name}} - {{data.age}}</li>
</ul>
Appクラスにデータを追加してください。
export class App implements OnInit {
constructor() { }
ngOnInit() { }
demoData: any = [
{name: '山田', age: 24},
{name: '田中', age: 28},
{name: '佐藤', age: 18},
{name: '井上', age: 32},
{name: '高橋', age: 46}
]
}
SPA の基本的な機能としてルーティングを扱います。ルーティング時のルートコンポーネントを
- HomeComponent
- IssueComponent
- WikiComponent
とします。スニペットを使ってそれぞれ作成します
@Component({
selector: 'my-home',
template: 'home.component.html'
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
@Component({
selector: 'my-issue',
template: 'issue.component.html'
})
export class IssueComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
@Component({
selector: 'my-wiki',
template: 'wiki.component.html'
})
export class WikiComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
次にルーティングの設定をします。スニペット a-rou
を使って作成します。
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const appRoutes: Routes= [
{ path: '', redirectTo: 'home', pathMatch: 'full'},
{ path: 'home', component: HomeComponent },
{ path: 'issue', component: IssueComponent },
{ path: 'wiki', component: WikiComponent }
];
NgModule にルータの設定を行い
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(appRoutes)
],
exports: [],
declarations: [
App,
HomeComponent,
IssueComponent,
WikiComponent
],
providers: [],
bootstrap: [App]
})
export class AppModule { }
App のテンプレートにページ切り替え用の記述をすると完了です
<h1>Issue Tracker</h1>
<ul>
<li><a routerLink="home">Home</a></li>
<li><a routerLink="issue">Issue</a></li>
<li><a routerLink="wiki">Wiki</a></li>
</ul>
<router-outlet></router-outlet>