Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Nov 29 02:24
    robwalch commented #7124
  • Nov 28 23:24
    kwonoj closed #7124
  • Nov 28 19:57
    jakovljevic-mladen closed #6781
  • Nov 28 19:57
    jakovljevic-mladen commented #6781
  • Nov 28 19:49
    kwonoj commented #7124
  • Nov 28 19:48
    robwalch edited #7124
  • Nov 28 19:47
    robwalch edited #7124
  • Nov 28 19:47
    robwalch opened #7124
  • Nov 28 14:31
    anisabboud commented #6781
  • Nov 25 21:01
    DavidWeiss2 commented #6946
  • Nov 25 18:24
    adaico commented #6406
  • Nov 25 18:14
    adaico commented #6406
  • Nov 22 07:31
    bene-we commented #7117
  • Nov 21 18:20
    BrainCrumbz opened #7119
  • Nov 20 04:30
    MeetzhDing synchronize #6926
  • Nov 19 12:25
    tmtron commented #5273
  • Nov 19 02:19
    kwonoj commented #7118
  • Nov 19 01:51
    adellamaggiora commented #7118
  • Nov 18 23:47
    kwonoj closed #7118
  • Nov 18 23:47
    kwonoj commented #7118
Lodewijk Wensveen
@lwensveen
It's a bit weird
there's this subject that's being nexted from a input
    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);
    });
then it calls this setDate from the service
this.onDispatchChanges.next(changes);

    this.onDispatchChanges.pipe(
      debounceTime(600),
      distinctUntilChanged(),
    ).subscribe(dateChanges => {
      this.dispatchChanges(dateChanges);
    });
Then in there it does this
I supppose it's being done like this so you can have the debounce?
Dorus
@Dorus
WHy do you subscribe after you next?
Is it a replay/behavior subject?
Lodewijk Wensveen
@lwensveen
nah it's just a regular subject
Dorus
@Dorus
You should only subscribe once and do it before you call next usually.
Ok regualar subject will forget about your next call, so that subscribe will not receive it. Just saying
common mistake (and a reason why you should avoid subjects)
Lodewijk Wensveen
@lwensveen
But then it will never receive data?
Dorus
@Dorus
yes it will only receive data that has been emitted from the subject after you subscribe.
Lodewijk Wensveen
@lwensveen
Which is none? :S
Dorus
@Dorus
Anyway this is unrelated to your cancel question (that i still do not quite understand)
Lodewijk Wensveen
@lwensveen
rxjs always works great till it doesn't
If I log inside that subscribe it logs like 3 times
at random really
Dorus
@Dorus
then you are calling the subject from somewhere
Lodewijk Wensveen
@lwensveen
Seems it doesn't clear it or something
Dorus
@Dorus
you could add tap() with a log in a few places to see wht's going trough it at each step
Lodewijk Wensveen
@lwensveen
But anyways this is too confusing for me, normally it makes sense but this is really strange, so I might just rewrite it using promises or something
Yeah that's what I did but see ^
Anyways it's still not clear to me what you meant with the next and the pipe?
A subject needs data, so you need to call next, or init it as a behavioursubject?
Dorus
@Dorus
A subject just forwards the next call to any current subscribers when you call next on it.
Lodewijk Wensveen
@lwensveen
Yes correct
Then how would I do that pipe etc without calling next?
Dorus
@Dorus
A subject is a hot primitive, it's both a observer and observable and it contains live data, other than say a cold observable like of(changes) that only holds one value and replays it each time you subscribe. Creating a new execution context each time you do.
If you use a subject, you should subscribe first and call next on it later
It's like, turn on the radio before you broadcase something, else you wont hear it.
Lodewijk Wensveen
@lwensveen
Ahh like that
Dorus
@Dorus
It's the biggest difference between promises and observable. Promises are eager, observable lazy. So with observable nothing happens till you subscribe.
Promises start running right away and store their result.
Aaron Brewer
@spaceribs

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:

  • When all selectors are exhausted, throw an error.
  • Stop executing when any observable completes.

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?

also, some marble tests I've made to describe the the intended output:
  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--#"
    );
  });
Dorus
@Dorus

@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)

Dominic Watson
@intellix
struggling to make something in RxJS and wondering if rubber ducking will help me
so basically, in an ideal world 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
so what I'm trying to create is an observable that emits when it's ACTUALLY changed by jumping into a timer loop and emitting when so
I need to know the current orientation when you start listening, so I have a starting point, and then switch into listening to the orientation change I guess:
of(getOrientation()).pipe(
  switchMap(current => {
    return fromEvent(platformService.window, 'orientationchange').pipe(
      map(() => getOrientation()),
    );
  });
);
if (current !== new) I can straight up emit the new one, but if not, I should change to a timer to keep checking every 50ms:
of(getOrientation()).pipe(
  switchMap(current => {
    return fromEvent(platformService.window, 'orientationchange').pipe(
      map(() => getOrientation()),
      switchMap(newOrientation => {
        return (current !== newOrientation) ? of(newOrientation) : timer(0, 50).pipe(
          ...
        );
      }),
    );
  });
);
Dominic Watson
@intellix
I think the timer should map each iteration to a detected orientation, filter and take 1?
of(getOrientation()).pipe(
  switchMap(current => {
    return fromEvent(platformService.window, 'orientationchange').pipe(
      map(() => getOrientation()),
      switchMap(newOrientation => {
        return (current !== newOrientation) ? newOrientation : timer(0, 50).pipe(
          map(() => getOrientation()),
          filter(v => v === current),
          take(1),
        );
      }),
    );
  });
);
I guess my only problem now is that I'm stuck on the first inner switchMap with the wrong value and it won't work the next times in the future
Dominic Watson
@intellix
maybe this? I start with an initial value and also listen to orientation changes and get the NEXT value too. I use pairwise so I always have the last 2 emits
merge(
  of(getOrientation()),
  fromEvent(platformService.window, 'orientationchange').pipe(map(() => getOrientation())),
).pipe(
  pairwise(),
  switchMap(([prev, next]) => {
    return (prev !== next) ? next : timer(0, 50).pipe(
      map(() => getOrientation()),
      filter(v => v === current),
      take(1),
    );
  }),
);
Dominic Watson
@intellix
but that's not correct cause if I start from PORTRAIT and move to LANSCRAPE and it emits PORTRAIT 2x then it's only corrected in the 2nd part (LANDSCAPE) and when I move back to PORTRAIT it could get stuck waiting forever for PORTRAIT (previous emit) to !== PORTRAIT (next emit)
Dominic Watson
@intellix
it seems like what I need, is for the whole thing to re-run, the fetching of the initial again and the re-attaching of the listener