rxjs6 Таймер не запускается в подписке Angular 6 на наблюдаемый таймер, размещенный в службе

Я пытаюсь поставить таймер из rxjs 6 в службу angular 6. И не запускается. Я посмотрел в документации без везения. Это мой служебный код (только соответствующая часть:

import { map,flatMap, catchError, take } from 'rxjs/operators';
import { BehaviorSubject, of, throwError,timer, Observable } from "rxjs";

.....

  countdownTimer = new Observable<number>();


  formatCountdownTime(count) {
    const seconds = count % 60 < 10 ? '0' + Math.floor(count % 60) : Math.floor(count % 60);
    /*    if(count <= 1000){
         //set timer to NOT RUNNING state so it updates UI components like the button that depends on the count
          this.contributorManagerService.countdownTimerIsRunning.next(false);
       } */
       return Math.floor(count / 60) + ':' + seconds;
  }

  createCountdownTimerObservable(count){
    this.countdownTimer =  timer(0, 1000);

  }

и это потребление таймера. Мне нужно знать, когда истекло время, и поэтому я передаю этот третий параметр функции в подписку, так как мне нужно включить кнопку, когда время истекло.

import { map,take } from 'rxjs/operators';


export class CampaignDataComponent implements OnInit, OnDestroy {

 countdownTimerIsRunning = false ;
 count: number;


ngOnInit(){

/* I subscribe to the timer and the 3rd parameter indicates what to do when time has elapsed */
      this.sharedHelpersService.countdownTimer.
      pipe(
        take(this.count),
        map(() => {
          --this.count;

          return this.count;
        })
      ).subscribe(count=>{
        console.log("New count",count);

          if(count>0){
             this.countdownTimerIsRunning = true;
          }
      },
      err=>{
        console.log("Countdown timer error", err);
      },
      ()=>{
        console.log("Time has elapsed");
        this.countdownTimerIsRunning = false;
      });

}

}

Знаете почему не заводится? Раньше это работало, когда я использовал всю цепочку для компонента, но поскольку мне нужно использовать ее из других компонентов, мне пришлось поместить ее в службу, и это сломало ее. Любые идеи?. заранее большое спасибо

РЕДАКТИРОВАТЬ: Просто чтобы уточнить, все компоненты должны использовать один и тот же обратный отсчет


person Juan    schedule 27.06.2018    source источник


Ответы (3)


Следующее должно помочь, чтобы таймер был общим для нескольких компонентов:

Обслуживание:

import { Injectable } from '@angular/core';
import { timer, Subject, Observable } from 'rxjs';
import { takeWhile, map } from 'rxjs/operators';

@Injectable()
export class CountdownService {

  private _countdown = new Subject<number>();

  countdown(): Observable<number> {
    return this._countdown.asObservable();
  }

  private isCounting = false;

  start(count: number): void {
    // Ensure that only one timer is in progress at any given time.
    if (!this.isCounting) {
      this.isCounting = true;
      timer(0, 1000).pipe(
        takeWhile(t => t < count),
        map(t => count - t)
      ).subscribe(
        t => this._countdown.next(t),
        null,
        () => {
          this._countdown.complete();
          this.isCounting = false;
          // Reset the countdown Subject so that a 
          // countdown can be performed more than once.
          this._countdown = new Subject<number>();
        }
        );
    }
  }
}

Компонент может инициировать обратный отсчет с помощью

countdownService.start(myCountdownTime)

и все компоненты, заинтересованные в обратном отсчете времени, могут подписаться с помощью

countdownService.countdown().subscribe(t => ...)

Пример Stackblitz

person Sam Herrmann    schedule 28.06.2018
comment
Все ответы были действительно полезными, и Брандт много думал о rxjs. В этом конкретном случае мне нужно было создать сервис, подобный вашему, по нескольким причинам, и поэтому я выбираю этот ответ. - person Juan; 28.06.2018
comment
просто чтобы уточнить, мне пришлось создать дополнительную тему поведения, чтобы проверить, запущен ли новый таймер, поскольку в противном случае некоторые компоненты не будут обновляться, если я не обновлю страницу, я добавил это поверх вашего решения, и это сработало очень хорошо - person Juan; 28.06.2018

Проблема в этом коде

  pipe(
    take(this.count),
    map(() => {
      --this.count;

      return this.count;
    })

Я предполагаю, что в компоненте нет другого кода, кроме этого, поэтому this.count инициализируется равным 0. Затем вы подписываетесь на наблюдаемое и говорите, что эффективно принимаете (0), поэтому наблюдаемое немедленно завершается.

person Brandt    schedule 28.06.2018
comment
Условие ngIf сделало компонент недоступным. это помогло мне обнаружить первую стадию проблемы!! - person Juan; 28.06.2018

Когда вы говорите, что вам нужно использовать обратный отсчет от других компонентов, если при этом вы имеете в виду, что вам нужно использовать функциональность от других компонентов, но каждый компонент, который подписывается, имеет свой собственный независимый обратный отсчет, тогда вы можете сделать следующее:

Обслуживание:

import { timer, Observable } from 'rxjs';
import { filter, takeWhile, map } from 'rxjs/operators';

// startTime is in seconds
count(startTime: number): Observable<number> {
  return timer(0, 1000).pipe(
    takeWhile(t => t < startTime),
    map(t => startTime - t)
  )
}

Составная часть:

// Count down for 10 seconds.
countdownService.count(10).subscribe(
  t => console.log(t), 
  null, 
  () => console.log('Done!')
)

Это напечатает: 10 9 8 7 6 5 4 3 2 1 Готово!

person Sam Herrmann    schedule 28.06.2018
comment
Прежде всего спасибо за вашу помощь! Нет, все компоненты должны использовать один и тот же обратный отсчет, поскольку он позволяет использовать разные компоненты пользовательского интерфейса, и один и тот же обратный отсчет продолжается после уничтожения и создания компонентов. - person Juan; 28.06.2018
comment
Сэм Херрманн, так как один из компонентов инициирует обратный отсчет, а затем тот же обратный отсчет используется еще двумя компонентами, у которых есть элементы пользовательского интерфейса, которые необходимо обновить. - person Juan; 28.06.2018
comment
Смотрите мой другой ответ. Я надеюсь, что это больше соответствует вашим требованиям. - person Sam Herrmann; 28.06.2018