refactor(LifecycleEvent): remove LifecycleEvent

fixes #3924

BREAKING CHANGE

The `lifecycle` configuration for directive has been dropped.

Before

    // Dart
    @Component({lifecycle: const [LifecycleEvent.OnChanges], ...})
    class MyComponent implements OnChanges {
      void onChanges() {...}
    }

    // Typescript
    @Component({lifecycle: [LifecycleEvent.OnChanges], ...})
    class MyComponent implements OnChanges {
      onChanges(): void {...}
    }

    // ES5
    var MyComponent = ng.
    Component({lifecycle: [LifecycleEvent.OnChanges], ...}).
    Class({
      onChanges: function() {...}
    });

After

    // Dart
    @Component({...})
    class MyComponent implements OnChanges {
      void onChanges() {...}
    }

    // Typescript
    @Component({...})
    class MyComponent implements OnChanges {
      onChanges(): void {...}
    }

    // ES5
    var MyComponent = ng
      .Component({...})
      .Class({
        onChanges: function() {
        }
      });
This commit is contained in:
Victor Berchet
2015-08-31 18:32:32 -07:00
parent 67b9414268
commit 8302afffb4
42 changed files with 311 additions and 842 deletions

View File

@ -1,36 +1,9 @@
library angular2.src.core.compiler.directive_lifecycle_reflector;
import 'package:angular2/src/core/metadata.dart';
import 'package:angular2/src/core/compiler/interfaces.dart';
import 'package:angular2/src/core/reflection/reflection.dart';
bool hasLifecycleHook(LifecycleEvent e, type, DirectiveMetadata annotation) {
if (annotation.lifecycle != null) {
return annotation.lifecycle.contains(e);
} else {
if (type is! Type) return false;
bool hasLifecycleHook(/*LifecycleHook*/ interface, type) {
if (type is! Type) return false;
final List interfaces = reflector.interfaces(type);
var interface;
if (e == LifecycleEvent.OnChanges) {
interface = OnChanges;
} else if (e == LifecycleEvent.OnDestroy) {
interface = OnDestroy;
} else if (e == LifecycleEvent.AfterContentInit) {
interface = AfterContentInit;
} else if (e == LifecycleEvent.AfterContentChecked) {
interface = AfterContentChecked;
} else if (e == LifecycleEvent.AfterViewInit) {
interface = AfterViewInit;
} else if (e == LifecycleEvent.AfterViewChecked) {
interface = AfterViewChecked;
} else if (e == LifecycleEvent.DoCheck) {
interface = DoCheck;
} else if (e == LifecycleEvent.OnInit) {
interface = OnInit;
}
return interfaces.contains(interface);
}
return reflector.interfaces(type).contains(interface);
}

View File

@ -1,31 +1,29 @@
import {Type, isPresent} from 'angular2/src/core/facade/lang';
import {LifecycleEvent, DirectiveMetadata} from 'angular2/metadata';
import {Type} from 'angular2/src/core/facade/lang';
import * as Interfaces from './interfaces';
export function hasLifecycleHook(e: LifecycleEvent, type, annotation: DirectiveMetadata): boolean {
if (isPresent(annotation.lifecycle)) {
return annotation.lifecycle.indexOf(e) !== -1;
} else {
if (!(type instanceof Type)) return false;
var proto = (<any>type).prototype;
switch (e) {
case LifecycleEvent.AfterContentInit:
return !!proto.afterContentInit;
case LifecycleEvent.AfterContentChecked:
return !!proto.afterContentChecked;
case LifecycleEvent.AfterViewInit:
return !!proto.afterViewInit;
case LifecycleEvent.AfterViewChecked:
return !!proto.afterViewChecked;
case LifecycleEvent.OnChanges:
return !!proto.onChanges;
case LifecycleEvent.DoCheck:
return !!proto.doCheck;
case LifecycleEvent.OnDestroy:
return !!proto.onDestroy;
case LifecycleEvent.OnInit:
return !!proto.onInit;
default:
return false;
}
export function hasLifecycleHook(lcInterface: Interfaces.LifecycleHook, type): boolean {
if (!(type instanceof Type)) return false;
var proto = (<any>type).prototype;
switch (lcInterface) {
case Interfaces.AfterContentInit:
return !!proto.afterContentInit;
case Interfaces.AfterContentChecked:
return !!proto.afterContentChecked;
case Interfaces.AfterViewInit:
return !!proto.afterViewInit;
case Interfaces.AfterViewChecked:
return !!proto.afterViewChecked;
case Interfaces.OnChanges:
return !!proto.onChanges;
case Interfaces.DoCheck:
return !!proto.doCheck;
case Interfaces.OnDestroy:
return !!proto.onDestroy;
case Interfaces.OnInit:
return !!proto.onInit;
default:
return false;
}
}

View File

@ -39,7 +39,7 @@ import * as avmModule from './view_manager';
import {ViewContainerRef} from './view_container_ref';
import {ElementRef} from './element_ref';
import {TemplateRef} from './template_ref';
import {DirectiveMetadata, ComponentMetadata, LifecycleEvent} from '../metadata/directives';
import {DirectiveMetadata, ComponentMetadata} from '../metadata/directives';
import {hasLifecycleHook} from './directive_lifecycle_reflector';
import {
ChangeDetector,
@ -51,6 +51,8 @@ import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
import {EventConfig} from 'angular2/src/core/render/event_config';
import {PipeBinding} from '../pipes/pipe_binding';
import * as LifecycleHooks from './interfaces';
var _staticKeys;
export class StaticKeys {
@ -160,14 +162,14 @@ export class DirectiveBinding extends ResolvedBinding {
properties: meta.properties,
readAttributes: DirectiveBinding._readAttributes(<any>deps),
callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, token, meta),
callAfterContentChecked: hasLifecycleHook(LifecycleEvent.AfterContentChecked, token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, token, meta),
callOnDestroy: hasLifecycleHook(LifecycleHooks.OnDestroy, token),
callOnChanges: hasLifecycleHook(LifecycleHooks.OnChanges, token),
callDoCheck: hasLifecycleHook(LifecycleHooks.DoCheck, token),
callOnInit: hasLifecycleHook(LifecycleHooks.OnInit, token),
callAfterContentInit: hasLifecycleHook(LifecycleHooks.AfterContentInit, token),
callAfterContentChecked: hasLifecycleHook(LifecycleHooks.AfterContentChecked, token),
callAfterViewInit: hasLifecycleHook(LifecycleHooks.AfterViewInit, token),
callAfterViewChecked: hasLifecycleHook(LifecycleHooks.AfterViewChecked, token),
changeDetection: meta instanceof ComponentMetadata ? meta.changeDetection : null,

View File

@ -1,58 +1,181 @@
import {StringMap} from 'angular2/src/core/facade/collection';
import {global} from 'angular2/src/core/facade/lang';
// This is here only so that after TS transpilation the file is not empty.
// TODO(rado): find a better way to fix this, or remove if likely culprit
// https://github.com/systemjs/systemjs/issues/487 gets closed.
var __ignore_me = global;
/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#OnChanges `LifeCycleEvent.OnChanges`}
* called after all of component's bound properties are updated.
*/
export interface OnChanges { onChanges(changes: StringMap<string, any>): void; }
/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#OnInit `LifeCycleEvent.OnInit`}
* called when a directive is being checked the first time.
* Lifecycle hooks are guaranteed to be called in the following order:
* - `OnChanges` (if any bindings have changed),
* - `OnInit` (after the first check only),
* - `DoCheck`,
* - `AfterContentInit`,
* - `AfterContentChecked`,
* - `OnDestroy` (at the very end before destruction)
*
* // todo(vicb): describe Dart & TS vs JS
*/
export interface OnInit { onInit(): void; }
export interface LifecycleHook {}
/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#DoCheck `LifeCycleEvent.DoCheck`}
* called when a directive is being checked.
* Notify a directive when any of its bindings have changed.
*
* `onChanges` 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 if at least one of the directive's bindings has changed.
*
* ## Example:
*
* ```
* @Component(...)
* class MyComponent implements OnChanges {
* propA;
* propB;
*
* onChanges(changes: {[idx: string, PropertyUpdate]}): void {
* // This will get called after any of the properties have been updated.
* if (changes['propA']) {
* // if propA was updated
* }
* if (changes['propA']) {
* // if propB was updated
* }
* }
* }
* ```
*/
export interface DoCheck { doCheck(): boolean; }
export class OnChanges implements LifecycleHook {
onChanges(changes: StringMap<string, any>): void {}
}
/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#OnDestroy `LifeCycleEvent.OnDestroy`}
* called when a directive is being destroyed.
* Notify a directive when it has been checked the first time.
*
* `onInit` is called right after the directive's bindings have been checked for the first time,
* and before any of its children's bindings have been checked.
*
* It is invoked only once.
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent @implements OnInit {
* onInit(): void {
* }
* }
* ```
*/
export interface OnDestroy { onDestroy(): void; }
export class OnInit implements LifecycleHook {
onInit(): void {}
}
/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterContentInit `LifeCycleEvent.afterContentInit`}
* called when the bindings of all its content children have been checked the first time.
* Overrides the default change detection.
*
* `doCheck()` gets called to check the changes in the directives instead of the default
* change detection mechanism.
*
* It is invoked every time the change detection is triggered.
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements DoCheck {
* doCheck(): void {
* // Custom logic to detect changes
* }
* }
* ```
*/
export interface AfterContentInit { afterContentInit(): void; }
export class DoCheck implements LifecycleHook {
doCheck(): void {}
}
/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterContentChecked `LifeCycleEvent.afterContentChecked`}
* called when the bindings of all its content children have been checked.
* Notify a directive whenever a {@link ViewMetadata} that contains it is destroyed.
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements OnDestroy {
* onDestroy(): void {
* // invoked to notify directive of the containing view destruction.
* }
* }
* ```
*/
export interface AfterContentChecked { afterContentChecked(): void; }
export class OnDestroy implements LifecycleHook {
onDestroy(): void {}
}
/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterViewInit `LifeCycleEvent.afterViewInit`}
* called when the bindings of all its view children have been checked the first time.
* Notify a directive when the bindings of all its content children have been checked the first
* time (whether they have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterContentInit {
* afterContentInit(): void {
* }
* }
* ```
*/
export interface AfterViewInit { afterViewInit(): void; }
export class AfterContentInit implements LifecycleHook {
afterContentInit(): void {}
}
/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterViewChecked `LifeCycleEvent.afterViewChecked`}
* called when the bindings of all its view children have been checked.
* Notify a directive when the bindings of all its content children have been checked (whether
* they have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterContentChecked {
* afterContentChecked(): void {
* }
* }
* ```
*/
export interface AfterViewChecked { afterViewChecked(): void; }
export class AfterContentChecked implements LifecycleHook {
afterContentChecked(): void {}
}
/**
* Notify a directive when the bindings of all its view children have been checked the first time
* (whether they have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterViewInit {
* afterViewInit(): void {
* }
* }
* ```
*/
export class AfterViewInit implements LifecycleHook {
afterViewInit(): void {}
}
/**
* Notify a directive when the bindings of all its view children have been checked (whether they
* have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterViewChecked {
* afterViewChecked(): void {
* }
* }
* ```
*/
export class AfterViewChecked implements LifecycleHook {
afterViewChecked(): void {}
}

View File

@ -1,5 +1,5 @@
import {isPresent, isString, StringWrapper, isBlank} from 'angular2/src/core/facade/lang';
import {Directive, LifecycleEvent} from 'angular2/metadata';
import {Directive, DoCheck, OnDestroy} from 'angular2/metadata';
import {ElementRef} from 'angular2/core';
import {Renderer} from 'angular2/src/core/render/api';
import {
@ -34,12 +34,8 @@ import {
* </div>
* ```
*/
@Directive({
selector: '[ng-class]',
lifecycle: [LifecycleEvent.DoCheck, LifecycleEvent.OnDestroy],
properties: ['rawClass: ng-class', 'initialClasses: class']
})
export class NgClass {
@Directive({selector: '[ng-class]', properties: ['rawClass: ng-class', 'initialClasses: class']})
export class NgClass implements DoCheck, OnDestroy {
private _differ: any;
private _mode: string;
private _initialClasses = [];

View File

@ -1,4 +1,4 @@
import {Directive, LifecycleEvent} from 'angular2/metadata';
import {Directive, DoCheck} from 'angular2/metadata';
import {ViewContainerRef, ViewRef, TemplateRef} from 'angular2/core';
import {ChangeDetectorRef, IterableDiffer, IterableDiffers} from 'angular2/change_detection';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
@ -34,9 +34,8 @@ import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
* - `<li template="ng-for #item of items; #i = index">...</li>`
* - `<template ng-for #item [ng-for-of]="items" #i="index"><li>...</li></template>`
*/
@Directive(
{selector: '[ng-for][ng-for-of]', properties: ['ngForOf'], lifecycle: [LifecycleEvent.DoCheck]})
export class NgFor {
@Directive({selector: '[ng-for][ng-for-of]', properties: ['ngForOf']})
export class NgFor implements DoCheck {
_ngForOf: any;
private _differ: IterableDiffer;

View File

@ -1,4 +1,4 @@
import {Directive, LifecycleEvent} from 'angular2/metadata';
import {Directive, DoCheck} from 'angular2/metadata';
import {ElementRef} from 'angular2/core';
import {KeyValueDiffer, KeyValueDiffers} from 'angular2/change_detection';
import {isPresent, isBlank, print} from 'angular2/src/core/facade/lang';
@ -25,12 +25,8 @@ import {Renderer} from 'angular2/src/core/render/api';
* - `<div [ng-style]="{'text-align': alignExp}"></div>`
* - `<div [ng-style]="styleExp"></div>`
*/
@Directive({
selector: '[ng-style]',
lifecycle: [LifecycleEvent.DoCheck],
properties: ['rawStyle: ng-style']
})
export class NgStyle {
@Directive({selector: '[ng-style]', properties: ['rawStyle: ng-style']})
export class NgStyle implements DoCheck {
_rawStyle;
_differ: KeyValueDiffer;

View File

@ -16,14 +16,13 @@ export "./metadata/view.dart";
class Directive extends DirectiveMetadata {
const Directive({String selector, List<String> properties,
List<String> events, Map<String, String> host,
List<LifecycleEvent> lifecycle, List bindings, String exportAs,
List bindings, String exportAs,
bool compileChildren: true})
: super(
selector: selector,
properties: properties,
events: events,
host: host,
lifecycle: lifecycle,
bindings: bindings,
exportAs: exportAs,
compileChildren: compileChildren);
@ -35,14 +34,13 @@ class Directive extends DirectiveMetadata {
class Component extends ComponentMetadata {
const Component({String selector, List<String> properties,
List<String> events, Map<String, String> host,
List<LifecycleEvent> lifecycle, List bindings, String exportAs,
List bindings, String exportAs,
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
: super(
selector: selector,
properties: properties,
events: events,
host: host,
lifecycle: lifecycle,
bindings: bindings,
exportAs: exportAs,
compileChildren: compileChildren,

View File

@ -13,7 +13,6 @@ export {
ComponentMetadata,
DirectiveMetadata,
PipeMetadata,
LifecycleEvent,
PropertyMetadata,
EventMetadata,
HostBindingMetadata,
@ -33,7 +32,6 @@ import {
ComponentMetadata,
DirectiveMetadata,
PipeMetadata,
LifecycleEvent,
PropertyMetadata,
EventMetadata,
HostBindingMetadata,
@ -142,13 +140,11 @@ export interface ViewDecorator extends TypeDecorator {
export interface DirectiveFactory {
(obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[], bindings?: any[], exportAs?: string,
compileChildren?: boolean;
bindings?: any[], exportAs?: string, compileChildren?: boolean;
}): DirectiveDecorator;
new (obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[], bindings?: any[], exportAs?: string,
compileChildren?: boolean;
bindings?: any[], exportAs?: string, compileChildren?: boolean;
}): DirectiveMetadata;
}
@ -201,7 +197,6 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[],
exportAs?: string,
compileChildren?: boolean,
@ -213,7 +208,6 @@ export interface ComponentFactory {
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[],
exportAs?: string,
compileChildren?: boolean,
@ -545,4 +539,4 @@ export var HostBinding: HostBindingFactory = makePropDecorator(HostBindingMetada
/**
* {@link HostListenerMetadata} factory function.
*/
export var HostListener: HostListenerFactory = makePropDecorator(HostListenerMetadata);
export var HostListener: HostListenerFactory = makePropDecorator(HostListenerMetadata);

View File

@ -630,13 +630,6 @@ export class DirectiveMetadata extends InjectableMetadata {
*/
host: StringMap<string, string>;
/**
* Specifies which lifecycle should be notified to the directive.
*
* See {@link LifecycleEvent} for details.
*/
lifecycle: LifecycleEvent[];
/**
* If set to false the compiler does not compile the children of this directive.
*/
@ -703,14 +696,12 @@ export class DirectiveMetadata extends InjectableMetadata {
exportAs: string;
constructor({
selector, properties, events, host, lifecycle, bindings, exportAs,
compileChildren = true,
selector, properties, events, host, bindings, exportAs, compileChildren = true,
}: {
selector?: string,
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[],
exportAs?: string,
compileChildren?: boolean,
@ -721,7 +712,6 @@ export class DirectiveMetadata extends InjectableMetadata {
this.events = events;
this.host = host;
this.exportAs = exportAs;
this.lifecycle = lifecycle;
this.compileChildren = compileChildren;
this.bindings = bindings;
}
@ -818,13 +808,12 @@ export class ComponentMetadata extends DirectiveMetadata {
*/
viewBindings: any[];
constructor({selector, properties, events, host, exportAs, lifecycle, bindings, viewBindings,
constructor({selector, properties, events, host, exportAs, bindings, viewBindings,
changeDetection = ChangeDetectionStrategy.Default, compileChildren = true}: {
selector?: string,
properties?: string[],
events?: string[],
host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[],
exportAs?: string,
compileChildren?: boolean,
@ -838,7 +827,6 @@ export class ComponentMetadata extends DirectiveMetadata {
host: host,
exportAs: exportAs,
bindings: bindings,
lifecycle: lifecycle,
compileChildren: compileChildren
});
@ -847,206 +835,6 @@ export class ComponentMetadata extends DirectiveMetadata {
}
}
/**
* Lifecycle events are guaranteed to be called in the following order:
* - `OnChanges` (if any bindings have changed),
* - `OnInit` (after the first check only),
* - `DoCheck`,
* - `AfterContentChecked`
* - `AfterContentChecked`
* - `OnDestroy` (at the very end before destruction)
*/
export enum LifecycleEvent {
/**
* Notify a directive when it has been checked the first time.
*
* 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: [LifecycleEvent.OnInit]
* })
* class ClassSet {
* onInit() {
* }
* }
* ```
*/
OnInit,
/**
* Notify a directive whenever a {@link ViewMetadata} that contains it is destroyed.
*
* ## Example
*
* ```
* @Directive({
* ...,
* lifecycle: [LifecycleEvent.OnDestroy]
* })
* class ClassSet {
* onDestroy() {
* // invoked to notify directive of the containing view destruction.
* }
* }
* ```
*/
OnDestroy,
/**
* Notify a directive when any of its bindings have changed.
*
* 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 if at least one of the directive's bindings has changed.
*
* ## Example:
*
* ```
* @Directive({
* selector: '[class-set]',
* properties: [
* 'propA',
* 'propB'
* ],
* lifecycle: [LifecycleEvent.OnChanges]
* })
* class ClassSet {
* propA;
* propB;
* onChanges(changes:{[idx: string, PropertyUpdate]}) {
* // This will get called after any of the properties have been updated.
* if (changes['propA']) {
* // if propA was updated
* }
* if (changes['propA']) {
* // if propB was updated
* }
* }
* }
* ```
*/
OnChanges,
/**
* 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: [LifecycleEvent.DoCheck]
* })
* class ClassSet {
* doCheck() {
* }
* }
* ```
*/
DoCheck,
/**
* Notify a directive when the bindings of all its content children have been checked the first
* time (whether they
* have changed or not).
*
* ## Example
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [LifecycleEvent.AfterContentInit]
* })
* class ClassSet {
*
* afterContentInit() {
* }
*
* }
* ```
*/
AfterContentInit,
/**
* Notify a directive when the bindings of all its content children have been checked (whether
* they
* have changed or not).
*
* ## Example
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [LifecycleEvent.AfterContentChecked]
* })
* class ClassSet {
*
* afterContentChecked() {
* }
*
* }
* ```
*/
AfterContentChecked,
/**
* Notify a directive when the bindings of all its view children have been checked the first time
* (whether they
* have changed or not).
*
* ## Example
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [LifecycleEvent.AfterViewInit]
* })
* class ClassSet {
*
* afterViewInit() {
* }
*
* }
* ```
*/
AfterViewInit,
/**
* Notify a directive when the bindings of all its view children have been checked (whether they
* have changed or not).
*
* ## Example
*
* ```
* @Directive({
* selector: '[class-set]',
* lifecycle: [LifecycleEvent.AfterViewChecked]
* })
* class ClassSet {
*
* afterViewChecked() {
* }
*
* }
* ```
*/
AfterViewChecked
}
/**
* Declare reusable pipe function.
*