benlesh on master
docs: fix typo word 'occurrance… (compare)
benlesh on master
docs(observable.md): add missin… (compare)
benlesh on master
docs(delayWhen): improve docs r… (compare)
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;
});
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?
//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);
});
}
}
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)
);
}
}
ngOnInit()
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 });
})
);
}
tap(()=> statusSubject.next(loading)),
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
from + concatMap + toArray
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!
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
}
*/
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?
Shouldnt
from([])
only result in completion? Seems like it just freezes
yes should be same as EMPTY