I have attempted to figure out a simple timer observable for a couple of weeks now with no luck. I originally posted this last week: ngrx and angular 5 on stackoverflow and didn't get anywhere. I tried implementing what was suggested and got a little further with my original solution. At this point I have a timer that is emitting and outputting the countdown but only when a play or pause button is clicked. I am trying to get the countdown to continue emitting values to the display component while the play button is pushed. I have console logged the timer and it emits the values while play is pushed fine but the display component does not. I can't figure this out. I am new to Angular 5 and to ngrx/rxjs.
I have the project code available in a working form on Stackblitz here. I have the project code available in a working form on Stackblitz here.
You can login with user: test password: test
The timer code is in core/services/pomo-timer.ts
The container component is books/containers/selected-book-page.ts
The display component is books/components/book-detail.ts
At the moment it should display 6 seconds and once the play button is pushed it should emit and display each second countdown until the pause button is pushed at which time it should pause until play is clicked again. As I mentioned, when I console.log the values the work just fine. It is only when displayed in the component that they don't.
From UI: log in with test/test. Search for a book. Add To Collection. Click Through to Detail Page. There is a play and pause button. Displayed on the page are three variations of the timer I have tried from solutions found on StackOverflow. The timer starts with 6 seconds and counts down to zero. play is clicked the timer begins. pause is clicked the timer stops until play clicks again. on the display page the emitted values are not counting down. with console open, it does countdown emitted values.
The timer is handled by 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();
});
}
The display is handled by app/books/components/book-detail.ts
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);
}
}
The communication with the timer service is handled by: app/books/containers/selected-book-page.ts
@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;
}
}
The pomo-timer.ts is outputting the timer via this.remainingTime
Any assistance you might be able to provide would be greatly appreciated. I have tried all examples that are even remotely related that I have found here on Stackoverflow as well. Thank you very much.