[Angular] mat-selection-list & ngForでcheckboxをリスト表示~選択値を配列として取得

  • Angular Materialを用いたUIの実装について、初級者向けに以下を解説します
    • チェックボックス型の選択項目をリスト表示
    • 選択値を配列にまとめて格納するロジック
  • 使いどころ
    • 外部サービスやDBに対するリクエストに含めるパラメータを選択値に応じて変化させる
    • 設定ページに良く使います
画面イメージ

1. 基礎知識

1.1. Angular Material

  • Angular Material

    • メニューやツールバー、ボタン、チェックボックスなどの良く使う部品を提供してくれるAngular公式のUIフレームワーク
    • 基本的に画面は0から作らずにMaterialを組み合わせて作ります
    • まだ導入していなれけば以下を実行すると使えるようになります
      • 聞かれることは全部Yesで問題ないです
        1
        ng add @angular/material
  • mat-selection-list

    • checkbox付きのリストを表示するMaterial
    • 今回はこれを使います (詳細は後述)

2. 実装

  • コンポーネント(sample-component)を例に解説します
    • sample-component.html
      • Angular Materialを活用したUI
    • sample-component.ts
      • データの宣言、データ加工機能

2.1. sample-component.html

  • まずAngular Materialを使って画面を作ります

  • 実装例

    • mat-selection-list要素の中にmat-list-option要素を並べます
    • 後でそれぞれ丁寧に解説します
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <!--選択リスト-->
      <mat-selection-list *ngFor="let item of Data; index as i">
      <ng-container>
      <mat-list-option
      [(selected)]="item.selected"
      [value]="item.value"><!--こっちに書いても発火しない(selectionChange)="checkRegion(i)"--->
      {{item.value}}<!--{{item[i].value}}--->
      </mat-list-option>
      </ng-container>
      </mat-selection-list>

      <br>
      <!--外へリクエストを送るボタン-->
      <button mat-raised-button (click)="submit()">Submit</button>

2.1.1. mat-selection-listとmat-list-optionについて

  • 書式

    • mat-list-optionが選択肢の単位
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <mat-selection-list>

      <mat-list-option
      [(selected)]="item.selected"
      [value]="item.value"><!--こっちに書いても発火しない(selectionChange)="checkRegion(i)"--->
      {{item.value}}<!--{{item[i].value}}--->
      </mat-list-option>

      </mat-selection-list>
  • mat-list-optionの属性値

    • selected
      • checkboxの状態を示す
        • true or false
    • value
      • 要素が持つ値
        1
        2
        3
        <mat-list-option [(selected)]="item.selected" [value]="item.value">
        {{item.value}}
        </mat-list-option>
  • mat-selection-listの属性値

    • (selectionChange)イベント
      • checkされた際に発火するイベント
      • 以下の例では何かが選択される度に”checkRegion()”というメソッドが実行される
        1
        <mat-selection-list (selectionChange)="checkRegion()">
    • mat-list-option側に書いても動かないので注意

2.1.2. *ngFor=”let item of regionsData; index as i”

  • ngFor

    • 構造型ディレクティブと呼ばれるもの
    • ある配列型のデータを元に、ngForを属性値として設定した要素で挟まれた部分をループ表示する
    • 以下をイメージしてください
      1
      2
      3
      <div *ngFor="..<参照するデータを定義(ループの中で使用する)>..">
      <!--ここに書かれた内容をループ表示--->
      </div>
    • HTMLで何行も大量にべた書きする必要がある様な項目を
    • 参照したデータ配列を元に、取り出した変数を変えながら楽に表示できる。すっきりかけるというのがポイント
  • let item of Data;

    • 書式

      1
      let <ループ内での変数名> of <参照するデータ配列>;
    • 意味

      • Data配列をループの中ではitemという名称で扱います
      • 配列から一要素づつ抜き出して、ループ内での変数itemとして使います
    • 使用イメージ

      • tsでデータを定義
        1
        Data =[Apple, Orange, Pinapple]
      • html
        1
        2
        3
        <div *ngFor="let item of Data">
        {{item}} <!--Dataの中身(Apple, Orange, Pinapple)を順に表示-->
        </div>
    • 参照するデータ

      • 上の例で分かるようにts側(sample-component.ts)で配列を定義する必要があります
        • 後で解説します
      • ts側で定義するので外部から取得した動的なデータを元にすることも可能
  • *ngFor=”let item of Data; index as i”

    • Dataに含まれる配列を変数itemとして一つづつ取り出しながらループで表示する
    • 配列のカウントをiで行う
  • ng-container

    • これで囲んだ要素はセットでngForでループする対象にできる
      • 複数の要素を纏めてループする場合にはよく使います
        1
        2
        3
        4
        5
        6
        <div *ngFor="..<参照するデータを定義(ループの中で使用する)>..">
        <ng-container>
        <div> XXXX </div>
        <div> XXXX </div>
        </ng-container>
        </div>

