feat(core): added afterContentInit, afterViewInit, and afterViewChecked hooks
Closes #3897
This commit is contained in:
@ -27,7 +27,10 @@ Map<String, dynamic> directiveMetadataToMap(RenderDirectiveMetadata meta) {
|
||||
["callDoCheck", meta.callDoCheck],
|
||||
["callOnInit", meta.callOnInit],
|
||||
["callOnChanges", meta.callOnChanges],
|
||||
["callAfterContentInit", meta.callAfterContentInit],
|
||||
["callAfterContentChecked", meta.callAfterContentChecked],
|
||||
["callAfterViewInit", meta.callAfterViewInit],
|
||||
["callAfterViewChecked", meta.callAfterViewChecked],
|
||||
["events", meta.events],
|
||||
["changeDetection", meta.changeDetection == null ? null : meta.changeDetection.index],
|
||||
["version", 1]
|
||||
@ -57,7 +60,10 @@ RenderDirectiveMetadata directiveMetadataFromMap(Map<String, dynamic> map) {
|
||||
callDoCheck: (map["callDoCheck"] as bool),
|
||||
callOnChanges: (map["callOnChanges"] as bool),
|
||||
callOnInit: (map["callOnInit"] as bool),
|
||||
callAfterContentInit: (map["callAfterContentInit"] as bool),
|
||||
callAfterContentChecked: (map["callAfterContentChecked"] as bool),
|
||||
callAfterViewInit: (map["callAfterViewInit"] as bool),
|
||||
callAfterViewChecked: (map["callAfterViewChecked"] as bool),
|
||||
events: (_cloneIfPresent(map["events"]) as List<String>),
|
||||
changeDetection: map["changeDetection"] == null ? null
|
||||
: ChangeDetectionStrategy.values[map["changeDetection"] as int]);
|
||||
|
@ -63,7 +63,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
bool _callOnChange;
|
||||
bool _callOnCheck;
|
||||
bool _callOnInit;
|
||||
bool _callAfterContentInit;
|
||||
bool _callAfterContentChecked;
|
||||
bool _callAfterViewInit;
|
||||
bool _callAfterViewChecked;
|
||||
ChangeDetectionStrategy _changeDetection;
|
||||
List<String> _events;
|
||||
|
||||
@ -83,7 +86,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_callOnChange = false;
|
||||
_callOnCheck = false;
|
||||
_callOnInit = false;
|
||||
_callAfterContentInit = false;
|
||||
_callAfterContentChecked = false;
|
||||
_callAfterViewInit = false;
|
||||
_callAfterViewChecked = false;
|
||||
_changeDetection = null;
|
||||
_events = [];
|
||||
}
|
||||
@ -100,7 +106,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
callOnChanges: _callOnChange,
|
||||
callDoCheck: _callOnCheck,
|
||||
callOnInit: _callOnInit,
|
||||
callAfterContentInit: _callAfterContentInit,
|
||||
callAfterContentChecked: _callAfterContentChecked,
|
||||
callAfterViewInit: _callAfterViewInit,
|
||||
callAfterViewChecked: _callAfterViewChecked,
|
||||
changeDetection: _changeDetection,
|
||||
events: _events);
|
||||
|
||||
@ -274,7 +283,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_callOnChange = lifecycleEvents.contains("OnChanges");
|
||||
_callOnCheck = lifecycleEvents.contains("DoCheck");
|
||||
_callOnInit = lifecycleEvents.contains("OnInit");
|
||||
_callAfterContentInit = lifecycleEvents.contains("AfterContentInit");
|
||||
_callAfterContentChecked = lifecycleEvents.contains("AfterContentChecked");
|
||||
_callAfterViewInit = lifecycleEvents.contains("AfterViewInit");
|
||||
_callAfterViewChecked = lifecycleEvents.contains("AfterViewChecked");
|
||||
}
|
||||
|
||||
void _populateEvents(Expression eventsValue) {
|
||||
|
@ -33,13 +33,34 @@ const _ON_INIT_INTERFACES = const [
|
||||
const ClassDescriptor(
|
||||
'OnInit', 'package:angular2/src/core/compiler/interfaces.dart'),
|
||||
];
|
||||
const _ON_ALL_CHANGES_DONE_INTERFACES = const [
|
||||
const _ON_AFTER_CONTENT_INIT_INTERFACES = const [
|
||||
const ClassDescriptor('AfterContentInit', 'package:angular2/angular2.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterContentInit', 'package:angular2/metadata.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterContentInit', 'package:angular2/src/core/compiler/interfaces.dart')
|
||||
];
|
||||
const _ON_AFTER_CONTENT_CHECKED_INTERFACES = const [
|
||||
const ClassDescriptor('AfterContentChecked', 'package:angular2/angular2.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterContentChecked', 'package:angular2/metadata.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterContentChecked', 'package:angular2/src/core/compiler/interfaces.dart')
|
||||
];
|
||||
const _ON_AFTER_VIEW_INIT_INTERFACES = const [
|
||||
const ClassDescriptor('AfterViewInit', 'package:angular2/angular2.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterViewInit', 'package:angular2/metadata.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterViewInit', 'package:angular2/src/core/compiler/interfaces.dart')
|
||||
];
|
||||
const _ON_AFTER_VIEW_CHECKED_INTERFACES = const [
|
||||
const ClassDescriptor('AfterViewChecked', 'package:angular2/angular2.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterViewChecked', 'package:angular2/metadata.dart'),
|
||||
const ClassDescriptor(
|
||||
'AfterViewChecked', 'package:angular2/src/core/compiler/interfaces.dart')
|
||||
];
|
||||
|
||||
/// Checks if a given [Annotation] matches any of the given
|
||||
/// [ClassDescriptors].
|
||||
@ -52,7 +73,10 @@ class InterfaceMatcher extends ClassMatcherBase {
|
||||
..addAll(_ON_DESTROY_INTERFACES)
|
||||
..addAll(_ON_CHECK_INTERFACES)
|
||||
..addAll(_ON_INIT_INTERFACES)
|
||||
..addAll(_ON_ALL_CHANGES_DONE_INTERFACES));
|
||||
..addAll(_ON_AFTER_CONTENT_INIT_INTERFACES)
|
||||
..addAll(_ON_AFTER_CONTENT_CHECKED_INTERFACES)
|
||||
..addAll(_ON_AFTER_VIEW_INIT_INTERFACES)
|
||||
..addAll(_ON_AFTER_VIEW_CHECKED_INTERFACES));
|
||||
}
|
||||
|
||||
/// Checks if an [Identifier] implements [OnChanges].
|
||||
@ -71,7 +95,19 @@ class InterfaceMatcher extends ClassMatcherBase {
|
||||
bool isOnInit(Identifier typeName, AssetId assetId) =>
|
||||
implements(firstMatch(typeName, assetId), _ON_INIT_INTERFACES);
|
||||
|
||||
/// Checks if an [Identifier] implements [AfterContentInit].
|
||||
bool isAfterContentInit(Identifier typeName, AssetId assetId) => implements(
|
||||
firstMatch(typeName, assetId), _ON_AFTER_CONTENT_INIT_INTERFACES);
|
||||
|
||||
/// Checks if an [Identifier] implements [AfterContentChecked].
|
||||
bool isAfterContentChecked(Identifier typeName, AssetId assetId) => implements(
|
||||
firstMatch(typeName, assetId), _ON_ALL_CHANGES_DONE_INTERFACES);
|
||||
firstMatch(typeName, assetId), _ON_AFTER_CONTENT_CHECKED_INTERFACES);
|
||||
|
||||
/// Checks if an [Identifier] implements [AfterViewInit].
|
||||
bool isAfterViewInit(Identifier typeName, AssetId assetId) => implements(
|
||||
firstMatch(typeName, assetId), _ON_AFTER_VIEW_INIT_INTERFACES);
|
||||
|
||||
/// Checks if an [Identifier] implements [AfterViewChecked].
|
||||
bool isAfterViewChecked(Identifier typeName, AssetId assetId) => implements(
|
||||
firstMatch(typeName, assetId), _ON_AFTER_VIEW_CHECKED_INTERFACES);
|
||||
}
|
||||
|
@ -271,10 +271,22 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
|
||||
_ifaceLifecycleEntries.add('${LifecycleEvent.OnInit}');
|
||||
populateImport(name);
|
||||
}
|
||||
if (_interfaceMatcher.isAfterContentInit(name, _assetId)) {
|
||||
_ifaceLifecycleEntries.add('${LifecycleEvent.AfterContentInit}');
|
||||
populateImport(name);
|
||||
}
|
||||
if (_interfaceMatcher.isAfterContentChecked(name, _assetId)) {
|
||||
_ifaceLifecycleEntries.add('${LifecycleEvent.AfterContentChecked}');
|
||||
populateImport(name);
|
||||
}
|
||||
if (_interfaceMatcher.isAfterViewInit(name, _assetId)) {
|
||||
_ifaceLifecycleEntries.add('${LifecycleEvent.AfterViewInit}');
|
||||
populateImport(name);
|
||||
}
|
||||
if (_interfaceMatcher.isAfterViewChecked(name, _assetId)) {
|
||||
_ifaceLifecycleEntries.add('${LifecycleEvent.AfterViewChecked}');
|
||||
populateImport(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -143,15 +143,15 @@ class _CodegenState {
|
||||
var $_CHANGES_LOCAL = null;
|
||||
|
||||
${_records.map(_genRecord).join('')}
|
||||
|
||||
${_names.getAlreadyCheckedName()} = true;
|
||||
}
|
||||
|
||||
${_maybeGenHandleEventInternal()}
|
||||
|
||||
${_genCheckNoChanges()}
|
||||
|
||||
${_maybeGenCallAfterContentChecked()}
|
||||
${_maybeGenAfterContentLifecycleCallbacks()}
|
||||
|
||||
${_maybeGenAfterViewLifecycleCallbacks()}
|
||||
|
||||
${_maybeGenHydrateDirectives()}
|
||||
|
||||
@ -260,19 +260,24 @@ class _CodegenState {
|
||||
'{ $hydrateDirectivesCode $hydrateDetectorsCode }';
|
||||
}
|
||||
|
||||
/// Generates calls to `afterContentChecked` for all `Directive`s that request
|
||||
/// them.
|
||||
String _maybeGenCallAfterContentChecked() {
|
||||
// NOTE(kegluneq): Order is important!
|
||||
var directiveNotifications = _directiveRecords.reversed
|
||||
.where((rec) => rec.callAfterContentChecked)
|
||||
.map((rec) =>
|
||||
'${_names.getDirectiveName(rec.directiveIndex)}.afterContentChecked();');
|
||||
|
||||
String _maybeGenAfterContentLifecycleCallbacks() {
|
||||
var directiveNotifications = _logic.genContentLifecycleCallbacks(_directiveRecords);
|
||||
if (directiveNotifications.isNotEmpty) {
|
||||
return '''
|
||||
void callAfterContentChecked() {
|
||||
${_names.getDispatcherName()}.notifyAfterContentChecked();
|
||||
void afterContentLifecycleCallbacksInternal() {
|
||||
${directiveNotifications.join('')}
|
||||
}
|
||||
''';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
String _maybeGenAfterViewLifecycleCallbacks() {
|
||||
var directiveNotifications = _logic.genViewLifecycleCallbacks(_directiveRecords);
|
||||
if (directiveNotifications.isNotEmpty) {
|
||||
return '''
|
||||
void afterViewLifecycleCallbacksInternal() {
|
||||
${directiveNotifications.join('')}
|
||||
}
|
||||
''';
|
||||
|
@ -26,7 +26,10 @@ main() {
|
||||
callOnChanges: true,
|
||||
callDoCheck: true,
|
||||
callOnInit: true,
|
||||
callAfterContentInit: true,
|
||||
callAfterContentChecked: true,
|
||||
callAfterViewInit: true,
|
||||
callAfterViewChecked: true,
|
||||
events: ["onFoo", "onBar"],
|
||||
changeDetection: ChangeDetectionStrategy.CheckOnce);
|
||||
var map = directiveMetadataToMap(someComponent);
|
||||
@ -46,7 +49,10 @@ main() {
|
||||
expect(map["callDoCheck"]).toEqual(true);
|
||||
expect(map["callOnChanges"]).toEqual(true);
|
||||
expect(map["callOnInit"]).toEqual(true);
|
||||
expect(map["callAfterContentInit"]).toEqual(true);
|
||||
expect(map["callAfterContentChecked"]).toEqual(true);
|
||||
expect(map["callAfterViewInit"]).toEqual(true);
|
||||
expect(map["callAfterViewChecked"]).toEqual(true);
|
||||
expect(map["exportAs"]).toEqual("aaa");
|
||||
expect(map["events"]).toEqual(["onFoo", "onBar"]);
|
||||
expect(map["changeDetection"]).toEqual(ChangeDetectionStrategy.CheckOnce.index);
|
||||
@ -67,7 +73,10 @@ main() {
|
||||
["callDoCheck", true],
|
||||
["callOnInit", true],
|
||||
["callOnChanges", true],
|
||||
["callAfterContentInit", true],
|
||||
["callAfterContentChecked", true],
|
||||
["callAfterViewInit", true],
|
||||
["callAfterViewChecked", true],
|
||||
["events", ["onFoo", "onBar"]],
|
||||
["changeDetection", ChangeDetectionStrategy.CheckOnce.index]
|
||||
]);
|
||||
@ -89,7 +98,10 @@ main() {
|
||||
expect(meta.callDoCheck).toEqual(true);
|
||||
expect(meta.callOnInit).toEqual(true);
|
||||
expect(meta.callOnChanges).toEqual(true);
|
||||
expect(meta.callAfterContentInit).toEqual(true);
|
||||
expect(meta.callAfterContentChecked).toEqual(true);
|
||||
expect(meta.callAfterViewInit).toEqual(true);
|
||||
expect(meta.callAfterViewChecked).toEqual(true);
|
||||
expect(meta.events).toEqual(["onFoo", "onBar"]);
|
||||
expect(meta.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
|
||||
});
|
||||
|
@ -106,7 +106,10 @@ void allTests() {
|
||||
expect(metadata.callOnChanges).toBe(true);
|
||||
expect(metadata.callDoCheck).toBe(true);
|
||||
expect(metadata.callOnInit).toBe(true);
|
||||
expect(metadata.callAfterContentInit).toBe(true);
|
||||
expect(metadata.callAfterContentChecked).toBe(true);
|
||||
expect(metadata.callAfterViewInit).toBe(true);
|
||||
expect(metadata.callAfterViewChecked).toBe(true);
|
||||
});
|
||||
|
||||
it('should parse events.', () async {
|
||||
|
@ -17,7 +17,10 @@ void initReflector(reflector) {
|
||||
LifecycleEvent.OnDestroy,
|
||||
LifecycleEvent.OnInit,
|
||||
LifecycleEvent.DoCheck,
|
||||
LifecycleEvent.AfterContentChecked
|
||||
LifecycleEvent.AfterContentInit,
|
||||
LifecycleEvent.AfterContentChecked,
|
||||
LifecycleEvent.AfterViewInit,
|
||||
LifecycleEvent.AfterViewChecked
|
||||
])
|
||||
], const [
|
||||
const []
|
||||
|
@ -52,6 +52,17 @@ void initReflector() {
|
||||
const [],
|
||||
() => new OnInitSoupComponent(),
|
||||
const [OnInit]))
|
||||
..registerType(
|
||||
AfterContentInitSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterContentInit])
|
||||
],
|
||||
const [],
|
||||
() => new AfterContentInitSoupComponent(),
|
||||
const [AfterContentInit]))
|
||||
..registerType(
|
||||
AfterContentCheckedSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
@ -62,5 +73,27 @@ void initReflector() {
|
||||
],
|
||||
const [],
|
||||
() => new AfterContentCheckedSoupComponent(),
|
||||
const [AfterContentChecked]));
|
||||
const [AfterContentChecked]))
|
||||
..registerType(
|
||||
AfterViewInitSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterViewInit])
|
||||
],
|
||||
const [],
|
||||
() => new AfterViewInitSoupComponent(),
|
||||
const [AfterViewInit]))
|
||||
..registerType(
|
||||
AfterViewCheckedSoupComponent,
|
||||
new _ngRef.ReflectionInfo(
|
||||
const [
|
||||
const Component(
|
||||
selector: '[soup]',
|
||||
lifecycle: const [LifecycleEvent.AfterViewChecked])
|
||||
],
|
||||
const [],
|
||||
() => new AfterViewCheckedSoupComponent(),
|
||||
const [AfterViewChecked]));
|
||||
}
|
||||
|
@ -14,5 +14,14 @@ class OnCheckSoupComponent implements DoCheck {}
|
||||
@Component(selector: '[soup]')
|
||||
class OnInitSoupComponent implements OnInit {}
|
||||
|
||||
@Component(selector: '[soup]')
|
||||
class AfterContentInitSoupComponent implements AfterContentInit {}
|
||||
|
||||
@Component(selector: '[soup]')
|
||||
class AfterContentCheckedSoupComponent implements AfterContentChecked {}
|
||||
|
||||
@Component(selector: '[soup]')
|
||||
class AfterViewInitSoupComponent implements AfterViewInit {}
|
||||
|
||||
@Component(selector: '[soup]')
|
||||
class AfterViewCheckedSoupComponent implements AfterViewChecked {}
|
@ -16,7 +16,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
|
@ -66,8 +66,6 @@ class _MyComponent_ChangeDetector0
|
||||
changes = null;
|
||||
|
||||
isChanged = false;
|
||||
|
||||
this.alreadyChecked = true;
|
||||
}
|
||||
|
||||
void checkNoChanges() {
|
||||
|
@ -16,7 +16,10 @@
|
||||
"callDoCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChanges": null,
|
||||
"callAfterContentInit": null,
|
||||
"callAfterContentChecked": null,
|
||||
"callAfterViewInit": null,
|
||||
"callAfterViewChecked": null,
|
||||
"events": ["dependencyEventName"],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -39,7 +42,10 @@
|
||||
"callDoCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChanges": null,
|
||||
"callAfterContentInit": null,
|
||||
"callAfterContentChecked": null,
|
||||
"callAfterViewInit": null,
|
||||
"callAfterViewChecked": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -62,7 +68,10 @@
|
||||
"callDoCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChanges": null,
|
||||
"callAfterContentInit": null,
|
||||
"callAfterContentChecked": null,
|
||||
"callAfterViewInit": null,
|
||||
"callAfterViewChecked": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -85,7 +94,10 @@
|
||||
"callDoCheck": true,
|
||||
"callOnInit": null,
|
||||
"callOnChanges": null,
|
||||
"callAfterContentInit": null,
|
||||
"callAfterContentChecked": null,
|
||||
"callAfterViewInit": null,
|
||||
"callAfterViewChecked": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
|
@ -16,7 +16,10 @@
|
||||
"callDoCheck": null,
|
||||
"callOnInit": null,
|
||||
"callOnChanges": null,
|
||||
"callAfterContentInit": null,
|
||||
"callAfterContentChecked": null,
|
||||
"callAfterViewInit": null,
|
||||
"callAfterViewChecked": null,
|
||||
"events": null,
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -39,7 +42,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -62,7 +68,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": ["eventName"],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -85,7 +94,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -108,7 +120,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -131,7 +146,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -154,7 +172,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
@ -177,7 +198,10 @@
|
||||
"callDoCheck": false,
|
||||
"callOnInit": false,
|
||||
"callOnChanges": false,
|
||||
"callAfterContentInit": false,
|
||||
"callAfterContentChecked": false,
|
||||
"callAfterViewInit": false,
|
||||
"callAfterViewChecked": false,
|
||||
"events": [],
|
||||
"changeDetection": null,
|
||||
"version": 1
|
||||
|
Reference in New Issue
Block a user