feat(core): added afterContentInit, afterViewInit, and afterViewChecked hooks

Closes #3897
This commit is contained in:
vsavkin
2015-08-28 18:11:04 -07:00
committed by Victor Savkin
parent f93cd9ced7
commit d49bc438e8
36 changed files with 974 additions and 253 deletions

View File

@ -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]);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}
});
}

View File

@ -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('')}
}
''';