Skip to content

Commit 926705e

Browse files
jutazchristopherthielen
authored andcommitted
feat(TransitionHook): Pass in transition to HookMatchCriteria (#255)
* Pass in transition to HookMatchCriteria * Updated docs & state types
1 parent 713a0d0 commit 926705e

File tree

5 files changed

+32
-18
lines changed

5 files changed

+32
-18
lines changed

src/common/common.ts

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface TypedMap<T> {
3232
[key: string]: T;
3333
}
3434
export type Predicate<X> = (x?: X) => boolean;
35+
export type PredicateBinary<X, Y> = (x?: X, y?: Y) => boolean;
3536
/**
3637
* An ng1-style injectable
3738
*

src/transition/hookBuilder.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class HookBuilder {
6060
const treeChanges = transition.treeChanges();
6161

6262
// Find all the matching registered hooks for a given hook type
63-
const matchingHooks = this.getMatchingHooks(hookType, treeChanges);
63+
const matchingHooks = this.getMatchingHooks(hookType, treeChanges, transition);
6464
if (!matchingHooks) return [];
6565

6666
const baseHookOptions = <TransitionHookOptions>{
@@ -70,7 +70,7 @@ export class HookBuilder {
7070

7171
const makeTransitionHooks = (hook: RegisteredHook) => {
7272
// Fetch the Nodes that caused this hook to match.
73-
const matches: IMatchingNodes = hook.matches(treeChanges);
73+
const matches: IMatchingNodes = hook.matches(treeChanges, transition);
7474
// Select the PathNode[] that will be used as TransitionHook context objects
7575
const matchingNodes: PathNode[] = matches[hookType.criteriaMatchPath.name];
7676

@@ -108,7 +108,11 @@ export class HookBuilder {
108108
*
109109
* @returns an array of matched [[RegisteredHook]]s
110110
*/
111-
public getMatchingHooks(hookType: TransitionEventType, treeChanges: TreeChanges): RegisteredHook[] {
111+
public getMatchingHooks(
112+
hookType: TransitionEventType,
113+
treeChanges: TreeChanges,
114+
transition: Transition
115+
): RegisteredHook[] {
112116
const isCreate = hookType.hookPhase === TransitionHookPhase.CREATE;
113117

114118
// Instance and Global hook registries
@@ -119,7 +123,7 @@ export class HookBuilder {
119123
.map((reg: IHookRegistry) => reg.getHooks(hookType.name)) // Get named hooks from registries
120124
.filter(assertPredicate(isArray, `broken event named: ${hookType.name}`)) // Sanity check
121125
.reduce(unnestR, []) // Un-nest RegisteredHook[][] to RegisteredHook[] array
122-
.filter(hook => hook.matches(treeChanges)); // Only those satisfying matchCriteria
126+
.filter(hook => hook.matches(treeChanges, transition)); // Only those satisfying matchCriteria
123127
}
124128
}
125129

src/transition/hookRegistry.ts

+9-8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
IMatchingNodes,
1919
HookFn,
2020
} from './interface';
21+
import { Transition } from './transition';
2122
import { StateObject } from '../state/stateObject';
2223
import { TransitionEventType } from './transitionEventType';
2324
import { TransitionService } from './transitionService';
@@ -35,7 +36,7 @@ import { TransitionService } from './transitionService';
3536
* - If a function, matchState calls the function with the state and returns true if the function's result is truthy.
3637
* @returns {boolean}
3738
*/
38-
export function matchState(state: StateObject, criterion: HookMatchCriterion) {
39+
export function matchState(state: StateObject, criterion: HookMatchCriterion, transition: Transition) {
3940
const toMatch = isString(criterion) ? [criterion] : criterion;
4041

4142
function matchGlobs(_state: StateObject) {
@@ -51,7 +52,7 @@ export function matchState(state: StateObject, criterion: HookMatchCriterion) {
5152
}
5253

5354
const matchFn = <any>(isFunction(toMatch) ? toMatch : matchGlobs);
54-
return !!matchFn(state);
55+
return !!matchFn(state, transition);
5556
}
5657

5758
/**
@@ -93,9 +94,9 @@ export class RegisteredHook {
9394
* with `entering: (state) => true` which only matches when a state is actually
9495
* being entered.
9596
*/
96-
private _matchingNodes(nodes: PathNode[], criterion: HookMatchCriterion): PathNode[] {
97+
private _matchingNodes(nodes: PathNode[], criterion: HookMatchCriterion, transition: Transition): PathNode[] {
9798
if (criterion === true) return nodes;
98-
const matching = nodes.filter(node => matchState(node.state, criterion));
99+
const matching = nodes.filter(node => matchState(node.state, criterion, transition));
99100
return matching.length ? matching : null;
100101
}
101102

@@ -132,7 +133,7 @@ export class RegisteredHook {
132133
* };
133134
* ```
134135
*/
135-
private _getMatchingNodes(treeChanges: TreeChanges): IMatchingNodes {
136+
private _getMatchingNodes(treeChanges: TreeChanges, transition: Transition): IMatchingNodes {
136137
const criteria = extend(this._getDefaultMatchCriteria(), this.matchCriteria);
137138
const paths: PathType[] = values(this.tranSvc._pluginapi._getPathTypes());
138139

@@ -144,7 +145,7 @@ export class RegisteredHook {
144145
const path = treeChanges[pathtype.name] || [];
145146
const nodes: PathNode[] = isStateHook ? path : [tail(path)];
146147

147-
mn[pathtype.name] = this._matchingNodes(nodes, criteria[pathtype.name]);
148+
mn[pathtype.name] = this._matchingNodes(nodes, criteria[pathtype.name], transition);
148149
return mn;
149150
},
150151
{} as IMatchingNodes
@@ -157,8 +158,8 @@ export class RegisteredHook {
157158
* @returns an IMatchingNodes object, or null. If an IMatchingNodes object is returned, its values
158159
* are the matching [[PathNode]]s for each [[HookMatchCriterion]] (to, from, exiting, retained, entering)
159160
*/
160-
matches(treeChanges: TreeChanges): IMatchingNodes {
161-
const matches = this._getMatchingNodes(treeChanges);
161+
matches(treeChanges: TreeChanges, transition: Transition): IMatchingNodes {
162+
const matches = this._getMatchingNodes(treeChanges, transition);
162163

163164
// Check if all the criteria matched the TreeChanges object
164165
const allMatched = values(matches).every(identity);

src/transition/interface.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @publicapi @module transition */ /** */
22
import { StateDeclaration } from '../state/interface';
3-
import { Predicate } from '../common/common';
3+
import { PredicateBinary } from '../common/common';
44

55
import { Transition } from './transition';
66
import { StateObject } from '../state/stateObject';
@@ -716,8 +716,8 @@ export interface IHookRegistry {
716716
getHooks(hookName: string): RegisteredHook[];
717717
}
718718

719-
/** A predicate type which tests if a [[StateObject]] passes some test. Returns a boolean. */
720-
export type IStateMatch = Predicate<StateObject>;
719+
/** A predicate type which tests if a [[StateObject]] and [[Transition]] passes some test. Returns a boolean. */
720+
export type IStateMatch = PredicateBinary<StateObject, Transition>;
721721

722722
/**
723723
* This object is used to configure whether or not a Transition Hook is invoked for a particular transition,
@@ -765,6 +765,14 @@ export type IStateMatch = Predicate<StateObject>;
765765
* }
766766
* }
767767
* ```
768+
* #### Example:
769+
* ```js
770+
* // This will match when route is just entered (initial load) or when the state is hard-refreshed
771+
* // by specifying `{refresh: true}` as transition options.
772+
* var match = {
773+
* from: (state, transition) => state.self.name === '' || transition.options().reload
774+
* }
775+
* ```
768776
*
769777
* #### Example:
770778
* ```js
@@ -826,7 +834,7 @@ export interface PathType {
826834
*
827835
* A [[Glob]] string that matches the name of a state.
828836
*
829-
* Or, a function with the signature `function(state) { return matches; }`
837+
* Or, a function with the signature `function(state, transition) { return matches; }`
830838
* which should return a boolean to indicate if a state matches.
831839
*
832840
* Or, `true` to always match

src/transition/transition.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ export class Transition implements IHookRegistry {
247247
return this.is({ to: compare.$to().name, from: compare.$from().name });
248248
}
249249
return !(
250-
(compare.to && !matchState(this.$to(), compare.to)) ||
251-
(compare.from && !matchState(this.$from(), compare.from))
250+
(compare.to && !matchState(this.$to(), compare.to, this)) ||
251+
(compare.from && !matchState(this.$from(), compare.from, this))
252252
);
253253
}
254254

0 commit comments

Comments
 (0)