Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 19:54
    Ore4444 commented #4996
  • 19:53
    Ore4444 closed #4911
  • 19:53
    Ore4444 commented #4911
  • 17:47
    timdp commented #5019
  • 17:04
    timdp commented #5019
  • 16:43
    PDavid edited #5097
  • 16:42
    PDavid edited #5097
  • 16:42
    PDavid synchronize #5097
  • 16:24
    PDavid commented #4406
  • 16:10
    PDavid opened #5097
  • 14:54
    PDavid synchronize #5067
  • 14:43
    mathieucaroff commented #4995
  • 14:39
    mathieucaroff synchronize #4995
  • 14:02
    WLun001 synchronize #5046
  • 13:59
    JWO719 synchronize #4895
  • 13:56

    JWO719 on master

    docs: create example for share … (compare)

  • 13:56
    JWO719 closed #4932
  • 13:56
    JWO719 closed #4797
  • 13:53

    JWO719 on master

    docs(catchError): Enhance descr… (compare)

  • 13:53
    JWO719 closed #4945
Tim Rose
@timrosede
from(this.files).pipe(
      concatMap((file: File) => this.uploadData(file)),
      reduce((acc, res) => acc.concat(res), [])
    ).subscribe((x) => console.log(x));
works
thank you!
Phife
@phife678_twitter
 private getSection(sectionId: string, taskId: string): Observable<Section> {

    const sectionId$ = sectionId
      ? of(sectionId)
      : this.appState$.pipe(select(store.getTask, taskId), take(1))
        .pipe(
          map(task => task.section),
        );

    return sectionId$
      .pipe(
        switchMap(id => this.appState$.pipe(select(store.getSection, id), take(1)))
      );
  }

I'm looking to simplify this function. Here I need to get a section from a stream, but there are 2 cases. In one I have the sectionId already in the second I need to get the sectionId from another stream.

What would be best practice to avoid the ternary operator and do this in one chained statement?

Jorrit
@jorrit-wehelp
iif could replace the ternary
Nico
@ndcunningham
depends how long the ternary is.
like foo ? ... 20 lines : 20 lines
better to split with something like filter in my opinion instead of iif
benbotto
@benbotto
@Dorus @ndcunningham The code you helped me with yesterday used a BehaviorSubject and then was simplified to use iif. Those were close, but when there are two subscribers in rapid succession it incurred two API hits, which is undesirable. I moved back to ReplaySubject like so: https://stackblitz.com/edit/rxjs-up6vzi That seem all right? It no longer loops next/complete to this.replay.
Nico
@ndcunningham
else foo ? ...1-2 lines : ...1-2 lines for sure iif
benbotto
@benbotto
https://stackblitz.com/edit/rxjs-83r9bk?file=index.ts <-- iif version with the issue shown on lines 42 and 45.
Phife
@phife678_twitter
iif works in my example, ty
@ndcunningham but am curious, how would you solve this with a filter operator? if I had a filter like !!sectionIdwouldnt the stream stop instead of switching to the second stream?
Jorrit
@jorrit-wehelp
anything like '... 20 lines' can be encapsulated in a function ;p. But don't really see the filter solution, do see it could also be done with a switchMap, but would do a ternary in that
Phife
@phife678_twitter
yes I'm usually trying to have one line operators since its way more readable that way
Nico
@ndcunningham
@jorrit-wehelp @phife678_twitter
When i say filter i mean filter split it into two observables so it's kinda like a func anyway but each is specialized to it's own condition
a$ = foo$.pipe(filter(baz => !baz));
b$ = foo$.pipe(filter(baz => !!baz));
Nico
@ndcunningham
i didn't read the top my bad context switching between tabs :sweat_smile:
why would it stop?
iif is best i think for your scenario i did add anything extra like merge(a$, b$)
Dorus
@Dorus
@timrosede Why not from()pipe(concatMap(), toArray())?
toArray is pretty much the same as the reduce you used.
Dorus
@Dorus

@ndcunningham

depends how long the ternary is.
like foo ? ... 20 lines : 20 lines

I don't agree. Why not put the two 20 lines blocks in their own function and call condtion() ? fun1() : fun2()?

Also re: iif(). You wont need iif inside a mergeMap selector because that already runs inside the stream, but if youare doing function() { return con ? f1() : f2() } then resubscribing to that observable wont retrigger the conditonal block, thus you can use iff to fix that. Another advantage is that iff evaluate the condition when required because it takes a condition selector (() => condition).

