iT邦幫忙

2024 iThome 鐵人賽

DAY 30
0
Modern Web

用 Angular Material 開發應用程式系列 第 30

Day 30 - Portals & Overlay

  • 分享至 

  • xImage
  •  

Portals

在 Angular 應用程式中,我們可以利用 NgTemplateOutlet 或 NgComponentOutlet 來實作動態內容元件。而在 CDK 裡也提供了 Portals 讓我們更容易實作這樣子的需求。

在引用 PortalModule 模組後,先使用 cdkPortalOutlet 來決定動態內容要放在的位置,並繫結型別為 Portal 的屬性。

<div [cdkPortalOutlet]="portal"></div>
selectedPortal: Portal<unkown>;

我們可以在此處放 Template、Component 或 DOM。例如,我們定義了一個 Template,接著在 TypeScript 中,利用這個 Template 建立 TemplatePortal 資料,就可以把它設定到 selectedPortal 來顯示出來。

<ng-template #templateContent>Template Portal</ng-template>
@ViewChild('templatePortal')
templateContent: TemplateRef<unknown>;

private readonly viewContainerRef = inject(ViewContainerRef);
templatePortal: TemplatePortal<any>;

ngAfterViewInit() {
  this.templatePortal = new TemplatePortal(this.templateContent, this.viewContainerRef);
}

如果要傳入外部資料,則在建立實體時傳入第三個參數 ({ name: ‘A’ }),就可以在範本中以 let-name=name 的方式取得。如下面程式,將動態內容元件建立一個 ComponentPortal ,就可以顯示在 cdkPortalOutlet 內。

@Component({ ... })
export class ContentComponent() {}
componentPortal: ComponentPortal<ContentComponent>;

ngAfterViewInit() {
  this.componentPortal = new ComponentPortal(ContentComponent);
}

Overlay

Overlay 是在 Angular Material 彈跳視窗的底層,我們可以利用 Overlay 來實作浮動於主頁面區塊的需求。在實作此種需求前,先使用 Portal 來定義動態頁面的區塊。

<ng-template cdkPortal>
  <div style="border: solid 1px red; width: 400px">彈跳視窗內容</div>
</ng-template>

接著,在引用 OverlayModule 後,以及使用 Overlay 服務來開啟目標對象。如下面程式,可以利用 OverlayConfig 類別來定義開啟對象的位置、長與高等組態資訊。接著,透過 Overlay 服務的 create 來建立一個 Overlay 區域,並把剛定義的 Protal 內容加入這個區域內;以及關閉時把它給卸載掉。

@ViewChild(CdkPortal)
portal!: CdkPortal;

private readonly overlay = inject(Overlay);

onOpen(): void {
  const config = new OverlayConfig({
    positionStrategy: this.overlay
      .position()
      .global()
      .centerHorizontally()
      .centerVertically(),
    minWidth: '500px',
    height: '400px',
    hasBackdrop: true,
  });
  const overlayRef = this.overlay.create(config);
  overlayRef.attach(this.portal);
  overlayRef.backdropClick().subscribe(() => overlayRef.detach());
}

除了上述方法外,我們也可以利用指令的方式來開啟 Overlay。如下面程式,在按鈕中透過 cdkOverlayOrigin 來設定觸發點,並且在點選這個按鈕時去控制一是否開啟的屬性。

<button
  mat-stroked-button
  color="primary"
  cdkOverlayOrigin
  #trigger="cdkOverlayOrigin"
  (click)="isOpen = !isOpen"
>
  Open
</button>

<ng-template
  cdkConnectedOverlay
  [cdkConnectedOverlayOrigin]="trigger"
  [cdkConnectedOverlayOpen]="isOpen"
>
  <div style="border: solid 1px red; width: 400px">Dialog Open</div>
</ng-template>

接著,在範本中利用 cdkConnectedOverlay 指定此為 Overlay 區域,並設定 cdkConnectedOverlayOrigincdkConnectedOverlayOpen 來決定開啟此區域的觸發按鈕與開啟狀態資訊。

結論

在過去撰寫 Angular 專案時,常常會把 Angular Material 專案當作撰寫的參考資訊。在明確定義應用程式的全域與區域設定下,透過 Angular 與 Material 所提供的機制,可以較容易地開發出高靈活度的應用程式。


上一篇
Day 29 - CDK 的公用程式
系列文
用 Angular Material 開發應用程式30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言