Angular7 で Web アプリを作ろう - mat-menu
今日すること
こんにちは、ふるてつです。
今回のテーマもAngular Material
で、<mat-menu>
のお話です。
以前わたしがbootstrap
で作っていたメニューと同じものをmaterial
で作ろうと思います。
メニューは上記のような感じです(緑色の部分です)
mat-menu関連のリファレンスについて
リファレンスはこちらです。https://material.angular.io/components/menu/overview
リファレンスを参考にして作っていきます。
わたしの場合はヘッダー用のコンポーネントを作っていて、その中にまず<mat-toolbar>
を配置しています。
そしてその中に<mat-menu>
やmat-button
を動的に入れています。
サインアウトなど必ず表示するアイコンなどは固定で配置します。
ヘッダー用のコンポーネントについて
まずヘッダーのhtml
ですが、下記のようになります。
header.component.html
<div *ngIf="this.router.url!=='/signIn'">
<mat-toolbar class="toolbar mat-elevation-z8">
<mat-toolbar-row class="toolbar">
<button mat-icon-button (click)="onToggleSidenav()">
<mat-icon>menu</mat-icon>
</button>
<button mat-button routerLink="/account-setting" class="btnMenu">
<div class="systemName">Sanrokumaru</div>
</button>
<div class="toolBarMenu">
<ng-container *ngFor="let item of availableMenuListDtoLists">
<button mat-button [matMenuTriggerFor]="appMenu" class="btnMenu">
<div class="btnMenu">{{ item.propertyId | translate }}</div>
</button>
<mat-menu #appMenu="matMenu">
<ng-container *ngFor="let subitem of item.availableMenuDto">
<button mat-menu-item routerLink="/{{subitem.apiName}}">
{{ subitem.propertyId | translate }}
</button>
</ng-container>
</mat-menu>
</ng-container>
</div>
<button mat-button routerLink="/account-setting" class="btnAccount">
<mat-icon>account_circle</mat-icon>
</button>
<button mat-button routerLink="/account-setting" class="btnSignOut">
<mat-icon>exit_to_app</mat-icon>
</button>
</mat-toolbar-row>
</mat-toolbar>
</div>
順に<mat-icon>menu</mat-icon>
はまずsidenav
表示用のメニューアイコンです。
(ただし画面サイズが大きい時は表示されません)
次に<div class="systemName">Sanrokumaru</div>
はシステム名の部分。
そして<ng-container *ngFor="let item of availableMenuListDtoLists">
のところがメニューを動的に作る箇所です。
さらに下の<ng-container *ngFor="let subitem of item.availableMenuDto">
のところはサブメニューを作る箇所で、メニューに対してネストして繰り返しています。
残りの<mat-icon>account_circle</mat-icon>
と<mat-icon>exit_to_app</mat-icon>
がそれぞれアカウントの設定と、サインアウトボタンです。
次にts
ファイルの内容を書きます。
header.component.ts
の内容
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Router } from '@angular/router';
import { AccountService } from 'src/app/service/common/account/account.service';
import { AvailableMenuListDto } from 'src/app/entity/dto/available-menu-list-dto';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
// 親コンポーネントとの連係
@Output() public sidenavToggle = new EventEmitter();
// メニュー
public availableMenuListDtoLists: AvailableMenuListDto[];
constructor(
private accountService: AccountService,
public router: Router
) { }
ngOnInit() {
// メニューを取得する。
this.getAvailableMenu();
}
/**
* メニューを取得する。
*/
private getAvailableMenu(): void {
this.accountService.getAvailableMenu()
.subscribe(availableMenuListDtoLists => this.availableMenuListDtoLists = availableMenuListDtoLists);
}
/**
* イベントを発生させる。
*/
public onToggleSidenav = () => {
this.sidenavToggle.emit();
}
}
public availableMenuListDtoLists: AvailableMenuListDto[];
がサーバから取得したメニューの内容を格納する変数です。
これは初期表示時にgetAvailableMenu();
で取得します。
以前sidenav
で使用したものと同じ変数を使用します。https://tetsufuru.hatenablog.com/entry/2019/05/07/212627
public onToggleSidenav = () => {
の周辺はsidenav
を関連のメソッドです。
レスポンシブ対応
以前作ったsidenav
だけで十分役に立つので、あえてメニューはなくても良いかなと思いましたが一旦、bootstrap
のように画面サイズが小さい時はsidevan
のみを表示しPCなどサイズが大きい時はメニューのみを表示するように切り替えました。
そのあたりの切り替えはわたしはMedia Queries
でおこなっています。
header.component.css
の内容(Media Queries
の部分のみ抜粋)
/* Tablet or PC */
@media only screen and (min-width: 641px) {
.mat-icon-button {
display: none;
}
}
/* SmartPhone */
@media screen and (max-width: 640px) {
.toolBarMenu {
display: none;
}
}
640px以下の時はメニューが表示されないようにして、641px以上の時はsidenav
が表示されないようにしています。
動かしてみる
では動かしてみます。
下のように動的に作った部分やそのサブメニューも出るようになりました。
画面サイズが小さい場合は下記のようにメニューアイコンに切り替わります。
最後にsidenav
をクリックすると下記のようにサブメニューが表示されました。
今日の感想
今日は以前書いたsidenav
の続きになりますが、mat-menu
を表示する方法でした。
今回はそれほど苦労はしませんでした、sidenav
で少し慣れていたからと思います。
せっかくマテリアルで作っているので、わざわざbootstrap
と同じようなメニュー切替にする必要はなかったのですが、
せっかくsidenab
とmat-menu
の両方を作ったので、一旦はこのまま使ってみようと思います。
では、今日もお疲れ様でした。