我有一个使用Observable.timer
的倒计时组件,它在父组件中使用。使用它时,从父组件中获取@Input() seconds: string
,用作倒计时ex: 60
开始的数字。现在,我想向父组件发出倒计时数@Output() checkTime
,以便在按钮到达0
时禁用该按钮。
所以我将倒计时编号订阅到checkTime
事件发射器。但结果是,倒计时不会将其停在0并且它会不断递减。任何人都可以看到下面的问题吗?
register.component.html
<tr *ngFor="let course of courses">
<td>
<button class="btn btn-info" [disabled]="counter === 0"> Register</button>
</td>
<td>
<countdown [seconds]="60" (checkTime)="checkTimeExpired($event);"></countdown>
</td>
</tr>
countdown.component.ts
import { Component, Input, Output, OnInit, EventEmitter } from '@angular/core'
import { Observable, Subscription } from 'rxjs/Rx';
@Component({
selector: 'countdown',
template: '{{ countDown | async | formatTime }}'
})
export class CountdownComponent implements OnInit {
@Input() seconds: string;
@Output() checkTime: EventEmitter<number> = new EventEmitter();
countDown: any;
counter: number;
private subscription: Subscription;
constructor() {}
ngOnInit() {
this.counter = parseInt(this.seconds, 10);
this.countDown = Observable.timer(0, 1000)
.take(this.counter)
.map(() => --this.counter)
this.subscription = this.countDown.subscribe(t => {
this.checkTime.emit(this.counter)
});
}
}
register.component.ts
counter: number;
checkTimeExpired(evt) {
this.counter = evt;
}
如果我不使用订阅,倒计时将停在0。
this.subscription = this.countDown.subscribe(t => {
this.checkTime.emit(this.counter)
});
很抱歉,如果已经有相关问题,请帮助这个新输入的角色用户。
答案 0 :(得分:2)
主要问题是你将Observable的值与任意变量分离。通常你想要一个Observable流来为你转换一个值 - 这是RxJS的一半。
问题在于.map(() => --this.counter)
。 map
运算符转换值流并返回新值。在这里,您将Observable值转换为--counter
;有问题。 --counter
将返回counter - 1
并递减counter
,但该值与Observable流完全解耦。这是什么意思?
从该Observable外部控制该值会使Observable hot 。它的值可以流向不同的订阅者,但值可能会因外部因素而发生变化。 (请记住,Observable在订阅之前不会执行)
但是......你只有一个用户,所以这不是问题,对吧?实际上,Angular async
pipe 也订阅了Observables。这意味着您的Observable已经订阅两次,这意味着有两个定时器倒计时,这意味着有两个流执行map
函数 - 这意味着每秒,{{1}正在递减两次。
我建议将Observable的计时器值和实际时间值组合在一起,然后仅将您的事件作为副作用发出:
this.counter
ngOnInit() {
const start = parseInt(this.seconds, 10);
this.countDown = Observable.timer(0, 1000)
.take(start + 1) // add one, so zero is included in emissions.
.map(i => start - i) // decrement the stream's value and return
.do(s => this.checkTime.emit(s)) // do a side effect without affecting value
}
管道将订阅它并开始排放。最好的部分是,async
管道会在销毁时自动清理订阅。
另一个想法是使用async
,这是一种更具说明性的方式来说明应该采取多少排放,并在提供的表达式为假时完成:
takeWhile
希望有助于消除一些困惑!
答案 1 :(得分:-1)
您可以尝试停止订阅倒计时,计时器将在后台运行。