Reputation: 83
Expected behavior:
Reset interval when input value changes. When interval reaches 0 hide element in the dom.
My implementation does not consistently restart the interval. I believe the issue is because the value changes observable only fires off when the input value is a distinct values. I have add a Stackblitz to show the behavior. Any help is greatly appreciated.
View
<input [formControl]="inputFC">
Controller
public inputFC: FormControl = new FormControl('', []);
public counter$ = interval(1000).pipe(
mapTo(-1), // subtract from timer
scan((accumulator, current) => {
return accumulator + current;
}, 3),
takeWhile(value => {
return value >= 0;
}),
map(value => {
this.hide = (value >= 0);
return value;
}),
repeatWhen(() => this.inputFC.valueChanges));
public input$ = this.inputFC.valueChanges.pipe(throttle(() => this.counter$));
Upvotes: 1
Views: 254
Reputation: 96969
There're a couple of things:
With this.hide = (value >= 0)
hide
will always be true
because the last value passed by takeWhile
is 1
. When the counter reaches 0
it will swallow the value and complete the chain.
takeWhile
accepts an optional argument that tells takeWhile
to pass the last value that didn't pass the predicate function. So you can use it like this takeWhile(value => value >= 0, true)
.
throttle()
will unsubscribe from this.counter$
after its first emission and then subscribe again when the form value changes. This means that you don't need to use repeatWhen
at all and the timer will reset automatically.
For sideeffects it's better to use tap()
for convinience. When using timers in Angular you might need in some situations trigger change detection manually.
So I'm not sure what exactly you want to do but I guess this could be fairly close and hopefuly you'll get the idea how it works.
public counter$ = interval(1000).pipe(
mapTo(-1), // subtract from timer
scan((accumulator, current) => accumulator + current, 3),
takeWhile(value => value >= 0, true),
tap(value => this.hide = (value > 0)),
filter(value => value === 0), // only when the timer reaches `0` we'll disable `throttle`'s timer and it'll unsubscribe.
);
public input$ = this.inputFC
.valueChanges
.pipe(
map(value => value.substr(value.length - 1)),
throttle(() => this.counter$)
);
Your updated live demo: https://stackblitz.com/edit/rxjs-interval-form-control-qquuyb?file=src%2Fapp%2Fapp.component.ts
Upvotes: 1