feat(change_detection): added onInit and onCheck hooks

This commit is contained in:
vsavkin
2015-05-27 10:14:37 -07:00
parent 5d2af54730
commit c39c8ebcd0
22 changed files with 504 additions and 72 deletions

View File

@ -8,5 +8,7 @@ export {
Directive as DirectiveAnnotation,
onDestroy,
onChange,
onCheck,
onInit,
onAllChangesDone
} from '../annotations_impl/annotations';

View File

@ -1077,6 +1077,54 @@ export const onDestroy = CONST_EXPR(new LifecycleEvent("onDestroy"));
*/
export const onChange = CONST_EXPR(new LifecycleEvent("onChange"));
/**
* Notify a directive when it has been checked.
*
* This method is called right after the directive's bindings have been checked,
* and before any of its children's bindings have been checked.
*
* It is invoked every time even when none of the directive's bindings has changed.
*
* ## Example:
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [onCheck]
* })
* class ClassSet {
* onCheck() {
* }
* }
* ```
* @exportedAs angular2/annotations
*/
export const onCheck = CONST_EXPR(new LifecycleEvent("onCheck"));
/**
* Notify a directive when it has been checked the first itme.
*
* This method is called right after the directive's bindings have been checked,
* and before any of its children's bindings have been checked.
*
* It is invoked only once.
*
* ## Example:
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [onInit]
* })
* class ClassSet {
* onInit() {
* }
* }
* ```
* @exportedAs angular2/annotations
*/
export const onInit = CONST_EXPR(new LifecycleEvent("onInit"));
/**
* Notify a directive when the bindings of all its children have been changed.
*

View File

@ -19,6 +19,12 @@ bool hasLifecycleHook(LifecycleEvent e, type, Directive annotation) {
} else if (e == onAllChangesDone) {
interface = OnAllChangesDone;
} else if (e == onCheck) {
interface = OnCheck;
} else if (e == onInit) {
interface = OnInit;
}
return interfaces.contains(interface);

View File

@ -26,6 +26,8 @@ import {
Component,
onChange,
onDestroy,
onCheck,
onInit,
onAllChangesDone
} from 'angular2/src/core/annotations_impl/annotations';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
@ -303,6 +305,8 @@ export class DirectiveBinding extends ResolvedBinding {
callOnDestroy: hasLifecycleHook(onDestroy, rb.key.token, ann),
callOnChange: hasLifecycleHook(onChange, rb.key.token, ann),
callOnCheck: hasLifecycleHook(onCheck, rb.key.token, ann),
callOnInit: hasLifecycleHook(onInit, rb.key.token, ann),
callOnAllChangesDone: hasLifecycleHook(onAllChangesDone, rb.key.token, ann),
changeDetection: ann instanceof

View File

@ -11,6 +11,16 @@ export interface OnChange { onChange(changes: StringMap<string, any>): void; }
*/
export interface OnDestroy { onDestroy(): void; }
/**
* Defines lifecycle method [onCheck] called when a directive is being checked.
*/
export interface OnCheck { onCheck(): void; }
/**
* Defines lifecycle method [onInit] called when a directive is being checked the first time.
*/
export interface OnInit { onInit(): void; }
/**
* Defines lifecycle method [onAllChangesDone ] called when the bindings of all its children have
* been changed.

View File

@ -85,17 +85,27 @@ class BindingRecordsCreator {
for (var i = 0; i < directiveBinders.length; i++) {
var directiveBinder = directiveBinders[i];
var directiveMetadata = allDirectiveMetadatas[directiveBinder.directiveIndex];
var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, directiveMetadata);
// directive properties
MapWrapper.forEach(directiveBinder.propertyBindings, (astWithSource, propertyName) => {
// TODO: these setters should eventually be created by change detection, to make
// it monomorphic!
var setter = reflector.setter(propertyName);
var directiveRecord = this._getDirectiveRecord(boundElementIndex, i, directiveMetadata);
ListWrapper.push(bindings, BindingRecord.createForDirective(astWithSource, propertyName,
setter, directiveRecord));
});
if (directiveRecord.callOnChange) {
ListWrapper.push(bindings, BindingRecord.createDirectiveOnChange(directiveRecord));
}
if (directiveRecord.callOnInit) {
ListWrapper.push(bindings, BindingRecord.createDirectiveOnInit(directiveRecord));
}
if (directiveRecord.callOnCheck) {
ListWrapper.push(bindings, BindingRecord.createDirectiveOnCheck(directiveRecord));
}
// host properties
MapWrapper.forEach(directiveBinder.hostPropertyBindings, (astWithSource, propertyName) => {
var dirIndex = new DirectiveIndex(boundElementIndex, i);
@ -110,12 +120,14 @@ class BindingRecordsCreator {
var id = boundElementIndex * 100 + directiveIndex;
if (!MapWrapper.contains(this._directiveRecordsMap, id)) {
var changeDetection = directiveMetadata.changeDetection;
MapWrapper.set(this._directiveRecordsMap, id,
new DirectiveRecord(new DirectiveIndex(boundElementIndex, directiveIndex),
directiveMetadata.callOnAllChangesDone,
directiveMetadata.callOnChange, changeDetection));
MapWrapper.set(this._directiveRecordsMap, id, new DirectiveRecord({
directiveIndex: new DirectiveIndex(boundElementIndex, directiveIndex),
callOnAllChangesDone: directiveMetadata.callOnAllChangesDone,
callOnChange: directiveMetadata.callOnChange,
callOnCheck: directiveMetadata.callOnCheck,
callOnInit: directiveMetadata.callOnInit,
changeDetection: directiveMetadata.changeDetection
}));
}
return MapWrapper.get(this._directiveRecordsMap, id);