Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Aug 10 20:04
    benlesh closed #7010
  • Aug 10 20:04

    benlesh on master

    docs: fix typo word 'occurrance… (compare)

  • Aug 10 20:03

    benlesh on master

    docs(observable.md): add missin… (compare)

  • Aug 10 20:03
    benlesh closed #7026
  • Aug 10 20:02

    benlesh on master

    docs(delayWhen): improve docs r… (compare)

  • Aug 10 20:02
    benlesh closed #6977
  • Aug 10 20:02
    benlesh closed #7028
  • Aug 09 08:09
    nick-bailey-uk commented #2601
  • Aug 09 05:52
    iofedurin edited #7035
  • Aug 09 05:45
    MeetzhDing commented #6926
  • Aug 08 17:39
    bdirito commented #7030
  • Aug 08 17:39
    bdirito commented #7030
  • Aug 08 10:05
    iofedurin edited #7035
  • Aug 08 09:56
    iofedurin edited #7035
  • Aug 08 02:04
    tamtakoe commented #7033
  • Aug 08 02:03
    tamtakoe commented #7033
  • Aug 07 20:05
    iofedurin edited #7035
  • Aug 07 20:05
    iofedurin edited #7035
  • Aug 07 16:13
    iofedurin opened #7035
  • Aug 05 20:09
    jkossis commented #6760
Dominic Watson
@intellix
and I can't start with the fromEvent because I need to know the orientation BEFORE
Dominic Watson
@intellix
omg.... I've figured it out, by using a recursive expand operator
function getOrientationChange$(prev) {
  return fromEvent(window, 'orientationchange').pipe(
    map(() => getOrientation()),
    switchMap(next => {
      return (prev !== next) ? of(next) : timer(0, 50).pipe(
        map(() => getOrientation()),
        filter(next2 => next2 !== prev),
      );
    }),
    take(1),
  );
}

of(getOrientation()).pipe(
  expand(v => getOrientationChange$(v)),
).subscribe(v => {
  console.log(v);
  document.querySelector('#results').innerHTML = v;
});
the magic being that I wanted the whole thing to go back into itself and couldn't figure out how to do it. I needed an initial value to seed it being the tricky part
connor-odoherty
@connor-odoherty

Hey all! I'm in the process of cleaning up a 4 year old codebase and saw that the auth flow uses an observer pattern not found anywhere else in the codebase:

  public login(credentials: LoginCredentials, loginSource = ""): Observable<any> {
    this.loginResponseMessage = null;
    if (...) {
      return observableThrowError("Please provide both a username and a password");
    } else {
      return Observable.create((observer) => {
        let urlSearchString = ".."
        this.http
          .post(this.serverInfo.getServerBaseURL() + "/users/api_sign_in", urlSearchString, { observe: "response" })
          .subscribe(
            (response: HttpResponse<any>) => this.signInHttpDataResponse(response, credentials, observer),
            (err) => {
              console.log(err);
              observer.error("Network error. <br><br>" + err.statusText);
              observer.complete();
            }
          );
      });
    }
  }

  private signInHttpDataResponse(response: HttpResponse<any>, credentials, observer) {
    const responseData = response.body;
    this.loginResponseMessage = responseData.message;
    if (responseData.success == true) {
      const auth_header = response.headers.get("Authorization");
      let jwt_token = null;
      if (auth_header) {
        const header_pair = auth_header.split(" ");
        if (header_pair.length == 2 && header_pair[0] == "Bearer") {
          jwt_token = header_pair[1];
          responseData.email = credentials.email;
          responseData.jwtToken = jwt_token;

          let currentUser = this.userStore.getUserNow();
          if (currentUser.suduAsUser != null) {
            currentUser.suduAsUser = new CurrentUser(responseData);
            this.userStore.setUserWithCurrentUser(currentUser);
          } else {
            this.userStore.setUserWithJSON(responseData);
          }
          observer.next(response);
        } else {
          observer.error({
            message: "The server failed to return a valid authorization token",
          });
        }
      } else {
        observer.error({
          message: "The server failed to return an authorization token",
        });
      }
    } else if (responseData.failureReason && responseData.failureReason == "TWO_FACTOR_REQUIRED") {
      // login failed because two factor is required
      // save the current user data for use by the two factor page and return
      responseData.email = credentials.email;
      // this will store the twoFactorTempId for us
      this.userStore.setUserWithJSON(responseData);
      observer.next(response);
    } else {
      observer.error(responseData);
    }

    observer.complete();
  }

Everywhere else, I've been using a pattern like this:

  public destroyExpenseDocument(expenseToUpdate: Expense, expenseDocument: ExpenseDocument): Observable<any> {
    return this.expenseAccessor.getExpense(expenseToUpdate.uuid).pipe(
      map((expense: Expense) => {
        expense.expense_documents = filter(expense.expense_documents, (doc: ExpenseDocument) => {
          return doc.uuid !== expenseDocument.uuid;
        });
        return expense;
      }),
      mergeMap((expenseHere) => {
        return this.expenseAccessor.setExpense(expenseHere);
      }),
      tap(() => {
        this.hydrateCachedExpenses();
      })
    );
  }

