Angular ngrx、rxjs和角5

Angular ngrx、rxjs和角5,angular,rxjs,ngrx,Angular,Rxjs,Ngrx,我已经试着找出一个简单的计时器,这几个星期以来都是可以观察到的,但运气不好。我上周最初发布了以下内容: 什么也没有得到。我试着实现了建议,并用我最初的解决方案取得了一些进展。在这一点上,我有一个计时器,它正在发出和输出倒计时,但只有当播放或暂停按钮被点击时。我正在尝试倒计时,以便在按下播放按钮时继续向显示组件发送值。我有控制台记录的计时器,它发出的值,而发挥是推罚款,但显示组件没有。我想不出来。我是Angular 5和ngrx/rxjs的新手 我这里有Stackblitz工作表中的项目代码 您可

我已经试着找出一个简单的计时器,这几个星期以来都是可以观察到的,但运气不好。我上周最初发布了以下内容: 什么也没有得到。我试着实现了建议,并用我最初的解决方案取得了一些进展。在这一点上,我有一个计时器,它正在发出和输出倒计时,但只有当播放或暂停按钮被点击时。我正在尝试倒计时,以便在按下播放按钮时继续向显示组件发送值。我有控制台记录的计时器,它发出的值,而发挥是推罚款,但显示组件没有。我想不出来。我是Angular 5和ngrx/rxjs的新手

我这里有Stackblitz工作表中的项目代码

您可以使用user:test登录密码:test

计时器代码位于核心/services/pomo timer.ts中

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
容器组件是书籍/容器/所选书籍页面。ts

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
显示组件为书籍/组件/书籍详细信息。ts

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
此时它应显示6秒,一旦按下播放按钮,它应发出并显示每秒倒计时,直到按下暂停按钮,此时它应暂停,直到再次单击播放按钮。正如我提到的,当我将值记录到console.log中时,工作正常。只有在组件中显示时,它们才不会显示

从UI:使用测试/测试登录。找一本书。添加到集合中。点击至详细信息页面。有一个播放和暂停按钮。页面上显示的是我从StackOverflow上找到的解决方案中尝试的计时器的三个变体。计时器以6秒开始计时,并倒计时至零。单击播放,计时器开始。单击暂停,计时器停止,直到再次单击播放。在显示页面上,发出的值不是倒计时。控制台打开时,它会对发出的值进行倒计时

计时器由core/services/pomo timer.ts处理

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
显示由应用程序/书籍/组件/书籍详细信息处理。ts

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
导出类BookDetailComponent{
@Input()simpleObservable:数字;
@输入()秒:字符串;
@Input()剩余时间:数字;
@Input()timerSubscription:订阅;
@Input()book:book;
@inCollection中的Input():布尔值;
@Output()add=neweventemitter();
@Output()remove=neweventemitter();
@Output()resumeClicked=neweventemitter();
@Output()checkTime:EventEmitter=neweventemitter();
获取id(){
返回此.book.id;
}
获取标题(){
返回this.book.volumeInfo.title;
}
获取副标题(){
返回此.book.volumeInfo.subtitle;
}
获取描述(){
返回this.book.volumeInfo.description;
}
获取缩略图(){
返回(
this.book.volumeInfo.imageLinks&&
this.book.volumeInfo.imageLinks.small缩略图
);
}
获得时间{
返回此。剩余时间;
}
resumeCommand(操作:任意){
this.resumeClicked.emit(操作);
}
}
与计时器服务的通信由以下程序处理:app/books/containers/selected book page.ts

   startTimer() {

    const resumeButton = document.getElementById('resume');
    const pauseButton = document.getElementById('pause');
    const resetButton = document.getElementById('reset');
    const interval$: any = interval(1000).pipe(mapTo(-1));
    const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
    const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));

   const timer$ = merge(pause$, resume$).pipe(
    startWith(interval$),
     switchMap(val => (val ? interval$ : empty())),
     scan((acc, curr) => (curr ? curr + acc : acc), 
     this.countdownSeconds$),
      takeWhile(v => v >= 0),
      )
     .subscribe(
      val => { this.timeRemaining = val; 
               console.log(this.timeRemaining); 
       },
        val => { this.checkTime.emit(val); },
        () => {
         this.resetTimer();
        });
       }
export class BookDetailComponent {