2.1.3. index as i

  • ループが何週目か?をiで定義可能
  • ”0から始まる”ので注意
  • 使用イメージ
    • 実装
      1
      2
      3
      <div *ngFor="let item of Data">
      {{i+1}}番目: {{item}}
      </div>
    • 表示
      1
      2
      3
      1番目: Apple
      2番目: Orange
      3番目: Pinapple

2.2. sample-component.ts

  • ts側には以下を書きます
    • ngForで使うデータソース
    • 選択値を取得するロジック

2.2.1. データソースの準備

  • ngForで参照するデータを以下のように定義します
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 選択肢として表示するregionデータをハッシュで管理
Data = [ // 個々のselectedプロパティでチェック状態を保持
{ value: 'us-east-1', selected: false},
{ value: 'us-east-2', selected: false},
{ value: 'us-west-1', selected: false},
{ value: 'us-west-2', selected: false},
{ value: 'ca-central-1', selected: false},
{ value: 'eu-central-1', selected: false},
{ value: 'eu-west-1', selected: false},
{ value: 'eu-west-2', selected: false},
{ value: 'eu-west-3', selected: false},
{ value: 'eu-north-1', selected: false},
{ value: 'ap-northeast-1', selected: true}, // 初めからcheck=true
{ value: 'ap-northeast-2', selected: false},
{ value: 'ap-northeast-3', selected: false},
{ value: 'ap-southeast-1', selected: false},
{ value: 'ap-southeast-2', selected: false},
{ value: 'ap-south-1', selected: false},
{ value: 'me-south-1', selected: false},
{ value: 'sa-east-1', selected: false},
];
  • 使い方
    • ngForでこの配列から一つづつ呼び出す単位は以下です
      1
      { value: 'us-east-1', selected: false}
    • つまりそのループの中で us-east-1 を示すには以下のように書きます
      1
      2
      3
      <div *ngFor="let item of Data">
      {{item.value}}
      </div>

2.2.2. 双方向バインドによる状態値(selected)の変更

  • これを用いるとパラメータの変化を伝えることができます
  • Angularにおける双方向バインド
    • 片方の変数の変化を
      1
      [(変数)]=変数
  • 今回の使い方
    • ユーザがcheckした際にselectedの値が変わります
    • item.selected=tsで定義したハッシュの該当箇所の選択値が変更されます
      • 後はts側でitem.selectedの値を使って機能を書けます
        1
        2
        <mat-list-option
        [(selected)]="item.selected"

2.2.3. 選択値の取得

  • メソッドを用意して任意のタイミングで呼び出します
    • ハッシュ値全体からfilter()とmap()を使って選択値を取り出します
      1
      2
      3
      4
      5
      6
      7
      8
      9
      // チェックされたリージョンを判別して配列を作成して返す
      makeCheckList() {

      let checkList = [];
      // selectedからチェック状態を確認→配列に選択値を格納
      return checkList = this.Data // Data=ハッシュ値
      .filter((d) => d.selected) // checkされているものに絞る
      .map((d) => d.value); // checkされているリージョン名を取得
      }

2.2.4. 選択値を用いた外部へのリクエスト

  • 外部と通信する機能はServiceに書きましょう

    • Serviceを呼び出す際に、
  • 機能連携イメージ

    • ボタンの(click)イベント

    • (click)=”submit()”と定めていた、submit()メソッドが発火

    • 選択値を取得

    • 外部連携Serviceを呼び出す

      • この際に引数として、取得した選択値を渡す
    • Service内での外部リクエスト

      • この際に引数として渡した選択値を使う
1
2
3
4
5
6
7
8
submit() {

// チェックされたリージョンリストを取得
const REGIONS = this.makeCheckList();

// 外部へリクエストするサービスの呼び出し
let responseData = this.getService(REGIONS);
}