Is there any reason to use the Observer.next pattern instead of the pipe/mergeMap pattern?

I could see the Observer.next pattern making sense if we expected that observer to emit multiple times, but as far as I can tell the conditional tree ensures it will only emit once
Matt Erman
@CodeLiftSleep
So an observable created in a parent component is not subscribable in the child component?
Dorus
@Dorus
@CodeLiftSleep i'm not sure what you mean, rxjs has no concepts of (parent) components.
Matt Erman
@CodeLiftSleep
This doesn't work...header$ is always undefined---why?
//parent class
export class baseComponent implements OnInit {
  header$: Observable<headerData>;

   ngOnIt() {
      header$ = this.store.select(getHeaderData);
   }
}

//child class

export class headerComponent extends baseComponent imlpements OnInit {
   ngOnInit() {
      header$.subscribe(header => { <---- error 'cannot subscribe to undefined'
         console.log(header);
      });
   }
}
Dorus
@Dorus
@connor-odoherty the pattern above is observable.create(), the most advanced for of creating an observable i would usually only recommand if all else fail. Indeed since the code above is just subscribing to this.http.post() and then mapping the error callback and calling a function on next calls, it could have been
  public login(credentials: LoginCredentials, loginSource = ""): Observable<any> {
    this.loginResponseMessage = null;
    if (...) {
      return observableThrowError("Please provide both a username and a password");
    } else {
      return Observable.defer(() => {
        let urlSearchString = ".."
        return this.http
          .post(this.serverInfo.getServerBaseURL() + "/users/api_sign_in", urlSearchString, { observe: "response" })
      }).pipe(
        tap((response: HttpResponse<any>) => this.signInHttpDataResponse(response, credentials, observer),
            err) => console.log(err))
        catchError((err) => "Network error. <br><br>" + err.statusText)
      );
    }
  }
Matt Erman
@CodeLiftSleep
@Dorus how is an obervable declared in the parent class undefined in the child class?
Dorus
@Dorus
@CodeLiftSleep This is angular code, or rather OO code. If i understand this right you override the ngOnInit of the base class in the subclass.
Matt Erman
@CodeLiftSleep
so I would need to do something like super.header$?
Dorus
@Dorus
You would need to do something like super.ngOnInit() or something.
inside ngOnInit()
or at least that's my first guess.
Matt Erman
@CodeLiftSleep
wow...that was an easy fix
it worked
avechuche
@avechuche
Hi, I'm going crazy trying to create an observable with a state to be able to show a loading/error in the UI.
I created combineLatest and works perfectly, the pipe is only on "MyWebServiceWithPossibleError" to prevent the observable (combineLatest) from closing in case of error, the problem is that I don't know how to combine my observable with the web example, any help? thx
combineLatest([
    Observable_One,
    Observable_Two,
    Observable_Three,
  ]).pipe(
    switchMap(([R1, R2, R3]) =>
      this.MyWebServiceWithPossibleError(...)
        .pipe(catchError(() => { return EMPTY }))))    

Web example

export enum ObsevableStatus {
  SUCCESS = 'Success',
  ERROR = 'Error',
  LOADING = 'Loading',
}

export interface ObservableWithStatus<T> {
  status: string;
  data?: T;
  error?: Error;
}

export function observableWithStatus<T>(x: Observable<T>): Observable<ObservableWithStatus<T>> {
  return x.pipe(
    map(x => ({ status: ObsevableStatus.SUCCESS, data: x })),
    startWith({ status: ObsevableStatus.LOADING }),
    catchError(x => {
      return of({ status: ObsevableStatus.ERROR, error: x });
    })
  );
}
Derek
@derekkite
@avechuche you consume the data in two ways. One is the api call results, the second is some status. The second one needs to be sent status from the first. If the status is a subject, the api observable can tell it by calling status Subject.next(status). Before the switchMap tap(()=> statusSubject.next(loading)),
avechuche
@avechuche
@derekkite Perfect, I'm going to try this option. Thank you
Nicholas Cunningham
@ndcunningham
hey all i have a question if i have an array that contains [Ob, Ob, Ob] and i want to unwrap the ob inside the array and still keep the array
what op could i use?
mergeAll?
Nicholas Cunningham
@ndcunningham
  map(accounts => {
                return accounts.map(account => {
                    if (account.productType === AccountSummaryJO.ProductTypeEnum.FRUITS) {
                        return this.store.pipe(select(fromFruits.getFruit(account.fruitId), take(1)));
                    } else {
                        return observableOf(account)
                    }
                })
            }),
            combineAll(),