  @Input() simpleObservable: number;
  @Input() seconds: string;
  @Input() timeRemaining: number;
  @Input() timerSubscription: Subscription;
  @Input() book: Book;
  @Input() inCollection: boolean;
  @Output() add = new EventEmitter<Book>();
  @Output() remove = new EventEmitter<Book>();
  @Output() resumeClicked = new EventEmitter();
  @Output() checkTime: EventEmitter<number> = new EventEmitter();

get id() {
 return this.book.id;
}

get title() {
 return this.book.volumeInfo.title;
 }

get subtitle() {
  return this.book.volumeInfo.subtitle;
}

get description() {
 return this.book.volumeInfo.description;
}

get thumbnail() {
 return (
   this.book.volumeInfo.imageLinks &&
   this.book.volumeInfo.imageLinks.smallThumbnail
  );
}

get time() {
  return this.timeRemaining;
 }
resumeCommand(action: any) {
  this.resumeClicked.emit(action);
 }
}
@Component({
  selector: 'bc-selected-book-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
 template: `
   <bc-book-detail
    [book]="book$ | async"
    [inCollection]="isSelectedBookInCollection$ | async"
    [timeRemaining]="this.pomoTimerService.timeRemaining"
    [simpleObservable]="this.simpleObservable | async"
    [seconds]="this.pomoTimerService.timeRemaining"
    (checkTime)="checkCurrentTime($event)"
    (add)="addToCollection($event)"
    (remove)="removeFromCollection($event)"
    (resumeClicked)="resumeClicked($event)"
    (resumeClicked)="resumeClicked($event)"
    (reset)="resumeClicked($event)">
   </bc-book-detail>
  `,
  })
  export class SelectedBookPageComponent implements OnInit {
   book$: Observable<Book>;
   isSelectedBookInCollection$: Observable<boolean>;
   timeRemaining: any;
  private timerSubscription: Subscription;
  timerSource = new Subject<any>();
  simpleObservable;
  countDown: any;
  counter: number;
  seconds: string;
  private subscription: Subscription;
  checkTime;

 constructor(public pomoTimerService: PomoTimerService, private store: 
   Store<fromBooks.State>) {
   this.book$ = store.pipe(select(fromBooks.getSelectedBook));
   this.isSelectedBookInCollection$ = store.pipe(
   select(fromBooks.isSelectedBookInCollection)
  );
 }

ngOnInit(): void {
  this.pomoTimerService.pomoCount$ = 0;
  this.pomoTimerService.pomosCompleted$ = 0;
   this.pomoTimerService.pomoTitle$ = 'Time to Work';
   this.pomoTimerService.initTimer();
 }

addToCollection(book: Book) {
 this.store.dispatch(new collection.AddBook(book));
 }

 removeFromCollection(book: Book) {
  this.store.dispatch(new collection.RemoveBook(book));
  }

resumeClicked(event) {
  console.log(event);
  console.log(event.target);
  console.log(event.srcElement);
  console.log(event.type);
  console.log(event.currentTarget.attributes.name.nodeValue);
  console.log(event.currentTarget.attributes.id.nodeValue);
   if (event.currentTarget.attributes.id.nodeValue === 'resume' && 
    !this.pomoTimerService.timerStarted) {
    this.pomoTimerService.timerStarted = true;
    this.pomoTimerService.startTimer();
    }
   }

checkCurrentTime(event) {
  this.counter = event;
 }
}
@组件({
选择器:“bc所选图书页”,
changeDetection:ChangeDetectionStrategy.OnPush,
模板:`
`,
})
导出类SelectedBookPageComponent实现OnInit{
账面价值:可见;
isSelectedBookInCollection$:可见;
剩余时间:任何;
私人定时器订阅:订阅;
timerSource=新主题();
简单可观测;
倒计时:任何;
柜台:号码;
秒:字符串;
私人认购:认购;
检查时间;
建造商(公共pomoTimerService:pomoTimerService,私人商店:
商店){
this.book$=store.pipe(选择(fromBooks.getSelectedBook));
此.isSelectedBookInCollection$=store.pipe(
选择(从Books.isSelectedBookInCollection中)
);
}
ngOnInit():void{
this.pomoTimerService.pomoCount$=0;
this.pomoTimerService.pomosCompleted$=0;
this.pomoTimerService.pomoTitle$=“工作时间”;
this.pomoTimerService.initTimer();
}
addToCollection(book:book){
this.store.dispatch(new collection.AddBook(book));
}
从集合中移除(书本:书本){
this.store.dispatch(new collection.RemoveBook(book));
}
恢复(事件){
console.log(事件);
console.log(event.target);
log(event.src元素);
console.log(事件类型);
log(event.currentTarget.attributes.name.nodeValue);
log(event.currentTarget.attributes.id.nodeValue);
如果(event.currentTarget.attributes.id.nodeValue==='resume'&&
!this.pomoTimerService.timerStarted){
this.pomoTimerService.timerStarted=true;
这个.pomoTimerService.startTimer();
}
}
checkCurrentTime(事件){
this.counter=事件;
}
}
pomo-timer.ts通过
this.remainingTime

如果您能提供任何帮助,我们将不胜感激。我已经尝试了所有我在Stackoverflow上找到的甚至是远程相关的例子。多谢各位

我设法得到了一个工作计时器服务

代码中有很多我想重构的地方,但在这里我给出了使其与现有应用程序结构一起工作所需的最低分类

我应用的基本原则是:

  • 使用异步订阅
    服务随时间产生值,因此应该在组件中作为可观察对象订阅,最好使用
    async
    管道,以便通过Angular自动清理订阅

  • 缓冲内部可观察对象
    使用
    主题
    作为计时器$与其消费组件之间的缓冲区。这使得组件总是能看到有效的可观察对象,甚至在计时器$初始化之前

  • 带有ViewChild的访问按钮
    不要使用
    document.getElementById()
    作为文档访问按钮