後書き

今回は以上です。このようなロジックを作るシーンは結構あると思います。
短時間でぱっと作って機能面にかける時間を増やしましょう。

関連記事

[Angular] map() & filter() & mat-checkboxを使って選択値を配列に格納するロジック

  • 複数のチェックボックスの中で選択項目を判別して、それぞれの固有値を配列に格納するロジックの作り方を解説します。
    • 以下のSample画面で言うと、チェックされたJapanの値を配列に格納します
  • 使いどころ
    • checkした項目に応じて外部サービスに対するリクエストに含めるパラメータを変化させる
画面イメージ

基礎知識

  • すぐに実装に取り掛かりたい方は飛ばしてOK

Angularにおけるデータ加工ロジック

  • 基本的にmapやfilterを利用する
    • アンチパターン
      • 何でもfor,if文
    • 何故か?
      • mapは並列処理
        • for文と比較して処理が高速
      • 書式がシンプル
        • 開発期間短縮
        • 可読性向上
        • リファクタリングの簡略化

map

  • map()
    • 処理
      • 引数として与えられた配列の各要素に対して、一つづつ関数を実行
      • カウンタが不要な配列向けのfor文というイメージでOKです
    • 返り値
      • 実行結果から新たな配列を生成

filter

  • filter()
    • 処理
      • 引数として与えられたテスト関数を各配列要素に対して実行
      • 配列向けのif文というイメージでOKです
    • 返り値
      • テスト関数の条件に合格した要素からなる新しい配列を生成
  • 利用イメージ

    1
    2
    3
    4
    5
    6
    7
    8
    // 配列を宣言
    const array = ['AA', 'BB', 'CC', 'DDD', 'EEEE', 'FFFFF'];

    // 配列arrayを引数として、条件式3文字以上の要素を抽出して、配列として返す
    const result = array.filter(array => array.length >= 3);

    console.log(result);
    // output: Array ["DDD", "EEEE", "FFFFF"]
  • 構文は以下

    • value: 配列の要素
    • index: インデックス
    • array: 操作中の配列本体
      1
      var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
  • 他の利用例は以下を参考にどうぞ

実装

ざっくりイメージは以下

  • tsファイル
    • 役割
      • データ構造の定義
      • 判別ロジック
        • (click)イベントで発火
  • html
    • 役割
      • checkboxの表示
      • tsファイルで指定したデータの参照
      • (click)イベントの指定

データ構造の定義

  • 配列dataに以下のようにデータ構造を定義します
    • valueを読み替えて使用してください
  • sample.component.ts
    1
    2
    3
    4
    5
    6
    7
    // dataにcheckboxの値とチェック状態の初期値:selectedを定義
    data = [
    { value: 'Japan', selected: false}, // 初期値 true
    { value: 'America', selected: false},
    { value: 'China', selected: false},
    { value: 'England', selected: false},
    ]

状態判別ロジック

  • 状態を判別するmethodを宣言します
  • ざっくりイメージ
    • filter()
      • data全体からチェック済みのもの(Selected=true)に絞る
    • map()
      • 残ったdataのvalueで配列を生成
    • Listに格納
  • sample.component.ts
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    makeList() {
    // 格納先の配列を宣言
    let countryList = [];

    // selectedからチェック状態を確認して、配列にを格納していく
    countryList = this.data
    .filter((d) => d.selected) // checkされているものに絞る
    .map((d) => d.value); // valueを取得
    return countryList; //
    }

配列データを引数としてリクエストを送る際の例

  • 選択値を使って外部サービスへリクエストを行うケースを想定
    • service側で受け取った変数に応じた分岐処理を用意しておくイメージです
  • sample.component.ts
    1
    2
    3
    4
    5
    6
    7
    submit(){
    // 選択値を受け取る
    const selectedCountries = this.makeList();

    // 任意のServiceのメソッドを実行
    getService.requesrMethod(selectedCountries)
    }

tsに定めたdataに応じてチェックボックスのリストを表示するHTML