This is what i am trying
Nicholas Cunningham
@ndcunningham
fixed it nvm :)
used from + concatMap + toArray
Felipe Gasper
@FGasper

Hi all.

So, observables are lazy, which means they don’t have the built-in caching that promises have.

So let’s say I need to request two resources from the server, then when they arrive execute a function that uses the two results.

Let’s also say that I’m going to repeat that request, but this time I can reuse one of those earlier results to save an HTTP call.

With promises this is trivial, but I’m not seeing an intuitive-looking way to do this with observables. I assume this is a fairly common thing … is there a widely-used pattern for such things?

Thank you in advance!

Derek
@derekkite
Look at subjects and replay in the docs. Search on those two terms and there will be observables with the characteristics
Nicholas Cunningham
@ndcunningham
Idk if anyone is around but is there a way to convert an array of strings to an object while keeping the key as the type for that said object ?
const foo = ["alpha", "bravo", "charlie"]
// With these types below 
const fooObj = foo.reduce((acc, curr) => /* convert to object */)
/* 
But fooObj now has type of
 = {
    alpha, 
    bravo,
    charlie
}
*/
Derek
@derekkite
const fooObj = foo.reduce((acc, curr) => acc[curr] = curr, {})
Felipe Gasper
@FGasper

Look at subjects and replay in the docs. Search on those two terms and there will be observables with the characteristics

@derekkite shareReplay() was what I needed. Thank you!

Stephen
@S-Stephen

Hi,
I'm using rxjs in an angular application, which is chaining several combineLatest() observables.

The source observable finishes with a share() (so that the observable is replayed to new subscribers?)

The trouble I'm having is that when I subscribe to the observable in my component I am not seeing extra values that are being added via one of the many combinedLatest calls. The values appear to be in the chain of commands. I log them via tap, however my the output from my subscription appears in the console boefore those log messages and doesn't appear to include the values I suggest should be there.

my code is something like this

obs1$ =  obs$.pipe(
   map( /* some operation */),
   share()
) 

obs2$ = combineLatest(
   [$obs1, $actionx] )
.pipe(
   map(/* reduce the data some way*/)
)

obs3$ = combineLatest(
  [ obs2$, newdata$])
.pipe(
   map(/*insert new data*/)
)

obs3$.subscribe(data => this.myappdata = data)

My current thoughts are that it does seem as though I'm overusing combine latest, what other appraoches can I use and then does the original share() affect when the subscribe reacts?

Jorrit
@jorrit-wehelp
@S-Stephen well, share() does not replay by itself... you add a replay() or use the convenient shareReplay operator :)
Stephen
@S-Stephen
@jorrit-wehelp sorry my mix up. I use share() to prevent the underlying get request to be re-actioned, so when there is a new subscriber it provides the last data? (I only want the last data that was provided, not the history)
Am I correct in understanding that when I subscribe to obs3$ then when there is a newdata$ event the subscribe should run with the new data?
Jorrit
@jorrit-wehelp
No, share does not cache/replay data by itself. I will just keep a single (ref-counted) subscription to the source
as for obs$3, only if obs2$ and newdata$ both have emitted atleast one value
Stephen
@S-Stephen
If obs2$ and newdata$ have emitted a value then newdata$ emits a second value, provided the subscribe happened before all the events, would we expect the subscription action to be called twice, ie with the updated data?
Jorrit
@jorrit-wehelp
yes
Stephen
@S-Stephen
okay thanks, I have some confidence that I'm doing things correctly (thought I have quite a few chained combineLatest -; I'll find the correct idiom later) I can see the data I expect in tap() but not when the observable is piped into async in the component. Looks like something quite subtle (or stupid by me ;-) )
Jorrit
@jorrit-wehelp
if you only subscribe in the asyc pipe that should work, but often the case with combineLatest that you need to give the sources some starting value, so you know for sure everything gets an initial value and you are not waiting on one of them
Stephen
@S-Stephen
Yep the observables are from a BehaviourSubject .asObservable(). I'm subscribing both in the init of the component and using the angular provided pipe in the template. It's a mystery at the moment why the updated data is not coming though ;-(
Lennu Vuolanne
@vuolen
Shouldnt from([]) only result in completion? Seems like it just freezes
Lennu Vuolanne
@vuolen
oops nevermind ^^ fixed it
Dorus
@Dorus
:+1:

Shouldnt from([]) only result in completion? Seems like it just freezes

yes should be same as EMPTY

Nicholas Cunningham
@ndcunningham

@derekkite

const fooObj = foo.reduce((acc, curr) => acc[curr] = curr, {})

This will not have a type on fooObj since we did the {} inside of the reduce

sorry kinda late :sweat_smile:
Tyler
@tkil_gitlab
Hi gang, did switchLatest for previous become switchMap? Thanks in advance.