サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

Angular 4入門 01: 編集ページをつくる


「Angular 4入門」シリーズはAngular公式サイトの「TUTORIAL」をもとに、説明の仕方や進め方を手直ししたものです。コードの動きは段階を細かく分けて確かめるようにし、TypeScriptの構文についても補いました。本稿では、基本的な機能であるデータバインディングについてご説明します。Angular 4をよく知らなかったり、まだ環境ができていない方は、「Angular 4: とにかくAngular 4でコードを書いて動かす」を先に読まれるとよいでしょう。

Angular Version 5については「Angular 5入門 01: アプリケーションの枠組みをつくる」および「Angular 5入門 02: 編集ページをつくる」をお読みください。

01 もとにする作例ファイル

本稿の解説は、前出「Angular 4: とにかくAngular 4でコードを書いて動かす」でつくったファイル(コード001およびコード002)に手を加えるかたちで進めます(中身はAngular公式サイトの「QUICKSTART」と同じです)。ファイルの構成は、つぎの図001のとおりです。プロジェクトのフォルダの名前は、どのように変えても構いません。

図001■「Angular 4: とにかくAngular 4でコードを書いて動かす」でつくったファイル構成

図001

02 Visual Studio Codeのlaunch.jsonファイルに設定を加える

Visual Studio Codeを使う場合(「Visual Studio Codeでビルドしてアプリケーションを起ち上げる」参照)には、launch.jsonファイルにつぎのように"cwd"属性を加えてください。デバッグされるプログラムの作業ディレクトリへの絶対パスを定めます。bs-config.jsonが見つからないというエラーにより、正しくデバッグできない問題を避けるためです。


{

	"configurations": [
		{

			"program": "${workspaceRoot}/node_modules/lite-server/bin/lite-server",
			"cwd": "${workspaceRoot}"
		}
	]
}

03 HTMLドキュメントを書き替える

まず、HTMLドキュメントの<head>要素は、つぎのように書き替えます。もとのファイルと組み立てはほぼ同じです。変わったのは、JavaScriptライブラリ3つをCDN(unpkg)から読み込んでいます。サーバーで試すときも、ライブラリのアップロードは要りません。index.html全体は、以下のコード001にまとめました。

<head>要素

<title>Angular Tour of Heroines</title>

<!--<script src="node_modules/core-js/client/shim.min.js"></script>-->
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<!--<script src="node_modules/zone.js/dist/zone.js"></script>-->
<script src="https://unpkg.com/zone.js@0.8.4?main=browser"></script>
<!--<script src="node_modules/systemjs/dist/system.src.js"></script>-->
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

コード001■アプリケーションを動かすHTMLドキュメント

index.html

<!DOCTYPE html>
<html>
<head>
	<title>Angular Tour of Heroines</title>
	<base href="/">
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="styles.css">
	<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
	<script src="https://unpkg.com/zone.js@0.8.4?main=browser"></script>
	<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
	<script src="systemjs.config.js"></script>
	<script>
		System.import('main.js').catch(function(err){console.error(err);});
	</script>
</head>
<body>
	<my-app>Loading AppComponent content here ...</my-app>
</body>
</html>

なお、CSSファイル(styles.css)については、「TUTORIAL」(Plunker)からコピーして使うことにしましょう。

04 コンポーネントのクラスに定めたプロパティの値を要素に差し込む

つぎに、コンポーネントのクラス(AppComponent)に、つぎのようにプロパティ(titleとheroine)を加えます。この値は、クラスのデコレータに定めたComponent()関数で、引数オブジェクトに定めたテンプレート(template)の中から取り出せます。二重波括弧{{}}でプロパティをくくるのが参照の仕方です。ビルドしてアプリケーションを試すと、以下の図002のようにコンポーネントのクラスのプロパティ値が、差し込まれた要素のテキストとして示されます。

app.component.ts


@Component({

	template: `<h1>{{title}}</h1><h2>{{heroine}}の情報</h2>`  // `<h1>Hello {{name}}</h1>`,
})
export class AppComponent {
	title = 'ヒロイン一覧';
	heroine = 'シータ';
}

図002■コンポーネントのクラスのプロパティ値が要素のテキストに差し込まれた

図002

なお、デコレータ関数(Component())は渡された引数にもとづいて、そのあとに宣言されたクラス(AppComponent)を実行時に処理します(「TypeScript入門 12: デコレータ(Decorator)を使う」参照)。また、exportはファイルに分けたモジュールを、別のモジュールから使えるようにする仕組みです。他のモジュールは、使いたいモジュールとその宣言(クラスや関数など)をimportします(「TypeScript入門 10: モジュール ー exportとimport」参照)。

プロパティにオブジェクトを与えれば、複数の値が含められます。そこで、つぎのように新たなクラス(Heroine)を定め、そこにプロパティ(idとname)を加えました。そして、コンポーネントのクラス(AppComponent)のプロパティ(heroine)は、その型づけにしてオブジェクトを与えています。もっとも、そのオブジェクトは新しいクラスのインスタンスではありません。TypeScriptでは、クラスを継承しなくても、オブジェクトに同じ型のプロパティが揃っていれば互換性は認められるのです(「TypeScript入門 08: 型の互換性」参照)。アプリケーションから表示されるページは、とくに変わりありません(前掲図002)。