@benbotto Oh good catch, i didn't think of that one. I think that one can be fixed in the iif solution too, but nothing against using replaySubjects. Let me take a quick look at that code.
Dorus
@Dorus
@benbotto I tried to fix it in the iif solution and it got a lot more complicated, to a point where the replay solution is probably better (i had to add subjects xD)
The replay solutions does look correct yes.
For reference, my adapted iif solution
class SomeResourceRecord {
  private lastVal: SomeResource;

  private retriving: Subject<SomeResource>;

  // Get a SomeRes record and cache it until it expires.
  getSomeRes(): Observable<SomeResource> {
    return iif(
      () => this.lastVal !== undefined && this.lastVal.expires > new Date(),
      of(this.lastVal),
      iif(
        () => this.retriving !== undefined,
        defer(() => this.retriving),
        defer(()=> {
          this.retriving = new Subject<SomeResource>();
          return retrieve().pipe(tap(e => {
            this.lastVal = e;
            if(this.retriving) this.retriving.next(e);
          }, (err) => {
            if(this.retriving) this.retriving.error(err);
          }, () => {
            if(this.retriving) this.retriving.complete();
          }), finalize(() => {
            this.retriving = undefined;
          }));
        }))
    );
  }
}
Nico
@ndcunningham

@Dorus

I don't agree. Why not put the two 20 lines blocks in their own function and call condition() ? fun1() : fun2()?

I didn't say i would do that? I was giving a scenario for the ternary not to use the ternary in that scenario
the last solution looks like it's getting longer haha
guess its due to the subject handling
benbotto
@benbotto
@Dorus Thanks for taking a look. Much appreciated.
Dorus
@Dorus
@ndcunningham Yeah the iif wend trough the usual expand when you need to fix a scenrio. I wonder if i could reduce it again given some more thoughts.

But if the replay is unavoidable, it might not be possible.

Another route would be to look at shareReplay, i wonder if that could do something.

Nico
@ndcunningham
Did gitter have an update. It has an annoying way of cropping out the last few words if it breaks on the last line
Dorus
@Dorus
Not for me
Nico
@ndcunningham
Fl
Well I'm not used to it on device lol I'll look when I get home
Hard to read code as well
Dorus
@Dorus
Yeah i'm on desktop
React
@victorpavlenko
I need to make a delay after every 5 calls
5 requests to the server, then a pause of 3 seconds, then continue, all this time events can accumulate
How should I do it? I really need ur help
Wilgert Velinga
@wilgert
You need delayWhen before the map to the http call
observableThatTriggersTheCall.pipe(delayWhen((event, index) => index % 5 === 0 ? of(3000) :of(0)), mergeMap( httpCall ) );
that's just freehand directly into this comment box
so it will probably not work, but should give you a general idea
Wilgert Velinga
@wilgert
Working example stackblitz: https://stackblitz.com/edit/angular-fmclf1
mistake i made before was returing of(3000) instead of timer(3000) from within delaywhen
Dorus
@Dorus

@victorpavlenko There are 2 options.

  1. use concatmap and delay every 5th call by 3 seconds. This will also concat the 5 calls that could potentionanlly be made in parallele.
  2. use mergeMap with concurrent set to 5, and delay all calls by 3 seconds. This wont put a 3 sec delay exactly every 5 calls, but will make sure max 5 calls happen in a 3 second interval.
  3. collect 5 calls with buffer and run them all at once. This does mean you need to delay the calls a little initially to collect 5 of them.

concatMap:

source.pipe(concatMap((e, i) => makeCall(e).pipe(delay(i % 5 === 0 ? 3000 : 0)))))

mergeMap:

source.pipe(mergeMap((e, i) => makeCall(e).pipe(delay(3000)), 5)))

buffer:

source.pipe(bufferCount(5), mergeMap(buf => from(buf).pipe(mergeMap(e => makeCall(e)))))
optional bufferTime shouyld also have a maxBufferSize parameter (it's in the source but not the docs weirdly), this could be used to make the buffer close if collecting 5 items takes too long.
@wilgert Idk but doesn't that just delay every fifth call? So call 1,2,3,4,6,7,8,9 would happen instantly but call 5 and 10 are delayed by 3 seconds? That's not the same as putting a 5 second delay between call 5 and the remaining 5.
Wilgert Velinga
@wilgert
@Dorus I think you're right
but it looks like a concatMap in place of the mergeMap in my example fixes that
see the stackblitz now
React
@victorpavlenko
@Dorus @wilgert Thanks a lot