-
Notifications
You must be signed in to change notification settings - Fork 24.8k
/
ng_onchanges_feature.ts
116 lines (102 loc) 路 3.95 KB
/
ng_onchanges_feature.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {OnChanges} from '../../interface/lifecycle_hooks';
import {SimpleChange, SimpleChanges} from '../../interface/simple_change';
import {EMPTY_OBJ} from '../../util/empty';
import {DirectiveDef, DirectiveDefFeature} from '../interfaces/definition';
/**
* The NgOnChangesFeature decorates a component with support for the ngOnChanges
* lifecycle hook, so it should be included in any component that implements
* that hook.
*
* If the component or directive uses inheritance, the NgOnChangesFeature MUST
* be included as a feature AFTER {@link InheritDefinitionFeature}, otherwise
* inherited properties will not be propagated to the ngOnChanges lifecycle
* hook.
*
* Example usage:
*
* ```
* static 傻cmp = defineComponent({
* ...
* inputs: {name: 'publicName'},
* features: [NgOnChangesFeature]
* });
* ```
*
* @codeGenApi
*/
export function 傻傻NgOnChangesFeature<T>(): DirectiveDefFeature {
return NgOnChangesFeatureImpl;
}
export function NgOnChangesFeatureImpl<T>(definition: DirectiveDef<T>) {
if (definition.type.prototype.ngOnChanges) {
definition.setInput = ngOnChangesSetInput;
}
return rememberChangeHistoryAndInvokeOnChangesHook;
}
// This option ensures that the ngOnChanges lifecycle hook will be inherited
// from superclasses (in InheritDefinitionFeature).
/** @nocollapse */
// tslint:disable-next-line:no-toplevel-property-access
(傻傻NgOnChangesFeature as DirectiveDefFeature).ngInherit = true;
/**
* This is a synthetic lifecycle hook which gets inserted into `TView.preOrderHooks` to simulate
* `ngOnChanges`.
*
* The hook reads the `NgSimpleChangesStore` data from the component instance and if changes are
* found it invokes `ngOnChanges` on the component instance.
*
* @param this Component instance. Because this function gets inserted into `TView.preOrderHooks`,
* it is guaranteed to be called with component instance.
*/
function rememberChangeHistoryAndInvokeOnChangesHook(this: OnChanges) {
const simpleChangesStore = getSimpleChangesStore(this);
const current = simpleChangesStore?.current;
if (current) {
const previous = simpleChangesStore!.previous;
if (previous === EMPTY_OBJ) {
simpleChangesStore!.previous = current;
} else {
// New changes are copied to the previous store, so that we don't lose history for inputs
// which were not changed this time
for (let key in current) {
previous[key] = current[key];
}
}
simpleChangesStore!.current = null;
this.ngOnChanges(current);
}
}
function ngOnChangesSetInput<T>(
this: DirectiveDef<T>, instance: T, value: any, publicName: string, privateName: string): void {
const simpleChangesStore = getSimpleChangesStore(instance) ||
setSimpleChangesStore(instance, {previous: EMPTY_OBJ, current: null});
const current = simpleChangesStore.current || (simpleChangesStore.current = {});
const previous = simpleChangesStore.previous;
const declaredName = (this.declaredInputs as {[key: string]: string})[publicName];
const previousChange = previous[declaredName];
current[declaredName] = new SimpleChange(
previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
(instance as any)[privateName] = value;
}
const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__';
function getSimpleChangesStore(instance: any): null|NgSimpleChangesStore {
return instance[SIMPLE_CHANGES_STORE] || null;
}
function setSimpleChangesStore(instance: any, store: NgSimpleChangesStore): NgSimpleChangesStore {
return instance[SIMPLE_CHANGES_STORE] = store;
}
/**
* Data structure which is monkey-patched on the component instance and used by `ngOnChanges`
* life-cycle hook to track previous input values.
*/
interface NgSimpleChangesStore {
previous: SimpleChanges;
current: SimpleChanges|null;
}