Skip to content

Instantly share code, notes, and snippets.

@nathan-lapinski
Created December 4, 2018 08:18
Show Gist options
  • Save nathan-lapinski/165756938ada5a0574a8c032735ce8a7 to your computer and use it in GitHub Desktop.
Save nathan-lapinski/165756938ada5a0574a8c032735ce8a7 to your computer and use it in GitHub Desktop.
excerpt
const INITIAL_VALUE = Symbol('INITIAL_VALUE');
declare type INTERIM_VALUES = typeof INITIAL_VALUE | boolean | UrlTree;
export function prioritizedGuardValue():
OperatorFunction<Observable<boolean|UrlTree>[], boolean|UrlTree> {
return switchMap(obs => {
return combineLatest(
...obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE as INTERIM_VALUES))))
.pipe(
scan(
(acc: INTERIM_VALUES, list: INTERIM_VALUES[]) => {
let isPending = false;
return list.reduce((innerAcc, val, i: number) => {
if (innerAcc !== INITIAL_VALUE) return innerAcc;
// Toggle pending flag if any values haven't been set yet
if (val === INITIAL_VALUE) isPending = true;
// Any other return values are only valid if we haven't yet hit a pending call.
// This guarantees that in the case of a guard at the bottom of the tree that
// returns a redirect, we will wait for the higher priority guard at the top to
// finish before performing the redirect.
if (!isPending) {
// Early return when we hit a `false` value as that should always cancel
// navigation
if (val === false) return val;
if (i === list.length - 1 || isUrlTree(val)) {
return val;
}
}
return innerAcc;
}, acc);
},
INITIAL_VALUE),
filter(item => item !== INITIAL_VALUE), // why is INITIAL_VALUE here if it's just filtered? Just to make sure this works with 0 guards?
map(item => isUrlTree(item) ? item : item === true), // why item === true? The return type is just UrlTree or boolean, yea?
take(1)) as Observable<boolean|UrlTree>; // only one guard's UrlTree should win. Is that what this is doing? How are boolean vals handled?
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment