iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Modern Web

新新新手閱讀 Angular 文件30天系列 第 26

新新新手閱讀 Angular 文件 - Component - ngOnDestroy(2) - Day26

本文內容

接續昨天 ngOnDestroy 還沒有記錄完的內容。

ngOnDestroy 可能沒被啟動的狀況

這邊有一個蠻特別的事情,就是 ngOnDestroy 只會在該元件所處的網頁還在運行的狀態下才會被啟動。
你可能會覺得沒什麼特別的,阿不就網頁關掉就關掉,還管它什麼元件的 ngOnDestroy 啟不啟動。
你這樣想也是沒錯,
但...... 如果,我們有在該元件的 ngOnDestroy 寫入一些特製的功能(比如: 當該元件進入 ngOnDestroy 時,要直接幫使用者登出的功能),結果使用者直接關掉當下頁面,就會導致元件根本就沒有進入 ngOnDestroy 的 lifecycle,最終,就會導致我們在 ngOnDestroy 撰寫的這些特製的功能沒有被啟動。
那有哪些狀況有可能會造成以上的狀況發生呢?

  1. 頁面重新整理
  2. 分頁被關掉
  3. 整個瀏覽器被關掉
  4. 使用者直接從當下頁面外連到其他頁面

HostListener - 監聽 DOM 事件

為了解決以上的狀況,我們必須要引入 Angular 的 HostListener 來監聽網頁的 beforeunload 事件。
首先,什麼是 beforeunload 事件呢?
它是一個當網頁即將要被關閉或重新整理之前,會被觸發的一個事件,當這個事件被觸發的時候,網頁上的資料都還是被保留狀況,也就是使用者還可以反悔的狀況。

接著,我們就用 HostListener 來監聽 beforeunload 被觸發的時候,來執行該元件的 ngOnDestroy 事件,來解決以上的狀況。
我們改寫一下 Day25 的範例
[子元件 -TypeScript]

import { Component, OnDestroy, HostListener} from '@angular/core';
import { AuthService } from '@app/auth.service.ts'
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class AppComponent implements OnDestroy  {
  // ...
  @HostListener('window:beforeunload')
  ngOnDestroy() {
    this.destroy$.next(true)
    this.destroy$.unsubscribe()
    
    // ... 使用者登出功能,或是其他特製的功能
  }
}

是不是很簡單呢~ 只要利用 HostListener 去監聽 window:beforeunload 的事件,在這行程式碼的下面要接,想要觸發的內容,而以上的範例,我們想要接著觸發的內容就是 ngOnDestroy 囉。

其實,HostListener 有兩個參數,一個是像上面範例所示被監聽的 DOM 事件,第二個參數是這個 DOM 事件的內容,
寫法如下
@HostListener('window:beforeunload', ['$event'])
你可能會納悶,為什麼上面的範例你不這樣寫呢?
原因是,ngOnDestroy 是沒有辦法傳入任何參數的喔,如果,我硬將 $event 寫入 ngOnDestroy 的參數部分,會得到以下的錯誤訊息
https://ithelp.ithome.com.tw/upload/images/20210926/201400930Fo9G7WLAt.png
大概的意思就是無法傳入參數給 ngOnDestroy 。

嘗試阻止使用者離開當下頁面 - 自訂義函式

如果,我們今天希望當使用者離開或重整當下頁面的時候,會跳出一個 alert 提示使用者是否要離開頁面,這個時候,我們可以使用自訂義的函式
寫法如下
[子元件 -TypeScript]

import { Component, OnDestroy, HostListener} from '@angular/core';
import { AuthService } from '@app/auth.service.ts'
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class AppComponent implements OnDestroy  {
  ngOnDestroy() {
    this.destroy$.next(true)
    this.destroy$.unsubscribe()
  }
  
  @HostListener('window:beforeunload', [$event])
  onBeforeUnload($event) {
    $event.preventDeafult()
    $event.returnValue = true
  }
}

可以看到我們將 HostListener 的部分改寫在 onBeforeUnload 的上面,而且傳入了 $event ,讓我們可以在 onBeforeUnload 裡面操作裡面的內容。
加入以上的內容之後,當使用者重整或關閉當下頁面都會跳出提示訊息,告知使用者即將要離開頁面了。

但是,要特別注意的是,當我們改以上面的寫法時,該元件的 ngOnDestroy 內容是不會被觸發的喔,因為,beforeunload 被觸發的當下,你的元件都還是可視的(visible),根本還沒有被消除,所以,不會進到 ngOnDestroy 裡面。

Summary

來做個總結

  1. 要注意在某些情況下的操作是不會觸發元件的 ngonDestroy 的 lifecycle hook 的,這個時候,我們可以利用 HostListener 來監聽 window 的 beforeunload 事件,來防止這種事情。
  2. 可以使用 onBeforeUnload 來跳出提示訊息,提醒使用者他即將要離開頁面了。

Reference:

  1. Angular HostListener API Doc
  2. Introduce about beforeunload DOM event
  3. Introduce about how to prevent component from not proceeding its ngOnDestroy lifecycle hook when user directly closing brower

上一篇
新新新手閱讀 Angular 文件 - Component - ngOnDestroy(1) - Day25
下一篇
新新新手閱讀 Angular 文件 - Router - pathMatch(1) - Day27
系列文
新新新手閱讀 Angular 文件30天30

尚未有邦友留言

立即登入留言