feat(core): added support for detecting lifecycle events based on interfaces

This commit is contained in:
vsavkin
2015-05-27 08:08:14 -07:00
parent 2b6a653050
commit 30b6542fc8
12 changed files with 257 additions and 60 deletions
@@ -1,5 +1,5 @@
import {CONST, normalizeBlank, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
import {ListWrapper, List} from 'angular2/src/facade/collection';
import {CONST, CONST_EXPR} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {DEFAULT} from 'angular2/change_detection';
@@ -778,15 +778,6 @@ export class Directive extends Injectable {
this.compileChildren = compileChildren;
this.hostInjector = hostInjector;
}
/**
* Returns true if a directive participates in a given `LifecycleEvent`.
*
* See {@link onChange}, {@link onDestroy}, {@link onAllChangesDone} for details.
*/
hasLifecycleHook(hook: LifecycleEvent): boolean {
return isPresent(this.lifecycle) ? ListWrapper.contains(this.lifecycle, hook) : false;
}
}
/**
@@ -0,0 +1,26 @@
import 'package:angular2/src/core/annotations_impl/annotations.dart';
import 'package:angular2/src/core/compiler/interfaces.dart';
import 'package:angular2/src/reflection/reflection.dart';
bool hasLifecycleHook(LifecycleEvent e, type, Directive annotation) {
if (annotation.lifecycle != null) {
return annotation.lifecycle.contains(e);
} else {
if (type is! Type) return false;
final List interfaces = reflector.interfaces(type);
var interface;
if (e == onChange) {
interface = OnChange;
} else if (e == onDestroy) {
interface = OnDestroy;
} else if (e == onAllChangesDone) {
interface = OnAllChangesDone;
}
return interfaces.contains(interface);
}
}
@@ -0,0 +1,11 @@
import {Type, isPresent} from 'angular2/src/facade/lang';
import {LifecycleEvent, Directive} from 'angular2/src/core/annotations_impl/annotations';
export function hasLifecycleHook(e: LifecycleEvent, type, annotation: Directive): boolean {
if (isPresent(annotation.lifecycle)) {
return annotation.lifecycle.indexOf(e) !== -1;
} else {
if (!(type instanceof Type)) return false;
return e.name in(<any>type).prototype;
}
}
@@ -28,6 +28,7 @@ import {
onDestroy,
onAllChangesDone
} from 'angular2/src/core/annotations_impl/annotations';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {ChangeDetector, ChangeDetectorRef} from 'angular2/change_detection';
import {QueryList} from './query_list';
import {reflector} from 'angular2/src/reflection/reflection';
@@ -282,7 +283,6 @@ export class DirectiveBinding extends ResolvedBinding {
var resolvedViewInjectables = ann instanceof Component && isPresent(ann.viewInjector) ?
resolveBindings(ann.viewInjector) :
[];
var metadata = new DirectiveMetadata({
id: stringify(rb.key.token),
type: ann instanceof
@@ -300,9 +300,11 @@ export class DirectiveBinding extends ResolvedBinding {
null,
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
readAttributes: DirectiveBinding._readAttributes(deps),
callOnDestroy: ann.hasLifecycleHook(onDestroy),
callOnChange: ann.hasLifecycleHook(onChange),
callOnAllChangesDone: ann.hasLifecycleHook(onAllChangesDone),
callOnDestroy: hasLifecycleHook(onDestroy, rb.key.token, ann),
callOnChange: hasLifecycleHook(onChange, rb.key.token, ann),
callOnAllChangesDone: hasLifecycleHook(onAllChangesDone, rb.key.token, ann),
changeDetection: ann instanceof
Component ? ann.changeDetection : null
});
@@ -12,6 +12,7 @@ export interface OnChange { onChange(changes: StringMap<string, any>): void; }
export interface OnDestroy { onDestroy(): void; }
/**
* Defines lifecycle method [onAllChangesDone ] called when the bindings of all its children have been changed.
* Defines lifecycle method [onAllChangesDone ] called when the bindings of all its children have
* been changed.
*/
export interface OnAllChangesDone { onAllChangesDone (): void; }
export interface OnAllChangesDone { onAllChangesDone(): void; }
@@ -1,6 +1,5 @@
library reflection.reflection_capabilities;
import 'reflection.dart';
import 'package:angular2/src/facade/lang.dart';
import 'types.dart';
import 'dart:mirrors';
@@ -97,9 +97,7 @@ export class ReflectionCapabilities {
return [];
}
interfaces(type): List<any> {
throw new BaseException("JavaScript does not support interfaces");
}
interfaces(type): List<any> { throw new BaseException("JavaScript does not support interfaces"); }
getter(name: string): GetterFn { return new Function('o', 'return o.' + name + ';'); }
+27 -14
View File
@@ -1,7 +1,13 @@
import {Type, isPresent, stringify, BaseException} from 'angular2/src/facade/lang';
import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {
List,
ListWrapper,
Map,
MapWrapper,
StringMap,
StringMapWrapper
} from 'angular2/src/facade/collection';
import {SetterFn, GetterFn, MethodFn} from './types';
export {SetterFn, GetterFn, MethodFn} from './types';
export class Reflector {
_typeInfo: Map<Type, any>;
@@ -18,7 +24,7 @@ export class Reflector {
this.reflectionCapabilities = reflectionCapabilities;
}
registerType(type: Type, typeInfo: Map<Type, any>): void {
registerType(type: Type, typeInfo: StringMap<string, any>): void {
MapWrapper.set(this._typeInfo, type, typeInfo);
}
@@ -29,32 +35,32 @@ export class Reflector {
registerMethods(methods: Map<string, MethodFn>): void { _mergeMaps(this._methods, methods); }
factory(type: Type): Function {
if (MapWrapper.contains(this._typeInfo, type)) {
return MapWrapper.get(this._typeInfo, type)["factory"];
if (this._containsTypeInfo(type)) {
return this._getTypeInfoField(type, "factory", null);
} else {
return this.reflectionCapabilities.factory(type);
}
}
parameters(typeOfFunc): List<any> {
if (MapWrapper.contains(this._typeInfo, typeOfFunc)) {
return MapWrapper.get(this._typeInfo, typeOfFunc)["parameters"];
parameters(typeOrFunc): List<any> {
if (MapWrapper.contains(this._typeInfo, typeOrFunc)) {
return this._getTypeInfoField(typeOrFunc, "parameters", []);
} else {
return this.reflectionCapabilities.parameters(typeOfFunc);
return this.reflectionCapabilities.parameters(typeOrFunc);
}
}
annotations(typeOfFunc): List<any> {
if (MapWrapper.contains(this._typeInfo, typeOfFunc)) {
return MapWrapper.get(this._typeInfo, typeOfFunc)["annotations"];
annotations(typeOrFunc): List<any> {
if (MapWrapper.contains(this._typeInfo, typeOrFunc)) {
return this._getTypeInfoField(typeOrFunc, "annotations", []);
} else {
return this.reflectionCapabilities.annotations(typeOfFunc);
return this.reflectionCapabilities.annotations(typeOrFunc);
}
}
interfaces(type): List<any> {
if (MapWrapper.contains(this._typeInfo, type)) {
return MapWrapper.get(this._typeInfo, type)["interfaces"];
return this._getTypeInfoField(type, "interfaces", []);
} else {
return this.reflectionCapabilities.interfaces(type);
}
@@ -83,6 +89,13 @@ export class Reflector {
return this.reflectionCapabilities.method(name);
}
}
_getTypeInfoField(typeOrFunc, key, defaultValue) {
var res = MapWrapper.get(this._typeInfo, typeOrFunc)[key];
return isPresent(res) ? res : defaultValue;
}
_containsTypeInfo(typeOrFunc) { return MapWrapper.contains(this._typeInfo, typeOrFunc); }
}
function _mergeMaps(target: Map<any, any>, config: Map<string, Function>): void {