I need to start the timer by clicking the button. But this is not happening
public startTimerRxjs() {
this.timeLeft$ = timer(0, 1000).pipe(
takeWhile(() => this.timeLeft > 0),
map(() => {
this.timeLeft--;
this.changeDetRef.detectChanges();
return this.timeLeft;
})
);
}
CodePudding user response:
You can use a variable that counts down your emits. In rxjs variables (state) is processed by the scan operator. With the takeWhile you can stop your stream emitting.
const { timer } = rxjs;
const { scan, takeWhile, asyncScheduler } = rxjs.operators
const result$ = timer(0, 1000).pipe(
scan(ticks => --ticks, 5),
takeWhile(v => v >= 0)
);
result$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
To reuse it and with more comments I created a custom operator called countdown
that wraps your problem.
const { timer } = rxjs;
const { scan, takeWhile, asyncScheduler } = rxjs.operators
/*
* dueTime, intervalOrScheduler, schedule: timer api - https://rxjs.dev/api/index/function/timer
* maxTicks: describe the max timer emits
*/
const countdown = (dueTime = 0, intervalOrScheduler, maxTicks = 0, scheduler = asyncScheduler) => timer(dueTime, intervalOrScheduler).pipe(
// start with the maxTicks value and decrease every emit
scan(remainingTicks => --remainingTicks, maxTicks),
// stop emitting when maxTicks reaches -1
takeWhile(v => v >= 0)
);
const result$ = countdown(0, 1000, 5)
result$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
CodePudding user response:
Either use the async pipe in your component (without using a button to trigger it), or subscribe in code:
<div>{{ timeLeft | async }}</div>
or:
this.timeLeft$ = timer(0, 1000)
.pipe(
takeWhile(() => this.timeLeft > 0),
map(() => {
this.timeLeft--;
this.changeDetRef.detectChanges();
return this.timeLeft;
})
).subscribe();