🐣

Angularの公式チュートリアルをやっていく その14 - Add search functionality

2023/06/17に公開

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

今回やるのは、↓の部分です。

https://angular.jp/tutorial/first-app/first-app-lesson-13


検索機能を追加する

アプリケーションに検索機能を追加します。
検索時には、マッチングした家のみを表示できるようになります。

検索済みデータのフィールドを追加する

検索後の家データのリストを格納するフィールドfilteredLocationListを追加します。

検索ボックスが空の場合は全ての家データが格納されますが、検索を行った場合は、検索にマッチングする家データのみが格納されます。

また、コンストラクタでthis.filteredLocationList = this.housingLocationList;を設定することで、filteredLocationListの初期データはすべての家データが格納されることになります。

下のようにhome.component.tsを変更します。

home.component.ts
  import { Component, inject } from '@angular/core';
  import { CommonModule } from '@angular/common';
  import { HousingLocationComponent } from '../housing-location/housing-location.component';
  import { HousingLocation } from '../housinglocation';
  import { HousingService } from '../housing.service';
  
  @Component({
    selector: 'app-home',
    standalone: true,
    imports: [CommonModule, HousingLocationComponent],
    template: `
      <section>
        <form>
          <input type="text" placeholder="Filter by city" />
          <button class="primary" type="button">Search</button>
        </form>
      </section>
      <section class="results">
        <app-housing-location
          *ngFor="let housingLocation of housingLocationList"
          [housingLocation]="housingLocation"
        ></app-housing-location>
      </section>
    `,
    styleUrls: ['./home.component.css'],
  })
  export class HomeComponent {
    housingLocationList: HousingLocation[] = [];
+   filteredLocationList: HousingLocation[] = [];
    housingService: HousingService = inject(HousingService);
  
    constructor() {
      this.housingLocationList = this.housingService.getAllHousingLocations();
+     this.filteredLocationList = this.housingLocationList;
    }
  }


アプリケーションを再ビルドしてコードに間違いがないか確認します。

ng serve



検索フォームのテンプレートを更新する

今まで検索フォームはあったものの、実際には何も機能が無いただの張りぼてだったため、それを検索フォームとしてキチンと機能するように実装していきます。

下のようにhome.component.tsを変更します。

home.component.ts
  import { Component, inject } from '@angular/core';
  import { CommonModule } from '@angular/common';
  import { HousingLocationComponent } from '../housing-location/housing-location.component';
  import { HousingLocation } from '../housinglocation';
  import { HousingService } from '../housing.service';
  
  @Component({
    selector: 'app-home',
    standalone: true,
    imports: [CommonModule, HousingLocationComponent],
    template: `
      <section>
        <form>
-         <input type="text" placeholder="Filter by city" />
+         <input type="text" placeholder="Filter by city" #filter>
-         <button class="primary" type="button">Search</button>
+         <button class="primary" type="button" (click)="filterResults(filter.value)">Search</button>
        </form>
      </section>
      <section class="results">
        <app-housing-location
-         *ngFor="let housingLocation of housingLocationList"
+         *ngFor="let housingLocation of filteredLocationList"
          [housingLocation]="housingLocation"
        ></app-housing-location>
      </section>
    `,
    styleUrls: ['./home.component.css'],
  })
  export class HomeComponent {
    housingLocationList: HousingLocation[] = [];
    filteredLocationList: HousingLocation[] = [];
    housingService: HousingService = inject(HousingService);
  
    constructor() {
      this.housingLocationList = this.housingService.getAllHousingLocations();
      this.filteredLocationList = this.housingLocationList;
    }
    
+   filterResults(text: string) {
+     if (!text) {
+       this.filteredLocationList = this.housingLocationList;
+     }

+     this.filteredLocationList = this.housingLocationList.filter(
+       housingLocation => housingLocation?.city.toLowerCase().includes(text.toLowerCase())
+     );
+   }
  }


アプリケーションを再ビルドしてコードに間違いがないか確認します。

ng serve



検索フォームのシステムの動き

<input>タグには#filterのテンプレート変数が設定されています。

home.component.ts
<input type="text" placeholder="Filter by city" #filter>


こうすることで#filterは、このinput要素への参照を保持します。この参照を使用すると、その要素のプロパティ(例えば、ユーザーが入力した値)にアクセスしたり、その要素に対してメソッド(例えば、フォーカスを設定する)を呼び出すことができます。

そして下のボタンがクリックされたときにfilterテンプレート変数が参照する値を利用することができるようになります。

つまり、クリックした時にfilterResultsメソッドの引数にinputの値を入れた状態で実行することができます。

home.component.ts
<button class="primary" type="button" (click)="filterResults(filter.value)">Search</button>  //  filter.valueには#filterで紐づけられたinputのvalue属性の値が格納されている


次にfilterResultsメソッドが実行されたことにより、下のコードのfilter関数によってマッチングしたデータだけがfilteredLocationList変数に配列として格納されます。

また、下のように*ngForでループする配列がfilteredLocationListに変更されているため、検索でマッチングした家データのみが画面に表示されます。

home.component.ts
<app-housing-location
  *ngFor="let housingLocation of filteredLocationList"
  [housingLocation]="housingLocation"
></app-housing-location>


アプリの検索フォームをテストする

では実際に検索を行って、ちゃんと機能するか確かめましょう。

検索フォームに「chicago」と入力してSearchボタンをクリックします。

すると、検索機能が働いて住所が「chicago」だけのものが表示されるようになりました。


これにてAdd search functionalityは完了です。


← 前へ Angularの公式チュートリアルをやっていく その13 - Integrate Angular forms
→ 次へ Angularの公式チュートリアルをやっていく その15 - Add HTTP communication

Discussion