Angularの公式チュートリアルをやっていく その13 - Integrate Angular forms
Angularの公式チュートリアル「はじめての Angularアプリ」を進めていきます。
一覧
Angularの公式チュートリアルをやっていく その1 - Introduction
Angularの公式チュートリアルをやっていく その2 - Hello world
Angularの公式チュートリアルをやっていく その3 - Create home component
Angularの公式チュートリアルをやっていく その4 - Create housing location component
Angularの公式チュートリアルをやっていく その5 - Create an interface
Angularの公式チュートリアルをやっていく その6 - Add inputs to components
Angularの公式チュートリアルをやっていく その7 - Add property binding to components
Angularの公式チュートリアルをやっていく その8 - Add dynamic values to templates
Angularの公式チュートリアルをやっていく その9 - Use *ngFor in templates
Angularの公式チュートリアルをやっていく その10 - Angular services
Angularの公式チュートリアルをやっていく その11 - Add routing
Angularの公式チュートリアルをやっていく その12 - Customize the details page
Angularの公式チュートリアルをやっていく その13 - Integrate Angular forms
Angularの公式チュートリアルをやっていく その14 - Add search functionality
Angularの公式チュートリアルをやっていく その15 - Add HTTP communication
今回やるのは、↓の部分です。
入力フォームを追加する
このセクションでは入力フォームを作成します。
入力されたデータをどうやって取得するのか、やっていきます。
HousingServiceにデータ受け取りメソッドを追加する
HousingService
にデータを受け取るメソッドを追加します。
今回はconsole.log
で受け取ったデータを出力するだけですが、本来は受け取ったデータをバリデーションしたり、バックエンドに送信したりするロジックを実装したりすることになります。
下のようにhousing.service.ts
を変更します。
import { Injectable } from '@angular/core';
import { HousingLocation } from './housinglocation';
@Injectable({
providedIn: 'root',
})
export class HousingService {
housingLocationList: HousingLocation[] = [
{
id: 0,
name: 'Acme Fresh Start Housing',
city: 'Chicago',
state: 'IL',
photo: '/assets/bernard-hermant-CLKGGwIBTaY-unsplash.jpg',
availableUnits: 4,
wifi: true,
laundry: true,
},
{
id: 1,
name: 'A113 Transitional Housing',
city: 'Santa Monica',
state: 'CA',
photo: '/assets/brandon-griggs-wR11KBaB86U-unsplash.jpg',
availableUnits: 0,
wifi: false,
laundry: true,
},
{
id: 2,
name: 'Warm Beds Housing Support',
city: 'Juneau',
state: 'AK',
photo: '/assets/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg',
availableUnits: 1,
wifi: false,
laundry: false,
},
{
id: 3,
name: 'Homesteady Housing',
city: 'Chicago',
state: 'IL',
photo: '/assets/ian-macdonald-W8z6aiwfi1E-unsplash.jpg',
availableUnits: 1,
wifi: true,
laundry: false,
},
{
id: 4,
name: 'Happy Homes Group',
city: 'Gary',
state: 'IN',
photo: '/assets/krzysztof-hepner-978RAXoXnH4-unsplash.jpg',
availableUnits: 1,
wifi: true,
laundry: false,
},
{
id: 5,
name: 'Hopeful Apartment Group',
city: 'Oakland',
state: 'CA',
photo: '/assets/r-architecture-JvQ0Q5IkeMM-unsplash.jpg',
availableUnits: 2,
wifi: true,
laundry: true,
},
{
id: 6,
name: 'Seriously Safe Towns',
city: 'Oakland',
state: 'CA',
photo: '/assets/phil-hearing-IYfp2Ixe9nM-unsplash.jpg',
availableUnits: 5,
wifi: true,
laundry: true,
},
{
id: 7,
name: 'Hopeful Housing Solutions',
city: 'Oakland',
state: 'CA',
photo: '/assets/r-architecture-GGupkreKwxA-unsplash.jpg',
availableUnits: 2,
wifi: true,
laundry: true,
},
{
id: 8,
name: 'Seriously Safe Towns',
city: 'Oakland',
state: 'CA',
photo: '/assets/saru-robert-9rP3mxf8qWI-unsplash.jpg',
availableUnits: 10,
wifi: false,
laundry: false,
},
{
id: 9,
name: 'Capital Safe Towns',
city: 'Portland',
state: 'OR',
photo: '/assets/webaliser-_TPTXZd9mOo-unsplash.jpg',
availableUnits: 6,
wifi: true,
laundry: true,
},
];
constructor() {}
getAllHousingLocations(): HousingLocation[] {
return this.housingLocationList;
}
getHousingLocationById(id: number): HousingLocation | undefined {
return this.housingLocationList.find(
(housingLocation) => housingLocation.id === id
);
}
+ submitApplication(firstName: string, lastName: string, email: string) {
+ console.log(`Homes application received: firstName: ${firstName}, lastName: ${lastName}, email: ${email}.`);
+ }
}
アプリケーションを再ビルドしてコードに間違いがないか確認します。
ng serve
詳細ページにフォーム機能を追加する
詳細ページに、フォーム機能を追加します。
追加するのはフォームの裏側の機能だけで、実際に表示されるテンプレート部分は次の項目で追加されます。
下のようにdetails.component.ts
を変更します。
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
+ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { HousingService } from '../housing.service';
import { HousingLocation } from '../housinglocation';
@Component({
selector: 'app-details',
standalone: true,
- imports: [CommonModule],
+ imports: [
+ CommonModule,
+ ReactiveFormsModule
+ ],
template: `
<article>
<img
class="listing-photo"
[src]="housingLocation?.photo"
alt="Exterior photo of {{ housingLocation?.name }}"
/>
<section class="listing-description">
<h2 class="listing-heading">{{ housingLocation?.name }}</h2>
<p class="listing-location">
{{ housingLocation?.city }}, {{ housingLocation?.state }}
</p>
</section>
<section class="listing-features">
<h2 class="section-heading">About this housing location</h2>
<ul>
<li>Units available: {{ housingLocation?.availableUnits }}</li>
<li>Does this location have wifi: {{ housingLocation?.wifi }}</li>
<li>
Does this location have laundry: {{ housingLocation?.laundry }}
</li>
</ul>
</section>
</article>
`,
styleUrls: ['./details.component.css'],
})
export class DetailsComponent {
route: ActivatedRoute = inject(ActivatedRoute);
housingService = inject(HousingService);
housingLocation: HousingLocation | undefined;
+ applyForm = new FormGroup({
+ firstName: new FormControl(''),
+ lastName: new FormControl(''),
+ email: new FormControl('')
+ });
constructor() {
const housingLocationId = Number(this.route.snapshot.params['id']);
this.housingLocation =
this.housingService.getHousingLocationById(housingLocationId);
}
+ submitApplication() {
+ this.housingService.submitApplication(
+ this.applyForm.value.firstName ?? '',
+ this.applyForm.value.lastName ?? '',
+ this.applyForm.value.email ?? ''
+ );
+ }
}
アプリケーションを再ビルドしてコードに間違いがないか確認します。
ng serve
フォームのマークアップを詳細ページに追加する
実際に表示されるテンプレート部分を追加していきます。
下のようにdetails.component.ts
を変更します。
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { HousingService } from '../housing.service';
import { HousingLocation } from '../housinglocation';
@Component({
selector: 'app-details',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
template: `
<article>
<img
class="listing-photo"
[src]="housingLocation?.photo"
alt="Exterior photo of {{ housingLocation?.name }}"
/>
<section class="listing-description">
<h2 class="listing-heading">{{ housingLocation?.name }}</h2>
<p class="listing-location">
{{ housingLocation?.city }}, {{ housingLocation?.state }}
</p>
</section>
<section class="listing-features">
<h2 class="section-heading">About this housing location</h2>
<ul>
<li>Units available: {{ housingLocation?.availableUnits }}</li>
<li>Does this location have wifi: {{ housingLocation?.wifi }}</li>
<li>
Does this location have laundry: {{ housingLocation?.laundry }}
</li>
</ul>
</section>
+ <section class="listing-apply">
+ <h2 class="section-heading">Apply now to live here</h2>
+ <form [formGroup]="applyForm" (submit)="submitApplication()">
+ <label for="first-name">First Name</label>
+ <input id="first-name" type="text" formControlName="firstName">
+
+ <label for="last-name">Last Name</label>
+ <input id="last-name" type="text" formControlName="lastName">
+
+ <label for="email">Email</label>
+ <input id="email" type="email" formControlName="email">
+ <button type="submit" class="primary">Apply now</button>
+ </form>
+ </section>
</article>
`,
styleUrls: ['./details.component.css'],
})
export class DetailsComponent {
route: ActivatedRoute = inject(ActivatedRoute);
housingService = inject(HousingService);
housingLocation: HousingLocation | undefined;
applyForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
email: new FormControl(''),
});
constructor() {
const housingLocationId = Number(this.route.snapshot.params['id']);
this.housingLocation =
this.housingService.getHousingLocationById(housingLocationId);
}
submitApplication() {
this.housingService.submitApplication(
this.applyForm.value.firstName ?? '',
this.applyForm.value.lastName ?? '',
this.applyForm.value.email ?? ''
);
}
}
追加すると下のように画面になります。
確かにフォームが追加されていますね。
入力フォームのシステムの動き
FormGroup
には、フォームに入力されたデータがリアルタイムで格納されています。
applyForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
email: new FormControl(''),
});
例えば、私がFIRST NAMEの入力場所に画像の様に「Koha」まで入力したら、FormGroup
のfirstName
にも「Koha」までの値が格納されたことになります。
applyForm = new FormGroup({
firstName: new FormControl(''), // Kohaまでが格納される
lastName: new FormControl(''),
email: new FormControl(''),
});
Angularは、FormGroupやFormControlを使用することで、フォームの各フィールドの値を簡単に取得したり、検証ルールを追加したり、特定の状況でフィールドを無効にしたりすることが可能になります。
これらの機能はリアクティブフォームとして知られており、Angularの強力な特徴の一つです。
そして、「Apply now」ボタンをクリックすることによって、(submit)="submitApplication()"
のコードの機能でsubmitApplication()
メソッドが実行され、FormGroup
のデータを引数にしてhousingService.submitApplication
が実行されます。
今回の場合、下記のようにhousingService.submitApplication
にはコンソールにデータを出力するロジックだけが実装されているため、コンソールに入力した文字列が出てくるだけです。
submitApplication(firstName: string, lastName: string, email: string) {
console.log(`Homes application received: firstName: ${firstName}, lastName: ${lastName}, email: ${email}.`);
}
アプリの新しいフォームをテストする
フォームがちゃんと機能するか確かめてみましょう。
フォームにデータを入力して、入力したデータがコンソールに出力されるかテストします。
以下のようにフォームに入力してみます。
そして、「Apply now」ボタンをクリック
おお! しっかりとコンソールに入力した内容が出力されました!
これにてIntegrate Angular formsは完了です。
← 前へ Angularの公式チュートリアルをやっていく その12 - Customize the details page
→ 次へ Angularの公式チュートリアルをやっていく その14 - Add search functionality
Discussion