繁体   English   中英

监听Observable.timer并发送给父组件

[英]Listen to Observable.timer and emit to parent component

我有一个使用Observable.timer的倒计时组件,该组件在父组件中使用。 使用时,它需要花费来自父组件的@Input() seconds: string ,该@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)
}); 

抱歉,如果已经有相关问题,请帮助这个新输入的角度用户。

主要问题是您正在将Observable的值与任意变量解耦。 通常,您希望Observable流为您转换一个值-这是RxJS的一半。

问题在于.map(() => --this.counter) map运算符转换值流并返回新值。 在这里,您正在将Observable值转换为--counter 有问题。 --counter将返回counter - 1和decrement counter ,但是该值与Observable流完全分离 这意味着什么?

从该Observable外部控制该值会使该Observable变得炙手可热 它的值可以流式传输到不同的订户,但是值可以由于外部因素而改变。 (请记住,一个Observable在订阅之前不会执行)

但是...您只有一个订户,所以这不是问题,对吧? 实际上,Angular async管道订阅了底层的Observable。 这意味着您可观察已订阅的两倍 ,这意味着有两个定时器倒计时,这意味着有执行该两个流map功能-这意味着每一秒, this.counter正在递减两次

我建议结合Observable的计时器值和实际时间值,然后仅作为副作用发出事件:

  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 ,这是一种更具声明性的方式来说明应该采取多少排放量,并在提供的表达式为false时完成:

  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

  }

希望这有助于消除一些困惑!

您可以尝试停止订阅的倒计时,计时器将在后台运行。

Stackblitz重建

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM