🐟

[Angular][Material] Sidenavのナビゲーション開閉時にgridster2のグリッドをリサイズさせる

2022/12/21に公開約4,200字

やりたいこと

https://zenn.dev/yusuke_docha/articles/57f52e9d537caf
この記事で作成したgridster2のデモに
https://zenn.dev/yusuke_docha/articles/70a82ffad8e913

の記事で作成したAngularMaterialのsidenavを組み合わせたい。

完成形は下記のようになります。

現状

しかし、下記のようにナビゲーションを開閉したときに、グリッド幅やアイテムがリサイズされないので、見切れてしまいます。

グリッドが全体的に右に押されてしまいます。

そのため、ナビゲーションの開閉の度に、グリッドをリサイズさせるようにします。

解決法

gridster2のAPIであるresizeメソッドを呼び出すようにします。

app.component.html

<mat-drawer-container>
  <button mat-raised-button color="primary" (click)="addItem()" aria-label="icon button with a add icon">
    <mat-icon>add</mat-icon>
  </button>

  **<button mat-flat-button color="accent" (click)="onClick()">
    開閉
  </button>**

  <div>
    現在のinnerWidth: {{innerWidth}}
  </div>

  <gridster #gridster [options]="options" class="gridster-contents">
    <gridster-item [item]="item" *ngFor="let item of dashboard; index as i">
      <div class="draggable-handler">
        (ドラッグ可能域)
      </div>
      <div>
        ドラッグとリサイズが可能です
      </div>
      <div class="delete-button">
        <button mat-fab color="warn" (click)="removeItem(i)" aria-label="icon button with a delete icon">
          <mat-icon>delete</mat-icon>
        </button>
      </div>
    </gridster-item>
  </gridster>

  <!-- <div>フッター</div> -->
  <mat-drawer #drawer mode="side">
    <p>ぽち</p>
    <img
      src="https://material.angular.io/assets/img/examples/shiba2.jpg"
      alt="Photo of a Shiba Inu"
      height="200px"
      width="auto"
    >
  </mat-drawer>
</mat-drawer-container>
  • 開閉ボタンを設置します。

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { GridsterComponent, GridsterConfig, GridsterItem } from 'angular-gridster2';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @ViewChild('drawer') drawer!: MatSidenav;

  **options: GridsterConfig = {};**
  dashboard: Array<GridsterItem> = [];

  private gridCols = 20;
  private gridRows = 20;

  innerWidth = window.innerWidth;

  constructor() {

    // 初期化時のinnerWidthによってグリッド列数を変える
    if (1500 <= window.innerWidth) {
      this.gridCols = 30;
    } else if (1000 <= window.innerWidth) {
      this.gridCols = 13;
    } else {
      this.gridCols = 6;
    };
  }

  ngOnInit(): void {
    this.options = {
      gridType: 'scrollVertical', // 固定縦横比を縦スクロールで対応
      // gridType: 'scrollHorizontal', // 固定縦横比を水平スクロールで対応
      draggable: { // ドラッグ設定
        enabled: true, // ドラッグ許可
        ignoreContent: true, // dragHandleClassのみドラッグイベントを可能にする
        dragHandleClass: 'draggable-handler', // ここで指定したクラスのみドラッグイベントを可能にする
        // delayStart: 500,
      },
      resizable: { // リサイズ設定
        enabled: true, // リサイズを許可する
        // delayStart: 500,
      },
      swap: true, // 入れ替えを許可する
      displayGrid: 'always', // グリッド線を常に表示
      minCols: this.gridCols, // 最小列数
      maxCols: this.gridCols, // 最大列数(minCols以上はドラッグで表示される)
      minRows: this.gridRows, // 最小行数
      maxRows: this.gridRows, // 最大行数(minRows以上はドラッグで表示される)
      maxItemCols: 5, // アイテムの最大列数
      maxItemRows: 5, // アイテムの最大行数
      compactType: 'none', // 整列しない(自由)
      pushItems: true, // リサイズとドラッグでアイテムを押しのける
      mobileBreakpoint: 640, // 画面の幅が640px以下でグリッドを解除しアイテムを1列にする
    };

    this.dashboard = [
      {cols: 3, rows: 4, y: 1, x: 2}, // 初期値 横3マス, 縦4マス,をy1, x2の位置に配置
    ];
  }

  removeItem(index: number): void {
    this.dashboard.splice(index, 1); // index番目を1つ取り除く
  }

  addItem(): void {
    this.dashboard.push({cols: 3, rows: 3, y: 0, x: 0});
  }

  **async onClick() {
    await this.drawer.toggle();
    this.options.api?.resize?.();
  }**

}
  • onClick()メソッド内で、this.drawer.toggle()で開閉の後にthis.options.api?.resize?.()でリサイズを呼び出します。
  • async/awaitで順番を保証します。
  • optinosGridsterConfig型です。

開閉の度にグリッド全体がリサイズされて期待通りの挙動になりました。

参考

https://material.angular.io/components/sidenav/api
https://stackoverflow.com/questions/56489197/resizing-issue-with-mat-side-nav-and-gridster2

Discussion

ログインするとコメントできます