[小ネタ]mat-dividerをngForしたとき最後の要素だけ非表示にする方法

2020.01.13

どうも!大阪オフィスの西村祐二です。

要素を区切る際にAngular Materialmat-dividerを使うことがあります。

mat-dividerを含めて要素をngForでループさせるとき、mat-dividerを最後の要素のときだけ非表示にしたいときがありましたので、その方法をまとめておきたいと思います。

結論

ngForでは最後のループのときをlastとして取得できるので、その情報を使ってngIfを設定することによって実現します。

<mat-list-item *ngFor="let item of items; last as last">
.
.
.
<mat-divider *ngIf="!last"></mat-divider>
.
.

試してみた

環境

Angular CLI: 8.3.22
Node: 12.13.0
OS: darwin x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.803.22
@angular-devkit/build-angular     0.803.22
@angular-devkit/build-optimizer   0.803.22
@angular-devkit/build-webpack     0.803.22
@angular-devkit/core              8.3.22
@angular-devkit/schematics        8.3.22
@angular/cdk                      8.2.3
@angular/cli                      8.3.22
@angular/material                 8.2.3
@ngtools/webpack                  8.3.22
@schematics/angular               8.3.22
@schematics/update                0.803.22
rxjs                              6.4.0
typescript                        3.5.3
webpack                           4.39.2

セットアップ

Angular CLIを使って、雛形ファイルを作り、Angular Materialをインストールしておきます。

❯ ng new divider --style=scss --routing
❯ cd divider/
❯ ng add @angular/material
Installing packages for tooling via npm.
Installed packages for tooling via npm.
? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink        [ Preview: https://material.angular.io?theme=indigo-pink ]
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes

サンプル実装

必要なMaterialのモジュールをインポートします。

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { MatDividerModule } from '@angular/material/divider';
import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatDividerModule,
    MatListModule,
    MatIconModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

表示するデータを定義します。

src/app/app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  items = [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }];
}

ngIflastを使ったときと使わなかったときの挙動を比較するために下記のような実装します。

<mat-list>
  <h3 mat-subheader>最後のmat-divider表示</h3>
  <mat-list-item *ngFor="let item of items">
    <h4 mat-line>{{ item.name }}</h4>
    <mat-divider></mat-divider>
  </mat-list-item>

  <h3 mat-subheader>最後のmat-divider非表示</h3>
  <mat-list-item *ngFor="let item of items; last as last">
    <h4 mat-line>{{ item.name }}</h4>
    <mat-divider *ngIf="!last"></mat-divider>
  </mat-list-item>
</mat-list>

動作確認

ローカル実行して、画面を確認します。

$ ng serve

下記のような、最後の要素だけmat-dividerが非表示になっていることがわかります。

さいごに

mat-dividerをngForしたとき最後の要素だけ非表示にする方法をご紹介しました。

自分の中の知識の整理と記憶定着のサポートとして、ちょっとした小ネタですが細かい情報もアウトプットして行こうと思います。