Skip to content

Commit 10b7fde

Browse files
feat(transition): Added transition.paramsChanged() to get added/deleted/changed parameter values for a transition
1 parent fd6e0d8 commit 10b7fde

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

src/transition/transition.ts

+82
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { UIInjector } from '../interface';
3737
import { RawParams } from '../params/interface';
3838
import { ResolvableLiteral } from '../resolve/interface';
3939
import { Rejection } from './rejectFactory';
40+
import { applyPairs, flattenR, uniqR } from '../common';
4041

4142
/** @hidden */
4243
const stateSelf: (_state: StateObject) => StateDeclaration = prop('self');
@@ -286,6 +287,87 @@ export class Transition implements IHookRegistry {
286287
return Object.freeze(this._treeChanges[pathname].map(prop('paramValues')).reduce(mergeR, {}));
287288
}
288289

290+
/**
291+
* Gets the new values of any parameters that changed during this transition.
292+
*
293+
* Returns any parameter values that have changed during a transition, as key/value pairs.
294+
*
295+
* - Any parameter values that have changed will be present on the returned object reflecting the new value.
296+
* - Any parameters that *not* have changed will not be present on the returned object.
297+
* - Any new parameters that weren't present in the "from" state, but are now present in the "to" state will be present on the returned object.
298+
* - Any previous parameters that are no longer present (because the "to" state doesn't have them) will be included with a value of `undefined`.
299+
*
300+
* The returned object is immutable.
301+
*
302+
* #### Examples:
303+
*
304+
* Given:
305+
* ```js
306+
* var stateA = { name: 'stateA', url: '/stateA/:param1/param2' }
307+
* var stateB = { name: 'stateB', url: '/stateB/:param3' }
308+
* var stateC = { name: 'stateB.nest', url: '/nest/:param4' }
309+
* ```
310+
*
311+
* #### Example 1
312+
*
313+
* From `/stateA/abc/def` to `/stateA/abc/xyz`
314+
*
315+
* ```js
316+
* var changed = transition.paramsChanged()
317+
* // changed is { param2: 'xyz' }
318+
* ```
319+
*
320+
* The value of `param2` changed to `xyz`.
321+
* The value of `param1` stayed the same so its value is not present.
322+
*
323+
* #### Example 2
324+
*
325+
* From `/stateA/abc/def` to `/stateB/123`
326+
*
327+
* ```js
328+
* var changed = transition.paramsChanged()
329+
* // changed is { param1: undefined, param2: undefined, param3: '123' }
330+
* ```
331+
*
332+
* The value `param3` is present because it is a new param.
333+
* Both `param1` and `param2` are no longer present so their value is undefined.
334+
*
335+
* #### Example 3
336+
*
337+
* From `/stateB/123` to `/stateB/123/nest/456`
338+
*
339+
* ```js
340+
* var changed = transition.paramsChanged()
341+
* // changed is { param4: '456' }
342+
* ```
343+
*
344+
* The value `param4` is present because it is a new param.
345+
* The value of `param3` did not change, so its value is not present.
346+
*
347+
* @returns an immutable object with changed parameter keys/values.
348+
*/
349+
paramsChanged(): { [paramName: string]: any };
350+
paramsChanged<T>(): T;
351+
paramsChanged() {
352+
const fromParams = this.params('from');
353+
const toParams = this.params('to');
354+
355+
// All the parameters declared on both the "to" and "from" paths
356+
const allParamDescriptors: Param[] = []
357+
.concat(this._treeChanges.to)
358+
.concat(this._treeChanges.from)
359+
.map(pathNode => pathNode.paramSchema)
360+
.reduce(flattenR, [])
361+
.reduce(uniqR, []);
362+
363+
const changedParamDescriptors = Param.changed(allParamDescriptors, fromParams, toParams);
364+
365+
return changedParamDescriptors.reduce((changedValues, descriptor) => {
366+
changedValues[descriptor.id] = toParams[descriptor.id];
367+
return changedValues;
368+
}, {});
369+
}
370+
289371
/**
290372
* Creates a [[UIInjector]] Dependency Injector
291373
*

test/transitionSpec.ts

+68
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,74 @@ describe('transition', function() {
11991199
});
12001200
});
12011201

1202+
describe('paramsChanged()', () => {
1203+
beforeEach(() => {
1204+
router.stateRegistry.register({ name: 'stateA', url: '/stateA/:param1/:param2' });
1205+
router.stateRegistry.register({ name: 'stateB', url: '/stateB/:param3' });
1206+
router.stateRegistry.register({ name: 'stateB.nest', url: '/nest/:param4' });
1207+
});
1208+
1209+
it('should contain only changed param values', async done => {
1210+
await $state.go('stateA', { param1: 'abc', param2: 'def' });
1211+
const goPromise = $state.go('stateA', { param1: 'abc', param2: 'xyz' });
1212+
await goPromise;
1213+
1214+
const changed = goPromise.transition.paramsChanged();
1215+
expect(Object.keys(changed)).toEqual(['param2']);
1216+
expect(changed).toEqual({ param2: 'xyz' });
1217+
1218+
done();
1219+
});
1220+
1221+
it('should contain new params values when switching states', async done => {
1222+
await $state.go('stateB', { param3: '123' });
1223+
const goPromise = $state.go('stateB.nest', { param3: '123', param4: '456' });
1224+
await goPromise;
1225+
1226+
const changed = goPromise.transition.paramsChanged();
1227+
expect(Object.keys(changed)).toEqual(['param4']);
1228+
expect(changed).toEqual({ param4: '456' });
1229+
1230+
done();
1231+
});
1232+
1233+
it('should contain removed params with `undefined` when switching states', async done => {
1234+
await $state.go('stateB.nest', { param3: '123', param4: '456' });
1235+
const goPromise = $state.go('stateB');
1236+
await goPromise;
1237+
1238+
const changed = goPromise.transition.paramsChanged();
1239+
expect(Object.keys(changed)).toEqual(['param4']);
1240+
expect(changed).toEqual({ param4: undefined });
1241+
1242+
done();
1243+
});
1244+
1245+
it('should contain removed params with `undefined` when switching states', async done => {
1246+
await $state.go('stateB.nest', { param3: '123', param4: '456' });
1247+
const goPromise = $state.go('stateB');
1248+
await goPromise;
1249+
1250+
const changed = goPromise.transition.paramsChanged();
1251+
expect(Object.keys(changed)).toEqual(['param4']);
1252+
expect(changed).toEqual({ param4: undefined });
1253+
1254+
done();
1255+
});
1256+
1257+
it('should contain added and removed params', async done => {
1258+
await $state.go('stateB.nest', { param3: '123', param4: '456' });
1259+
const goPromise = $state.go('stateA', { param1: 'abc', param2: 'def' });
1260+
await goPromise;
1261+
1262+
const changed = goPromise.transition.paramsChanged();
1263+
expect(Object.keys(changed).sort()).toEqual(['param1', 'param2', 'param3', 'param4']);
1264+
expect(changed).toEqual({ param1: 'abc', param2: 'def', param3: undefined, param4: undefined });
1265+
1266+
done();
1267+
});
1268+
});
1269+
12021270
describe('from previous transitions', () => {
12031271
it('should get their Transition resolves cleaned up', async done => {
12041272
router.stateRegistry.register({ name: 'resolve', resolve: { foo: () => 'Some data' } });

0 commit comments

Comments
 (0)