Angular 2 の RC が出たので試しにコンポーネントを書いてみます。
インスト―ル
@angular/
で始まるのが Angular2 本体です。ほかにもいろいろ必要なのでインストールしておきます。
ビルドは Browserify + babelify を使うことにします。 angular2 むけのプリセットがあるので簡単です。
$ npm install -g browserify
$ npm install -D babelify babel-preset-es2015 babel-preset-angular2
$ npm install -S @angular/common @angular/compiler @angular/core @angular/platform-browser @angular/platform-browser-dynamic reflect-metadata rxjs zone.js
簡単なコンポーネント
情報を表示するだけの簡単なコンポーネントを作ってみます。
// a.js
import 'reflect-metadata';
import 'zone.js';
import { Component } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-component',
template: `
<section>
<h1>{{title}}</h1>
<div>{{body}}</div>
</section>
`
})
class MyComponent {
title = 'My Component';
body = `
Ipsum non officiis quis placeat impedit obcaecati? Ut nemo nulla error
deserunt quo! Eum illum architecto excepturi quas quidem ab, veniam
saepe iste. Asperiores consectetur harum id incidunt a! Delectus.
`;
}
bootstrap(MyComponent);
Polyfill である reflect-metadata
をはじめに読み込んでいます。自分の使い方が悪いのか zone.js
も明示的に読み込まないとダメでした。
@Component(...)
は MyComponent
がコンポーネントの定義であることを示します。 selector
に CSS セレクタを、 template
に文字通りテンプレートを渡します。
MyComponent
クラスは表示に必要な情報を保持させます。
bootstrap(...)
で実際のDOMのなかのコンポーネントを変換します。
これを bundle.js
に変換します。 .babelrc
を用意して browserify
コマンドをたたきます。
{ "presets": ["es2015", "angular2"] }
$ browserify -t babelify -o bundle.js a.js
HTML で <my-component>
要素を配置しつつ bundle.js
を読みこめばコンポーネントを利用できます。
<!DOCTYPE html>
<meta charset="utf-8">
<my-component></my-component>
<script src="bundle.js"></script>
コンポーネントを組み合わせて使う
コンポーネントの中でコンポーネントを使ってみます。文字を赤く表示する <my-red>
を作ってみます。
// a.js
import 'reflect-metadata';
import 'zone.js';
import { Component } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-red',
template: `
<div style="color: red">
<ng-content></ng-content>
</div>
`
})
class MyRed {}
@Component({
selector: 'my-component',
template: `
<section>
<h1>{{title}}</h1>
<my-red>
<div>{{body}}</div>
</my-red>
</section>
`,
directives: [MyRed]
})
class MyComponent {
title = 'My Component';
body = `
Ipsum non officiis quis placeat impedit obcaecati? Ut nemo nulla error
deserunt quo! Eum illum architecto excepturi quas quidem ab, veniam
saepe iste. Asperiores consectetur harum id incidunt a! Delectus.
`;
}
bootstrap(MyComponent);
ポイントは MyComponent
のデコレータで directives: [MyRed]
のように中で使うコンポーネントを渡して上げていることです。
<my-red>
のテンプレートの <ng-content>
は子要素に展開されます。
バインディング
Angular といえば双方向バインディングなので、それも試します。
// a.js
import 'reflect-metadata';
import 'zone.js';
import { Component } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-component',
template: `
<section>
<input type="text" [(ngModel)]="text">
<div>{{text}}</div>
</section>
`
})
class MyComponent {
text = 'Text';
}
bootstrap(MyComponent);
これを表示するとテキストの入力欄が表示され、すぐ下に同じ内容が表示されます。入力欄を書き換えるとすぐに下の要素の内容も切り替わります。 Angular 1 のころからよくあるやつですね。
[(ngModel)]="..."
が肝で、このように [(...)]
で囲んだ属性は双方向バインディングになるみたいです。若干わかりにくく感じますが慣れですかね。
おわりに
Angular 2 を試してみました。 1 だと依存性を細かく制御するのがきつかったですが、 2 ではそこは結構考えて設計されていそうです。
ただし、慣れないとコードの意味がわかりづらく、学習コストは高いままな印象でした。