app.component.ts


export class Heroine {
	id: number;
	name: string;
}
@Component({

	template: `<h1>{{title}}</h1><h2>{{heroine.name}}の情報</h2>`
		// `<h1>{{title}}</h1><h2>{{heroine}}の情報</h2>`
})
export class AppComponent {

	// heroine = 'シータ';
	heroine: Heroine = {
		id: 1,
		name: 'シータ'
	};
}

05 コンポーネントのテンプレートに値の入ったラベルとテキスト入力フィールドを加える

さらに、コンポーネントのテンプレートに要素を加えます。デコレータ関数(Component())の引数オブジェクトに与えたtemplateに、タグを書き足すということです。値の文字列には、バックティック(`)が使ってありました。TypeScriptでは、ECMAScript 2015(ES6)のテンプレート文字列(Template literal)が入力できるのです。クォーテーション("')と異なり、空白文字が無視されるので、つぎのようにHTMLのタグと同じように改行やインデントで書式を見やすく整えられます。


@Component({

	template: `
		<h1>{{title}}</h1>
		<h2>{{heroine.name}}の情報</h2>
		<div><label>番号: </label>{{heroine.id}}</div>
		<div><label>名前: </label>{{heroine.name}}</div>
		`
		// `<h1>{{title}}</h1><h2>{{heroine.name}}の情報</h2>`
})

アプリケーションをビルドして試すと、コンポーネントから差し込まれる要素にラベルとテキストが加わり、コンポーネントのクラス(AppComponent)のプロパティから得られた値が示されます(図003)。クラスのデータを要素に結びつけることは「バインディング」といいます。

図003■コンポーネントから差し込まれる要素にラベルとテキストが加わった

図003

06 編集されたテキストをコンポーネントに反映する

テストのひとつをテキスト入力フィールドにして、打ち込んだテキストをクラスのプロパティ値にバインディングしましょう。つぎのように、Angular 2のモジュールからFormsModuleクラスimportします。そいて、アプリケーションのクラス(AppModule)に定めたデコレータ関数(NgModule())で、引数オブジェクトのプロパティimportsに配列要素として加えます。なお、関数NgModule()の詳細は、「NgModule導入について」をご参照ください。

app.module.ts

import {FormsModule} from '@angular/forms';

@NgModule({
	imports: [
		BrowserModule,
		FormsModule
	],

})
export class AppModule {}

FormsModuleクラスのNgModelディレクティブを使うと、双方向のバインディングができます。コンポーネント(AppComponent)のテンプレート(template)は、要素をつぎのように書き替えます。テキスト入力フィールド(<input>要素)には[()]でくくったディレクティブを加え、プロパティの参照を文字列で定めます。プロパティは{{}}でくくらないことにご注意ください。

app.component.ts

@Component({

	template: `

		<div>
			<label>名前: </label>
			<input [(ngModel)]="heroine.name" placeholder="名前">
		</div>
		`
		/*	{{heroine.name}}</div>
		` */
})
export class AppComponent {

}

アプリケーションをビルドして確かめると、テキストフィールドに入力したテキストでコンポーネントのクラス(AppComponent)のプロパティ(heroine.name)値が書き替わり、その値を参照する他の要素(<h2>)の表示に反映されます(図004)。ここまで書き上げたアプリケーションとコンポーネントのモジュールは、以下のコード002にまとめました。併せて、Plunkerに作例のコードを掲げています。

図004■テキスト入力フィールドに打ち込んだテキストが他の要素の表示に反映される

図004

コード002■アプリケーションとコンポーネントのモジュール

app.module.ts

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule}   from '@angular/forms';
import {AppComponent} from './app.component';
@NgModule({
	imports: [
		BrowserModule,
		FormsModule
	],
	declarations: [AppComponent],
	bootstrap: [AppComponent]
})
export class AppModule {}

app.component.ts

import {Component} from '@angular/core';
export class Heroine {
	id: number;
	name: string;
}
@Component({
	selector: 'my-app',
	template: `
		<h1>{{title}}</h1>
		<h2>{{heroine.name}}の情報</h2>
		<div><label>番号: </label>{{heroine.id}}</div>
		<div>
			<label>名前: </label>
			<input [(ngModel)]="heroine.name" placeholder="名前">
		</div>
		`
})
export class AppComponent {
	title = 'ヒロイン一覧';
	heroine: Heroine = {
		id: 1,
		name: 'シータ'
	};
}


作成者: 野中文雄
更新日: 2017年6月18日 06「編集されたテキストをコンポーネントに反映する」に「NgModule導入について」の参照を追加。
作成日: 2017年5月31日


Copyright © 2001-2017 Fumio Nonaka.  All rights reserved.