やりたいこと
🎅 ダイアログコンポーネントに一意のURLを持たせ、そのURLにアクセスした時にダイアログを自動で開きたい
🎅 ダイアログページをURL共有できるようにしたい
🎅 ブラウザをリロードしてもダイアログが開いた状態を保ちたい
例えば
http://myurl?id=123
へアクセス
→ IDが123のデータをAPIリクエストし、その結果を載せたダイアログコンポーネントを開く
(ダイアログを使わない方が楽にできる気がしますが、
アプリケーション内の操作方法を統一したいなどの諸事情により今回はこのような実装にしました)
環境
- Angular 13
- Angular Material
早速つくっていきます
1. ダイアログの親コンポーネントのngOnInitのタイミングでダイアログを開く
@Component({
selector: 'app-my-table',
templateUrl: './my-table.component.html',
styleUrls: ['./my-table.component.sass'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyTableComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private router: Router,
public dialog: MatDialog,
private http: HttpClient
) {}
ngOnInit(): void {
this.route.queryParams
.pipe(
// 🎅クエリパラメータに特定のパラメータ(今回はid)が含まれるときのみダイアログを開く
filter(({ id }) => id),
// 🎅クエリパラメータから取得したIDでデータを取得、ダイアログコンポーネントに渡す
switchMap(({ id }) => this.http.get<MyData>(`${myURL}/${id}`)),
switchMap((myData) => {
return this.dialog
.open(MyDialogComponent, {
// 🎅今回はダイアログを普通のページっぽく見せたいのでheight, widthを100%にして、背景を見えないようにする
data: myData,
height: '100%',
width: '100%',
disableClose: true,
})
// 🎅ダイアログを閉じた後は任意のページに遷移させる
.afterClosed()
.pipe(
tap(() => {
this.router.navigate(['/myURL']);
})
);
})
)
.subscribe();
}
}
2. ダイアログが開くまでの間スピナーを表示する
ダイアログに表示するデータが返ってくるまでに時間がかかる場合、overlay+spinnerを使ってユーザの操作を制限
@Component({
selector: 'app-my-table',
templateUrl: './my-table.component.html',
styleUrls: ['./my-table.component.sass'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyTableComponent implements OnInit {
// 🎅追加
overlayRef = this.overlay.create({
hasBackdrop: true,
positionStrategy: this.overlay.position().global()![Something went wrong]()
.centerHorizontally().centerVertically(),
});
constructor(
private route: ActivatedRoute,
private router: Router,
public dialog: MatDialog,
private overlay: Overlay, // 🎅追加
private http: HttpClient
) {}
ngOnInit(): void {
this.route.queryParams
.pipe(
filter(({ id }) => id),
switchMap(({ id }) => {
// 🎅APIからのリスポンスが返ってくるまでの間スピナーを表示
this.overlayRef.attach(new ComponentPortal(MatSpinner));
return this.http.get<MyData>(`${myURL}/${id}`);
}),
switchMap((myData) => {
// 🎅スピナーを非表示にしてダイアログを開く
this.overlayRef.detach();
return this.dialog.open()
...
})
)
.subscribe();
}
}
最終結果
URLに?id=123
を追加すると、ダイアログコンポーネントが開いてくれました!
(※URL部分がわかりやすいように一部を切り取っているためスピナーの位置がずれています)