基礎知識

  • ngFor

    • 指定した配列をループ表示させる構造ディレクティブ
      • べた書きするよりもすっきり書けます
      • 今回は以下のように配列:dataをループさせています
        • ngForのループの中でdataを変数itemとして使うという意味
          1
          *ngFor= "let item of data; index as i"
    • ng-container x *ngFor
      • 組み合わせると、ng-containerの中の要素全てを一まとまりでループさせることが可能です
  • mat-checkbox

    • 通常のcheckboxはイケてないのでAngular Materialを使います
      • 通常のcheckboxを使う場合は”mat-checkbox”を”input”に読み替えてください
  • Angularのフォーム

    • 二種類あります
      • テンプレート駆動型
        • 書式がシンプルで手軽に実装可能であるため採用
        • #myForm=”ngForm” と設定することでこちらになる
      • モデル駆動型 (Reactive駆動型)
        • コードは冗長になりがち
        • より柔軟に複雑な要件を満たせる

          記載例

  • sample.component.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div>Choose Country</div>
    <!---formで選択したリージョンの情報を纏めてからリクエスト------>
    <form #myForm="ngForm" (ngSubmit)="submit()">

    <!---定義した配列dataをngForでループ表示 要素をiでカウント---->
    <ng-container *ngFor= "let item of data; index as i" >

    <!---inputで通常のCheckboxに変えてもOK--->
    <mat-checkbox type="checkbox" name = "country{{i}}"
    [(ngModel)]="data[i].selected"
    [value]="item.value"
    (change)="checkCountry(i)"
    >{{data[i].value}}</mat-checkbox>

    </ng-container>

    <!---チェックボックスから得たデータを纏めてリクエストするボタン--->
    <button mat-raised-button color="primary">Get Data</button>
    <!--(ngSubmit)=で設定されたsubmit()が実行される-->
    </form>

画面で確認

  • 以下のように表示されます
画面イメージ

おまけ: for文で書く場合

  • for文でも判別ロジック書いたので参考までにどうぞ
    • だいぶ冗長になってしまいます
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 格納先を宣言
let regionList = [];

// for文で書く場合
var num=0;
for ( let c = 0; c <= this.data.length - 1 ; c++) {
if (this.data[c].selected) { // Checkされているか判定 trueなら実行
// 配列に要素を追加 .push()
countryList.push(this.data[c].value); // リージョン名を格納
console.log(countryList[num] + ' checked'); // デバッグ用
num++;
} else {
console.log('Not Check'); // デバッグ用
}
}
console.log(countryList);
@EventEmitter @Input @Output @ViewChild ACM AMP API Gateway AR AR.js AR.js Studio AWS AWS Amplify AWS Budgets AWS Cost Explorer AWS SDK for JavaScript AddThis Adobe XD Alexa Amazon CloudWatch Amazon Honycode Amazon SNS Android Angular Angular Material AngularFire AppSync Augury C CDN CI/CD Cloud Craft Cloud9 CloudFormation CloudFront CloudTrail Cognito Cost Anomaly Detection Cubase ai Cubasis LE DTM Disqus DynamoDB Elgato HD 60S Firebase Firebase Hosting Former2 Github Github Actions Github.com GithubEnterprise GithubPages Google Chrome Google Cloud Shell GraphQL Hexo Hosting IAM Ionic JSON JavaScript LadioCast Logging LowCode MFA MS Authentication MacBook Pro 16 Mind Node NETDUETTO Netflix Party Netlify Network NoCode Observable PO PdM Promise RPA ReactiveForm Recognition Route53 S3 SAM(Serverless Application Model) SAR SSL SYNCROOM Schematics ScrumInc Serverless Service Siri Sitemap Spark AR Steinberg UR44C Teams Touch Cast Studio Treetable TypeScript UI UI Bakery WAF WAFv2 WEB Page Dev WEB会議 WebAR WebSocketAPI Webhook Windows Power Automate Wireshark aot async/await aws config cloud9 display.land draw.io e2e test filter() forkJoin() google search console hexo-generator-amp iOS iPad Pro iPhone icarus map() mat input mat tree mat-checkbox mat-input mat-selection-list mmhmm ngFor plantUML popIn Aladdin2 then() vscode ”global is not defined” らくがきAR アジャイル アジャイル開発 クロスプラットフォーム ショートカット スクラム スクラム開発 テレワーク ファイル操作 ブラウザ型IDE プロダクトオーナー プロダクトマネージャー プロトタイピング リモートセッション 共同開発 双方向データバインディング 待ち合わせ処理 認定スクラムマスター 静的WEB Hosting 静的WEBサイトHosting
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×