I cant really think of any situations in which you'd want an observable like this:
const formIdValid = defer(() => of(this.filterFrm.valid));
It's basically just using a bit of extra computing power to read this.filterFrm.valid
wherever you subscribe.
For example, your solution can be re-written like this without any issue:
this.filterFrm.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged(),
map(frmValue => ({
frmValue,
isValid: this.filterFrm.valid,
})),
tap(console.dir),
filter(({ isValid }) => isValid),
map(({ frmValue }) => ({
searchPhrase: frmValue.filterFld,
startDate: frmValue.startDateFld ? new Date(frmValue.startDateFld) : undefined,
endDate: frmValue.endDateFld ? new Date(frmValue.endDateFld) : undefined
})),
takeUntil(this.destroy)
).subscribe(
filterCriteria => this.filterChanged.emit(filterCriteria)
);
Or if you don't care about your console.dir
logging isValid, then this is also the same:
this.filterFrm.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged(),
tap(console.dir),
filter(_ => this.filterFrm.valid),
map(frmValue => ({
searchPhrase: frmValue.filterFld,
startDate: frmValue.startDateFld ? new Date(frmValue.startDateFld) : undefined,
endDate: frmValue.endDateFld ? new Date(frmValue.endDateFld) : undefined
})),
takeUntil(this.destroy)
).subscribe(
filterCriteria => this.filterChanged.emit(filterCriteria)
);
Aside: What is defer really doing?
consider the following:
let num = 10;
const $1 = of(num);
const $2 = defer(()=>of(num));
const $3 = of(1).pipe(map(_ => num));
const $4 = of(1).pipe(mapTo(num));
num++;
$1.subscribe(console.log);
$2.subscribe(console.log);
$3.subscribe(console.log);
$4.subscribe(console.log);
If you run this, what do you expect as output? What you need to understand to answer this properly is when the value of num
is resolved. For both, $1
and $4
, this is done when the observable is created, which means that you get the first value of num
. For $2
and $3
, num
is resolved when the lambda given to defer
/map
is invoked.
defer
doesn't invoke its factory function until subscription.
map
invokes its transformation function each time a new value arrives, which is some time after subscription at the earliest.
Therefore, both defer
and map
end up accessing the second value of num
The Output
10
11
11
10
Back to this.filterFrm.valid
The problem comes from when this.filterFrm.valid is resolved. A function (in this case the lambda given to filter
) doesn't access that variable until it is invoked. Filter only invokes the function when it gets a new value and so for every new value, the filter will access this.filterFrm.valid
anew.
So in this case, you're not gaining anything with defer