benlesh on master
docs(readme): fix number versio… (compare)
jakovljevic-mladen on 7.x
docs(exhaustAll): fix marble di… (compare)
this.onChangeHourChanged.pipe(
distinctUntilChanged(),
takeUntil(this.destroyed$),
).subscribe((hour) => {
const type = DateTimeType[this.dateTimeType];
console.log('HourChanged');
this.currentDateTime.set({
hour,
});
this.time = this.setTime(this.dateFilterValidatorService.setDate(type, this.currentDateTime));
this.writeValue(this.time);
});
this.onDispatchChanges.next(changes);
this.onDispatchChanges.pipe(
debounceTime(600),
distinctUntilChanged(),
).subscribe(dateChanges => {
this.dispatchChanges(dateChanges);
});
next
on it later
Hey friends, I've been exploring combining the concept of "Behavior Trees" (https://en.wikipedia.org/wiki/Behavior_Trees) with RxJS, and this revealed to me a combiner that I don't think currently exists, so I wanted to discuss if that's the case and if I should put up a PR to add such a combiner.
The most basic behavior tree at minimum contains an AND (sequence) combiner and an OR (selector) combiner. AND combiners run their children in sequence, and stop running if there are any failures. An AND combiner is actually very easy to translate to RxJS, it's literally just a concat.
An OR combiner instead runs it's children until success, and only fails if all it's children fail to return success. This is actually very similar to onErrorResumeNext
except for the following attributes:
The actual code for the combiner is below:
export function selector<T, R>(
...sources: Array<
| ObservableInput<any>
| Array<ObservableInput<any>>
| ((...values: Array<any>) => R)
>
): Observable<R> {
if (sources.length === 0) {
return throwError(new Error("No selections were successfully executed."));
}
const [first, ...remainder] = sources;
if (sources.length === 1 && Array.isArray(first)) {
return onErrorResumeNext(...first);
}
return new Observable((subscriber) => {
const subNext = () =>
subscriber.add(selector(...remainder).subscribe(subscriber));
return from(first).subscribe({
next(value) {
subscriber.next(value);
},
error: subNext,
complete: () => {
subscriber.complete();
},
});
});
}
Should I open a PR or am I recreating/reopening a discussion that has already occurred?
it("finds the first successful selection from a set.", () => {
const firstObs$ = cold("--#");
const secondObs$ = cold("--z--#");
const thirdObs$ = cold("--x--y|");
expect(selector(firstObs$, secondObs$, thirdObs$)).toBeMarble(
"----z----x--y|"
);
});
it("completes on the first successful selection.", () => {
const firstObs$ = cold("--y#");
const secondObs$ = cold("--z--|");
const thirdObs$ = cold("--x--#");
expect(selector(firstObs$, secondObs$, thirdObs$)).toBeMarble("--y--z--|");
});
it("errors if no selections are successful", () => {
const firstObs$ = cold("--y#");
const secondObs$ = cold("z--#");
const thirdObs$ = cold("--x--#");
expect(selector(firstObs$, secondObs$, thirdObs$)).toBeMarble(
"--yz----x--#"
);
});
@spaceribs A better place to reach the devs is slack or github. The usual response is to make a separate packages to combines with RxJs. That said they might be enthusiastic about this idea depending on how lightweight it can be added.
Also while i'm not familiar with behavior tree's myself, i do like to add RxJs is for multi value sequences and error is a rare item to emit. I'm not sure how that combines with behavior tree's.
That said, i do think what you describe is some unique behavior not easily combined with existing operators. Indeed AND could be concat or merge, but what you describe for OR (stop when any completes, error when all error) is not something i can easily produce from existing operators and sounds like a quite useful one.
Do remember that because of RxJs async nature, it would be interesting to have these operators you describe in both parallel (like merge) and sequential (like concat) flavor. Especially when you work with live data, onErrorResumeNext
and concat
will not work.
Ps. I just tought up of a way to get what you aim for using existing operators. onErrorResumeNext
already statisfies the stop requirement, and you can easily add the error requirement by not using onErrorResumeNext
on the last observable in line.
Now i'm pondering how to make a similar operator for the parallel case :D (as well as a nicer one that emits all previous errors when the last source fails)
fromEvent(window, 'orientationchange')
would emit a new width/height, but as it stands, it emits before the width/height have actually changed and it seems the only way to actually know when the orientation has changed, is to use interval hacks
of(getOrientation()).pipe(
switchMap(current => {
return fromEvent(platformService.window, 'orientationchange').pipe(
map(() => getOrientation()),
);
});
);