前一篇使用了 @Input
,來向元件傳入變數,今天我們要用 @Output
對元件外傳出變數。
我們之前做了一個登入的功能,卻只能從 AccountManagerComponent
來控制登入及登出的狀態,這是非常不合理的。所以今天我想實作,在子元件按下 Login 時,可以傳送一個請求,更改 AccountManagerComponent
的 status。
@Output
和 @Input
的基本概念相似,可以當成定義一個出口,送出event,所以我們一樣宣告一個變數,我命名為 loginRequest
並且在前面加上 @Output
:
// login.component.ts
@Output() loginRequest;
然後,我們需要初始化這個變數,我們給他一個 EventEmitter
,可以當成是,這個變數會往 Component 外丟出 event:
@Output() loginRequest = new EventEmitter<any>();
<any>
這個地方要放當 EventEmitter
觸發時,要送出資料的型別,any
就是任意型別都可以。在我這個範例,只會丟出 boolean
資料,所以其實填入 <boolean>
會比較嚴謹。
這邊注意在打 EventEmitter
時,由於我們這份 ts
還沒有 import 過這個模組,此時 VSCODE 會出現提示字,並且會幫我們 import。這時請注意,我們要選擇的是從 @angular/core
import的 EventEmitter
。
操作正確的話,最上面的 import 應該會像這樣:
此時我們已經定義好對外的 @Output()
介面了,切到 account-manager.component.html
,我們已經可以在 <app-login></app-login>
下用 loginRequest
做 Event Binding。
<app-login [loginStatus]="status" (loginRequest)=""></app-login>
那麼我們現在來實作,從 LoginComponent
要送出的事件與資料,我先決定好我要的 function:loginAction
負責登入,logout
負責登出。
// login.component.ts
loginAction() {
}
logout() {
}
然後綁定到我們 login.component.html
裡面的兩個 button
:
// login.component.html
<div *ngIf="!loginStatus">
...
<input type="submit" value="Login" (click)="loginAction()">
</div>
<div *ngIf="loginStatus">
<button (click)="logout()">Logout</button>
</div>
現在 loginAction()
和 logout()
已經和login.component.html
內的 button
做完 Event binding,按下 button
就會分別觸發 loginAction()
和 logout()
。
接者定義我按下這兩個 button
時, @Output()
要送什麼資料出去。
我用剛剛宣告的 loginRequest
,用 emit
這個function,發射一個 boolean
的物件。
登入時我發射 true
,登出時我發射 false
。而這裡為求簡單,就不做驗證帳密相關的功能了。
// login.component.ts
loginAction() {
this.loginRequest.emit(true);
}
logout() {
this.loginRequest.emit(false);
}
現在的 AccountManagerComponent
已經可以在 <app-login>
丟出 true
跟 false
,
// account-manager.component.html
<app-login ... (loginRequest)=""></app-login>
那我們要用一個 function 來接這個參數,或著說,當 loginRequest
發出 emit 時,我要觸發一個 function。所以我們需要在 account-manager.component.ts
中設計一個 function,被 loginRequest
觸發。
// account-manager.component.ts
loginCheck($event) {
this.status = $event;
}
// account-manager.component.html
<app-login ... (loginRequest)="loginCheck($event)" ></app-login>
這邊的 $event
就會接到從 loginRequest
emit 出來的 true
或 false
。並且直接改變 status 的登入狀態。
覺得疑惑的話,可以在 loginCheck($event)
中加入 console.log()
,將 $event
印出來看看:
console.log('$event: ' + $event);
現在按下 Login、Logout 的 button
,就可以透過 @Output
發出事件,改變登入狀態的 status ,並且修改 Login、 Logout 的顯示與否了。
按下 Login
:
再按下 Logout 又會回到 Login。
資料流大致上是這樣
還有在使用 @Input()
、@Output()
這兩個 Decorator
時,可以在括號中填入其他名字來 rename,就可以用 rename 過的名字進行 Property Binding。
舉例之前的 loginStatus
。
@Input() loginStatus;
可以 rename 成 sss
或任何名字 :
@Input('sss') loginStatus;
那我們就必須用 rename 過的名字 Binding:
<app-login [sss]="status"></app-login>
但這個 rename 的功能,Angular 是不推薦使用,所以還是盡量少用吧。