javascript - 為什麼 'emit' 只在我第一次點擊按鈕時顯示名稱?
我想使用 eventemiter 在點擊按鈕時傳送一個名字,但不工作。第一次點擊按鈕時名字沒有顯示,但如果再點擊一次,名字就會出現。https://stackblitz.com/edit/angular-ue9dzk-extrange-emit
app.component.html
<hello *ngIf="name"></hello>
<show></show>
app.component.ts
import { Component } from '@angular/core';
import { NameService } from './name.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
})
export class AppComponent {
name: string;
constructor(private nameService: NameService) {
}
ngOnInit() {
this.nameService.show.subscribe(name => {
this.name = name;
})
}
}
hello.component.ts
import { Component, Input } from '@angular/core';
import { NameService } from './name.service';
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
name: string;
constructor(private nameService: NameService) {
}
ngOnInit() {
this.nameService.show.subscribe(name => {
this.name = name;
})
}
}
name.service.ts
import {EventEmitter} from '@angular/core';
export class NameService {
show = new EventEmitter();
}
show.component.ts
import { Component, Input } from '@angular/core';
import { NameService } from './name.service';
@Component({
selector: 'show',
template: `<button (click)="show()">Click to emit</button>`,
styles: [`h1 { font-family: Lato; }`]
})
export class ShowComponent {
name: string;
constructor(private nameService: NameService) {
}
show() {
this.nameService.show.emit('World');
}
}
答案#1
EventEmitter 是用於 @Output() 綁定的,因為它可以選擇非同步地發出值。不要在共享服務中使用它。
<hello *ngIf="name"></hello>
上述 會在值被發出時建立 元件。值被發出後,元件將訂閱該服務,但 EventEmitter 不會保留先前發出的值的歷史紀錄。因此元件不會接收到任何東西。
參見建構函式:
https://angular.io/api/core/EventEmitter#constructor
你很少需要這個功能,但在某些情況下,@Output() 綁定需要在下一個變更檢測週期中發出一個值。因此在這些情況下你需要使用 EventEmitter,但你也可以使用其他 Observable 主體作為綁定的發射器。
但是如果再點擊一次,名字就會出現
元件建立後,它會接收發出的值,而當你第二次點擊按鈕時,會發出第二個值,該值會顯示在元件的範本中。
大多數創建共享服務的人會使用帶有預設值的 BehaviorSubject,或者如果需要等待直到可以發出值,則使用 ReplaySubject。
在上面的例子中,你有這個邏輯 *ngIf="name",這表示你想要 等待直到一個值被發出。所以你會使用 new ReplaySubject(1) 取代 EventEmitter。
export class NameService {
show = new ReplaySubject(1);
}
答案#2
那是因為你在 hello 應用程式的選擇器上使用了 *ngIf。這將不會初始化 hello 元件,直到 app.component.ts 中的 name 變數有值為止。所以當你第一次點擊 emit 時,name 變數會先被賦值,然後你的 hello 元件才會初始化。接著在第二次點擊後,hello 應用程式中的 name 變數將被賦值為 "world",然後它就會被顯示出來。
解答如下。
<hello>
<label *ngIf="name">
{{name}}
</label>
</hello>
<show></show>
