Reputation: 5367
In the application combineLatest is used to combine three observables:
class SomeComponent {
private heightProvider = new SubjectProvider<any>(this);
private marginsProvider = new SubjectProvider<any>(this);
private domainProvider = new SubjectProvider<any>(this);
arbitraryMethod(): void {
combineLatest([
this.heightProvider.value$,
this.marginsProvider.value$,
this.domainProvider.value$
]).pipe(
map(([height, margins, domain]) => {
// ...
}
}
setHeight(height: number): void {
this.heightProvider.next(height);
}
setMargins(margins: {}): void {
this.marginsProvider.next(margins);
}
setDomain(domain: []): void {
this.domainProvider.next(domain);
}
}
However, I've noticed a few times already that I am sometimes forgetting to set one of these observables.
Is there a way I can build in error handeling that throws to console once one of these isn't set?
Upvotes: 0
Views: 152
Reputation: 8052
Observables aren't typically 'set' or 'not set'. I'm not sure what you mean by this. If you have a predicate that can check your observables, here is how you might use it.
// predicate
function notSet(o: Observable<any>): Boolean{
//...
}
scale$: Observable<any> = defer(() => {
const combining = [
this.heightProvider.value$,
this.marginsProvider.value$,
this.domainProvider.value$
];
const allSet = !combining.find(notSet)
if(!allSet) console.log("Not Set Error");
return !allSet?
EMPTY :
combineLatest(combining).pipe(
map(([height, margins, domain]) => {
// ...
}
If I understand your problem properly, you want to throw an error if any of your source observables haven't emitted yet. At its heart, this feels like a simple problem, but it happens to be a problem for which there doesn't exist a single general solution.
Your solution has to be domain-specific to some extent.
What you're asking a similar to this:
const add = (a: number) => (b: number): number => {
// How do I throw an error if this function
// isn't invoked with a second number?
return a + b;
}
/***********
* Example 1
***********/
// add is being called with one number
const add5 = add(5);
...
/* More code here */
...
// add is being called with a second number
const result = add5(50);
console.log(result); // Prints "55"
/***********
* Example 2
***********/
const result = add(5)(20); // Add is being called with both numbers
console.log(result); // Prints "55"
/***********
* Example 3
***********/
// add is being called with one number
const add5 = add(5);
...
/* More code here */
...
// add was never given a second number
return
// Add throws an error? How?
How can you write add
such that it throws an error if the second number isn't 'set'? Well, there's no simple answer. add
doesn't know the future and can't guess whether that second number was forgotten or will still be set in the future. To add
, those two scenarios look the same.
One solution is to re-write add so that it must take both parameters at once. If either is missing, throw an error:
const add = (a: number, b: number): number => {
if(a != null && b != null){
return a + b;
}
throw "add: invalid argument error";
}
This solution fundamentally changes how add
works. This solution doesn't work if I have a requirement that add must take its arguments one at a time.
If I want add
to keep that behaviour, perhaps I can set a timer and throw an error if the second argument isn't given fast enough.
const add = (a: number) => {
const t = setTimeout(
() => throw "add: argument timeout error"),
1000 // wait 1 second
);
return (b: number): number => {
clearTimeout(t); // cancel the error
return a + b;
}
}
Now add
takes its arguments one at a time, but is a timeout really how I want this to work? Maybe I only care that add is given a second parameter before some other event (an API call returns or a user navigates away from the page) or something.
Hopefully, you can begin to understand how such a "simple" problem has only domain-specific solutions.
Your question, as writ, doesn't tell us enough about what you're trying to accomplish to guess what behaviour you want.
Observables have a lot of power built into them to allow you to design a solution specific to your needs. It's almost certain that you can throw an error if one of your observables isn't set, but first, you must define what this even means.
Is it not set quickly enough? Is it not set in time for a certain function call? Not set when an event is raised? Never set? How would you like to define never? When the program is shut down?
Maybe you could switch your Subject
s for BehaviourSubject
s so that they MUST always have a value set (sort of like add
taking both arguments at once instead of one at a time).
All of these things (and many many many more) are possible.
Upvotes: 1