收听 Observable.timer 并发送给父组件
Listen to Observable.timer and emit to parent component
我有一个使用父组件中使用的 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)
});
抱歉,如果已经有相关问题,请帮助这个新输入的 angular 用户。
您可以尝试停止订阅倒计时,计时器将在后台运行。
主要问题是您将 Observable 的值与任意变量解耦。通常您希望 Observable 流为您转换一个值——这是 RxJS 的一半。
.map(() => --this.counter)
有问题。 map
运算符转换值流和 return 新值。在这里,您将 Observable 值转换为 --counter
;有问题。 --counter
将 return counter - 1
递减 counter
,但该值与 Observable 流完全解耦。这是什么意思?
从 Observable 外部控制该值会使 Observable hot。它的值可以流向不同的订阅者,但这些值可能会因外部因素而改变。 (记住 Observable 在被订阅之前不会执行)
但是...您只有一个订阅者,所以这不是问题,对吧?实际上,Angular async
管道 也 订阅了引擎盖下的 Observables。这意味着你的 Observable 已经订阅了 两次,这意味着有两个计时器在倒计时,这意味着有两个流执行那个 map
函数——这意味着每秒,this.counter
被递减 两次 .
我建议结合 Observable 的 timer 值和 actual 时间值,然后仅作为副作用发出您的事件:
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
,这是一种更明确的方式来说明应该采取多少排放量,并在提供的表达式为假时完成:
ngOnInit() {
const start = parseInt(this.seconds, 10);
this.countdown = Observable.timer(0, 1000)
.map(i => start - i) // decrement the stream's value and return
.takeWhile(i => i >= 0)
.do(s => this.checkTime.emit(s)) // do a side effect without affecting value
}
希望这有助于消除一些困惑!
我有一个使用父组件中使用的 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)
});
抱歉,如果已经有相关问题,请帮助这个新输入的 angular 用户。
您可以尝试停止订阅倒计时,计时器将在后台运行。
主要问题是您将 Observable 的值与任意变量解耦。通常您希望 Observable 流为您转换一个值——这是 RxJS 的一半。
.map(() => --this.counter)
有问题。 map
运算符转换值流和 return 新值。在这里,您将 Observable 值转换为 --counter
;有问题。 --counter
将 return counter - 1
递减 counter
,但该值与 Observable 流完全解耦。这是什么意思?
从 Observable 外部控制该值会使 Observable hot。它的值可以流向不同的订阅者,但这些值可能会因外部因素而改变。 (记住 Observable 在被订阅之前不会执行)
但是...您只有一个订阅者,所以这不是问题,对吧?实际上,Angular async
管道 也 订阅了引擎盖下的 Observables。这意味着你的 Observable 已经订阅了 两次,这意味着有两个计时器在倒计时,这意味着有两个流执行那个 map
函数——这意味着每秒,this.counter
被递减 两次 .
我建议结合 Observable 的 timer 值和 actual 时间值,然后仅作为副作用发出您的事件:
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
,这是一种更明确的方式来说明应该采取多少排放量,并在提供的表达式为假时完成:
ngOnInit() {
const start = parseInt(this.seconds, 10);
this.countdown = Observable.timer(0, 1000)
.map(i => start - i) // decrement the stream's value and return
.takeWhile(i => i >= 0)
.do(s => this.checkTime.emit(s)) // do a side effect without affecting value
}
希望这有助于消除一些困惑!