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

@ -14,7 +14,6 @@ export {
ComponentMetadata, ComponentMetadata,
DirectiveMetadata, DirectiveMetadata,
PipeMetadata, PipeMetadata,
LifecycleEvent,
ViewMetadata, ViewMetadata,
ViewEncapsulation, ViewEncapsulation,
QueryMetadata, QueryMetadata,
@ -50,6 +49,8 @@ export {
} from './src/core/metadata'; } from './src/core/metadata';
export { export {
// todo(vbe): LifecycleHook should not be exposed (fails test.typings)
LifecycleHook,
AfterContentInit, AfterContentInit,
AfterContentChecked, AfterContentChecked,
AfterViewInit, AfterViewInit,

View File

@ -1,36 +1,9 @@
library angular2.src.core.compiler.directive_lifecycle_reflector; 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'; import 'package:angular2/src/core/reflection/reflection.dart';
bool hasLifecycleHook(LifecycleEvent e, type, DirectiveMetadata annotation) { bool hasLifecycleHook(/*LifecycleHook*/ interface, type) {
if (annotation.lifecycle != null) { if (type is! Type) return false;
return annotation.lifecycle.contains(e);
} else {
if (type is! Type) return false;
final List interfaces = reflector.interfaces(type); return reflector.interfaces(type).contains(interface);
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);
}
} }

View File

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

View File

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

View File

@ -1,58 +1,181 @@
import {StringMap} from 'angular2/src/core/facade/collection'; 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`} * Lifecycle hooks are guaranteed to be called in the following order:
* called when a directive is being checked the first time. * - `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`} * Notify a directive when any of its bindings have changed.
* called when a directive is being checked. *
* `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`} * Notify a directive when it has been checked the first time.
* called when a directive is being destroyed. *
* `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 * Overrides the default change detection.
* {@link metadata/LifeCycleEvent#AfterContentInit `LifeCycleEvent.afterContentInit`} *
* called when the bindings of all its content children have been checked the first time. * `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 * Notify a directive whenever a {@link ViewMetadata} that contains it is destroyed.
* {@link metadata/LifeCycleEvent#AfterContentChecked `LifeCycleEvent.afterContentChecked`} *
* called when the bindings of all its content children have been checked. * ## 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 * Notify a directive when the bindings of all its content children have been checked the first
* {@link metadata/LifeCycleEvent#AfterViewInit `LifeCycleEvent.afterViewInit`} * time (whether they have changed or not).
* called when the bindings of all its view children have been checked the first time. *
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterContentInit {
* afterContentInit(): void {
* }
* }
* ```
*/ */
export interface AfterViewInit { afterViewInit(): void; } export class AfterContentInit implements LifecycleHook {
afterContentInit(): void {}
}
/** /**
* Defines lifecycle method * Notify a directive when the bindings of all its content children have been checked (whether
* {@link metadata/LifeCycleEvent#AfterViewChecked `LifeCycleEvent.afterViewChecked`} * they have changed or not).
* called when the bindings of all its view children have been checked. *
* ## 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 {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 {ElementRef} from 'angular2/core';
import {Renderer} from 'angular2/src/core/render/api'; import {Renderer} from 'angular2/src/core/render/api';
import { import {
@ -34,12 +34,8 @@ import {
* </div> * </div>
* ``` * ```
*/ */
@Directive({ @Directive({selector: '[ng-class]', properties: ['rawClass: ng-class', 'initialClasses: class']})
selector: '[ng-class]', export class NgClass implements DoCheck, OnDestroy {
lifecycle: [LifecycleEvent.DoCheck, LifecycleEvent.OnDestroy],
properties: ['rawClass: ng-class', 'initialClasses: class']
})
export class NgClass {
private _differ: any; private _differ: any;
private _mode: string; private _mode: string;
private _initialClasses = []; 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 {ViewContainerRef, ViewRef, TemplateRef} from 'angular2/core';
import {ChangeDetectorRef, IterableDiffer, IterableDiffers} from 'angular2/change_detection'; import {ChangeDetectorRef, IterableDiffer, IterableDiffers} from 'angular2/change_detection';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang'; 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>` * - `<li template="ng-for #item of items; #i = index">...</li>`
* - `<template ng-for #item [ng-for-of]="items" #i="index"><li>...</li></template>` * - `<template ng-for #item [ng-for-of]="items" #i="index"><li>...</li></template>`
*/ */
@Directive( @Directive({selector: '[ng-for][ng-for-of]', properties: ['ngForOf']})
{selector: '[ng-for][ng-for-of]', properties: ['ngForOf'], lifecycle: [LifecycleEvent.DoCheck]}) export class NgFor implements DoCheck {
export class NgFor {
_ngForOf: any; _ngForOf: any;
private _differ: IterableDiffer; 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 {ElementRef} from 'angular2/core';
import {KeyValueDiffer, KeyValueDiffers} from 'angular2/change_detection'; import {KeyValueDiffer, KeyValueDiffers} from 'angular2/change_detection';
import {isPresent, isBlank, print} from 'angular2/src/core/facade/lang'; 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]="{'text-align': alignExp}"></div>`
* - `<div [ng-style]="styleExp"></div>` * - `<div [ng-style]="styleExp"></div>`
*/ */
@Directive({ @Directive({selector: '[ng-style]', properties: ['rawStyle: ng-style']})
selector: '[ng-style]', export class NgStyle implements DoCheck {
lifecycle: [LifecycleEvent.DoCheck],
properties: ['rawStyle: ng-style']
})
export class NgStyle {
_rawStyle; _rawStyle;
_differ: KeyValueDiffer; _differ: KeyValueDiffer;

View File

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

View File

@ -13,7 +13,6 @@ export {
ComponentMetadata, ComponentMetadata,
DirectiveMetadata, DirectiveMetadata,
PipeMetadata, PipeMetadata,
LifecycleEvent,
PropertyMetadata, PropertyMetadata,
EventMetadata, EventMetadata,
HostBindingMetadata, HostBindingMetadata,
@ -33,7 +32,6 @@ import {
ComponentMetadata, ComponentMetadata,
DirectiveMetadata, DirectiveMetadata,
PipeMetadata, PipeMetadata,
LifecycleEvent,
PropertyMetadata, PropertyMetadata,
EventMetadata, EventMetadata,
HostBindingMetadata, HostBindingMetadata,
@ -142,13 +140,11 @@ export interface ViewDecorator extends TypeDecorator {
export interface DirectiveFactory { export interface DirectiveFactory {
(obj: { (obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>, selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[], bindings?: any[], exportAs?: string, bindings?: any[], exportAs?: string, compileChildren?: boolean;
compileChildren?: boolean;
}): DirectiveDecorator; }): DirectiveDecorator;
new (obj: { new (obj: {
selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>, selector?: string, properties?: string[], events?: string[], host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[], bindings?: any[], exportAs?: string, bindings?: any[], exportAs?: string, compileChildren?: boolean;
compileChildren?: boolean;
}): DirectiveMetadata; }): DirectiveMetadata;
} }
@ -201,7 +197,6 @@ export interface ComponentFactory {
properties?: string[], properties?: string[],
events?: string[], events?: string[],
host?: StringMap<string, string>, host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[], bindings?: any[],
exportAs?: string, exportAs?: string,
compileChildren?: boolean, compileChildren?: boolean,
@ -213,7 +208,6 @@ export interface ComponentFactory {
properties?: string[], properties?: string[],
events?: string[], events?: string[],
host?: StringMap<string, string>, host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[], bindings?: any[],
exportAs?: string, exportAs?: string,
compileChildren?: boolean, compileChildren?: boolean,
@ -545,4 +539,4 @@ export var HostBinding: HostBindingFactory = makePropDecorator(HostBindingMetada
/** /**
* {@link HostListenerMetadata} factory function. * {@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>; 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. * 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; exportAs: string;
constructor({ constructor({
selector, properties, events, host, lifecycle, bindings, exportAs, selector, properties, events, host, bindings, exportAs, compileChildren = true,
compileChildren = true,
}: { }: {
selector?: string, selector?: string,
properties?: string[], properties?: string[],
events?: string[], events?: string[],
host?: StringMap<string, string>, host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[], bindings?: any[],
exportAs?: string, exportAs?: string,
compileChildren?: boolean, compileChildren?: boolean,
@ -721,7 +712,6 @@ export class DirectiveMetadata extends InjectableMetadata {
this.events = events; this.events = events;
this.host = host; this.host = host;
this.exportAs = exportAs; this.exportAs = exportAs;
this.lifecycle = lifecycle;
this.compileChildren = compileChildren; this.compileChildren = compileChildren;
this.bindings = bindings; this.bindings = bindings;
} }
@ -818,13 +808,12 @@ export class ComponentMetadata extends DirectiveMetadata {
*/ */
viewBindings: any[]; viewBindings: any[];
constructor({selector, properties, events, host, exportAs, lifecycle, bindings, viewBindings, constructor({selector, properties, events, host, exportAs, bindings, viewBindings,
changeDetection = ChangeDetectionStrategy.Default, compileChildren = true}: { changeDetection = ChangeDetectionStrategy.Default, compileChildren = true}: {
selector?: string, selector?: string,
properties?: string[], properties?: string[],
events?: string[], events?: string[],
host?: StringMap<string, string>, host?: StringMap<string, string>,
lifecycle?: LifecycleEvent[],
bindings?: any[], bindings?: any[],
exportAs?: string, exportAs?: string,
compileChildren?: boolean, compileChildren?: boolean,
@ -838,7 +827,6 @@ export class ComponentMetadata extends DirectiveMetadata {
host: host, host: host,
exportAs: exportAs, exportAs: exportAs,
bindings: bindings, bindings: bindings,
lifecycle: lifecycle,
compileChildren: compileChildren 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. * Declare reusable pipe function.
* *

View File

@ -1,4 +1,4 @@
import {Directive, LifecycleEvent} from 'angular2/metadata'; import {Directive, OnInit, OnDestroy} from 'angular2/metadata';
import {Inject, Host, SkipSelf, forwardRef, Binding} from 'angular2/di'; import {Inject, Host, SkipSelf, forwardRef, Binding} from 'angular2/di';
import {ListWrapper} from 'angular2/src/core/facade/collection'; import {ListWrapper} from 'angular2/src/core/facade/collection';
import {CONST_EXPR} from 'angular2/src/core/facade/lang'; import {CONST_EXPR} from 'angular2/src/core/facade/lang';
@ -52,10 +52,10 @@ const controlGroupBinding =
selector: '[ng-control-group]', selector: '[ng-control-group]',
bindings: [controlGroupBinding], bindings: [controlGroupBinding],
properties: ['name: ng-control-group'], properties: ['name: ng-control-group'],
lifecycle: [LifecycleEvent.OnInit, LifecycleEvent.OnDestroy],
exportAs: 'form' exportAs: 'form'
}) })
export class NgControlGroup extends ControlContainer { export class NgControlGroup extends ControlContainer implements OnInit,
OnDestroy {
_parent: ControlContainer; _parent: ControlContainer;
constructor(@Host() @SkipSelf() _parent: ControlContainer) { constructor(@Host() @SkipSelf() _parent: ControlContainer) {
super(); super();

View File

@ -2,7 +2,7 @@ import {CONST_EXPR} from 'angular2/src/core/facade/lang';
import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async'; import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async';
import {StringMap} from 'angular2/src/core/facade/collection'; import {StringMap} from 'angular2/src/core/facade/collection';
import {Query, Directive, LifecycleEvent} from 'angular2/metadata'; import {Query, Directive, OnChanges, OnDestroy} from 'angular2/metadata';
import {forwardRef, Host, SkipSelf, Binding, Inject, Optional} from 'angular2/di'; import {forwardRef, Host, SkipSelf, Binding, Inject, Optional} from 'angular2/di';
import {ControlContainer} from './control_container'; import {ControlContainer} from './control_container';
@ -76,10 +76,10 @@ const controlNameBinding =
bindings: [controlNameBinding], bindings: [controlNameBinding],
properties: ['name: ngControl', 'model: ngModel'], properties: ['name: ngControl', 'model: ngModel'],
events: ['update: ngModel'], events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnDestroy, LifecycleEvent.OnChanges],
exportAs: 'form' exportAs: 'form'
}) })
export class NgControlName extends NgControl { export class NgControlName extends NgControl implements OnChanges,
OnDestroy {
_parent: ControlContainer; _parent: ControlContainer;
update = new EventEmitter(); update = new EventEmitter();
model: any; model: any;

View File

@ -1,7 +1,7 @@
import {CONST_EXPR} from 'angular2/src/core/facade/lang'; import {CONST_EXPR} from 'angular2/src/core/facade/lang';
import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async'; import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async';
import {Query, Directive, LifecycleEvent} from 'angular2/metadata'; import {Query, Directive, OnChanges} from 'angular2/metadata';
import {forwardRef, Binding, Inject, Optional} from 'angular2/di'; import {forwardRef, Binding, Inject, Optional} from 'angular2/di';
import {NgControl} from './ng_control'; import {NgControl} from './ng_control';
@ -62,10 +62,9 @@ const formControlBinding =
bindings: [formControlBinding], bindings: [formControlBinding],
properties: ['form: ngFormControl', 'model: ngModel'], properties: ['form: ngFormControl', 'model: ngModel'],
events: ['update: ngModel'], events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnChanges],
exportAs: 'form' exportAs: 'form'
}) })
export class NgFormControl extends NgControl { export class NgFormControl extends NgControl implements OnChanges {
form: Control; form: Control;
update = new EventEmitter(); update = new EventEmitter();
_added = false; _added = false;

View File

@ -2,7 +2,7 @@ import {CONST_EXPR} from 'angular2/src/core/facade/lang';
import {ListWrapper} from 'angular2/src/core/facade/collection'; import {ListWrapper} from 'angular2/src/core/facade/collection';
import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async'; import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async';
import {Directive, LifecycleEvent} from 'angular2/metadata'; import {Directive, OnChanges} from 'angular2/metadata';
import {forwardRef, Binding} from 'angular2/di'; import {forwardRef, Binding} from 'angular2/di';
import {NgControl} from './ng_control'; import {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group'; import {NgControlGroup} from './ng_control_group';
@ -84,14 +84,14 @@ const formDirectiveBinding =
selector: '[ng-form-model]', selector: '[ng-form-model]',
bindings: [formDirectiveBinding], bindings: [formDirectiveBinding],
properties: ['form: ng-form-model'], properties: ['form: ng-form-model'],
lifecycle: [LifecycleEvent.OnChanges],
host: { host: {
'(submit)': 'onSubmit()', '(submit)': 'onSubmit()',
}, },
events: ['ngSubmit'], events: ['ngSubmit'],
exportAs: 'form' exportAs: 'form'
}) })
export class NgFormModel extends ControlContainer implements Form { export class NgFormModel extends ControlContainer implements Form,
OnChanges {
form: ControlGroup = null; form: ControlGroup = null;
directives: NgControl[] = []; directives: NgControl[] = [];
ngSubmit = new EventEmitter(); ngSubmit = new EventEmitter();

View File

@ -1,7 +1,7 @@
import {CONST_EXPR} from 'angular2/src/core/facade/lang'; import {CONST_EXPR} from 'angular2/src/core/facade/lang';
import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async'; import {EventEmitter, ObservableWrapper} from 'angular2/src/core/facade/async';
import {Query, Directive, LifecycleEvent} from 'angular2/metadata'; import {Query, Directive, OnChanges} from 'angular2/metadata';
import {forwardRef, Binding, Inject, Optional} from 'angular2/di'; import {forwardRef, Binding, Inject, Optional} from 'angular2/di';
import {NgControl} from './ng_control'; import {NgControl} from './ng_control';
@ -32,10 +32,9 @@ const formControlBinding = CONST_EXPR(new Binding(NgControl, {toAlias: forwardRe
bindings: [formControlBinding], bindings: [formControlBinding],
properties: ['model: ngModel'], properties: ['model: ngModel'],
events: ['update: ngModel'], events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnChanges],
exportAs: 'form' exportAs: 'form'
}) })
export class NgModel extends NgControl { export class NgModel extends NgControl implements OnChanges {
_control = new Control(); _control = new Control();
_added = false; _added = false;
update = new EventEmitter(); update = new EventEmitter();

View File

@ -16,22 +16,10 @@ main() {
.callOnChanges).toBe(true); .callOnChanges).toBe(true);
}); });
it("should be true when the lifecycle includes onChanges", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.OnChanges]))
.callOnChanges).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnChanges) expect(metadata(DirectiveNoHooks, new Directive()).callOnChanges)
.toBe(false); .toBe(false);
}); });
it("should be false when empty lifecycle", () {
expect(metadata(
DirectiveImplementingOnChanges, new Directive(lifecycle: []))
.callOnChanges).toBe(false);
});
}); });
describe("onDestroy", () { describe("onDestroy", () {
@ -40,12 +28,6 @@ main() {
.callOnDestroy).toBe(true); .callOnDestroy).toBe(true);
}); });
it("should be true when the lifecycle includes onDestroy", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.OnDestroy]))
.callOnDestroy).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnDestroy) expect(metadata(DirectiveNoHooks, new Directive()).callOnDestroy)
.toBe(false); .toBe(false);
@ -58,12 +40,6 @@ main() {
.callDoCheck).toBe(true); .callDoCheck).toBe(true);
}); });
it("should be true when the lifecycle includes doCheck", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.DoCheck]))
.callDoCheck).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()).callDoCheck) expect(metadata(DirectiveNoHooks, new Directive()).callDoCheck)
.toBe(false); .toBe(false);
@ -76,12 +52,6 @@ main() {
.callOnInit).toBe(true); .callOnInit).toBe(true);
}); });
it("should be true when the lifecycle includes onInit", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.OnInit])).callOnInit)
.toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnInit) expect(metadata(DirectiveNoHooks, new Directive()).callOnInit)
.toBe(false); .toBe(false);
@ -95,12 +65,6 @@ main() {
.callAfterContentInit).toBe(true); .callAfterContentInit).toBe(true);
}); });
it("should be true when the lifecycle includes afterContentInit", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.AfterContentInit]))
.callAfterContentInit).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()) expect(metadata(DirectiveNoHooks, new Directive())
.callAfterContentInit).toBe(false); .callAfterContentInit).toBe(false);
@ -114,12 +78,6 @@ main() {
.callAfterContentChecked).toBe(true); .callAfterContentChecked).toBe(true);
}); });
it("should be true when the lifecycle includes afterContentChecked", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.AfterContentChecked]))
.callAfterContentChecked).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()) expect(metadata(DirectiveNoHooks, new Directive())
.callAfterContentChecked).toBe(false); .callAfterContentChecked).toBe(false);
@ -133,12 +91,6 @@ main() {
.callAfterViewInit).toBe(true); .callAfterViewInit).toBe(true);
}); });
it("should be true when the lifecycle includes afterViewInit", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.AfterViewInit]))
.callAfterViewInit).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()) expect(metadata(DirectiveNoHooks, new Directive())
.callAfterViewInit).toBe(false); .callAfterViewInit).toBe(false);
@ -152,12 +104,6 @@ main() {
.callAfterViewChecked).toBe(true); .callAfterViewChecked).toBe(true);
}); });
it("should be true when the lifecycle includes afterViewChecked", () {
expect(metadata(DirectiveNoHooks,
new Directive(lifecycle: [LifecycleEvent.AfterViewChecked]))
.callAfterViewChecked).toBe(true);
});
it("should be false otherwise", () { it("should be false otherwise", () {
expect(metadata(DirectiveNoHooks, new Directive()) expect(metadata(DirectiveNoHooks, new Directive())
.callAfterViewChecked).toBe(false); .callAfterViewChecked).toBe(false);

View File

@ -13,7 +13,7 @@ import {
proxy proxy
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {DirectiveMetadata, LifecycleEvent} from 'angular2/src/core/metadata'; import {DirectiveMetadata} from 'angular2/src/core/metadata';
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector'; import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
import {RenderDirectiveMetadata} from 'angular2/src/core/render/api'; import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
@ -30,22 +30,9 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes onChanges", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.OnChanges]}))
.callOnChanges)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnChanges).toBe(false); expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnChanges).toBe(false);
}); });
it("should be false when empty lifecycle", () => {
expect(metadata(DirectiveWithOnChangesMethod, new DirectiveMetadata({lifecycle: []}))
.callOnChanges)
.toBe(false);
});
}); });
describe("onDestroy", () => { describe("onDestroy", () => {
@ -54,13 +41,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes onDestroy", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.OnDestroy]}))
.callOnDestroy)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnDestroy).toBe(false); expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnDestroy).toBe(false);
}); });
@ -72,13 +52,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes onDestroy", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.OnInit]}))
.callOnInit)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnInit).toBe(false); expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnInit).toBe(false);
}); });
@ -90,13 +63,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes doCheck", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.DoCheck]}))
.callDoCheck)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callDoCheck).toBe(false); expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callDoCheck).toBe(false);
}); });
@ -109,13 +75,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes afterContentInit", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterContentInit]}))
.callAfterContentInit)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentInit) expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentInit)
.toBe(false); .toBe(false);
@ -129,13 +88,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes afterContentChecked", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterContentChecked]}))
.callAfterContentChecked)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentChecked) expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentChecked)
.toBe(false); .toBe(false);
@ -150,13 +102,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes afterViewInit", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterViewInit]}))
.callAfterViewInit)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewInit).toBe(false); expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewInit).toBe(false);
}); });
@ -169,13 +114,6 @@ export function main() {
.toBe(true); .toBe(true);
}); });
it("should be true when the lifecycle includes afterViewChecked", () => {
expect(metadata(DirectiveNoHooks,
new DirectiveMetadata({lifecycle: [LifecycleEvent.AfterViewChecked]}))
.callAfterViewChecked)
.toBe(true);
});
it("should be false otherwise", () => { it("should be false otherwise", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewChecked) expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewChecked)
.toBe(false); .toBe(false);
@ -200,7 +138,7 @@ class DirectiveWithOnCheckMethod {
} }
class DirectiveWithOnDestroyMethod { class DirectiveWithOnDestroyMethod {
onDestroy(_) {} onDestroy() {}
} }
class DirectiveWithAfterContentInitMethod { class DirectiveWithAfterContentInitMethod {

View File

@ -20,7 +20,7 @@ import {
import {Injector} from 'angular2/di'; import {Injector} from 'angular2/di';
import {NgIf} from 'angular2/directives'; import {NgIf} from 'angular2/directives';
import {Component, View, ViewMetadata, LifecycleEvent} from 'angular2/metadata'; import {Component, View, ViewMetadata, OnDestroy} from 'angular2/metadata';
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {DOCUMENT} from 'angular2/src/core/render/render'; import {DOCUMENT} from 'angular2/src/core/render/render';
@ -262,13 +262,9 @@ class ChildComp {
class DynamicallyCreatedComponentService {} class DynamicallyCreatedComponentService {}
@Component({ @Component({selector: 'hello-cmp', viewBindings: [DynamicallyCreatedComponentService]})
selector: 'hello-cmp',
viewBindings: [DynamicallyCreatedComponentService],
lifecycle: [LifecycleEvent.OnDestroy]
})
@View({template: "{{greeting}}"}) @View({template: "{{greeting}}"})
class DynamicallyCreatedCmp { class DynamicallyCreatedCmp implements OnDestroy {
greeting: string; greeting: string;
dynamicallyCreatedComponentService: DynamicallyCreatedComponentService; dynamicallyCreatedComponentService: DynamicallyCreatedComponentService;
destroyed: boolean = false; destroyed: boolean = false;

View File

@ -36,7 +36,7 @@ import {
ViewQuery, ViewQuery,
ComponentMetadata, ComponentMetadata,
DirectiveMetadata, DirectiveMetadata,
LifecycleEvent OnDestroy
} from 'angular2/metadata'; } from 'angular2/metadata';
import {bind, Injector, Binding, Optional, Inject, Injectable, Self, SkipSelf, InjectMetadata, Host, HostMetadata, SkipSelfMetadata} from 'angular2/di'; import {bind, Injector, Binding, Optional, Inject, Injectable, Self, SkipSelf, InjectMetadata, Host, HostMetadata, SkipSelfMetadata} from 'angular2/di';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
@ -217,7 +217,7 @@ class B_Needs_A {
constructor(dep) {} constructor(dep) {}
} }
class DirectiveWithDestroy { class DirectiveWithDestroy implements OnDestroy {
onDestroyCounter: number; onDestroyCounter: number;
constructor() { this.onDestroyCounter = 0; } constructor() { this.onDestroyCounter = 0; }
@ -832,7 +832,7 @@ export function main() {
it("should call onDestroy on directives subscribed to this event", () => { it("should call onDestroy on directives subscribed to this event", () => {
var inj = injector(ListWrapper.concat( var inj = injector(ListWrapper.concat(
[DirectiveBinding.createFromType(DirectiveWithDestroy, [DirectiveBinding.createFromType(DirectiveWithDestroy,
new DirectiveMetadata({lifecycle: [LifecycleEvent.OnDestroy]}))], new DirectiveMetadata())],
extraBindings)); extraBindings));
var destroy = inj.get(DirectiveWithDestroy); var destroy = inj.get(DirectiveWithDestroy);
inj.dehydrate(); inj.dehydrate();

View File

@ -266,8 +266,6 @@ class NoPropertyAccess {
@Component( @Component(
selector: 'on-change', selector: 'on-change',
// TODO: needed because of https://github.com/angular/angular/issues/2120
lifecycle: const [LifecycleEvent.OnChanges],
properties: const ['prop']) properties: const ['prop'])
@View(template: '') @View(template: '')
class OnChangeComponent implements OnChanges { class OnChangeComponent implements OnChanges {
@ -300,8 +298,7 @@ class ComponentWithObservableList {
} }
@Directive( @Directive(
selector: 'directive-logging-checks', selector: 'directive-logging-checks')
lifecycle: const [LifecycleEvent.DoCheck])
class DirectiveLoggingChecks implements DoCheck { class DirectiveLoggingChecks implements DoCheck {
Log log; Log log;

View File

@ -13,7 +13,19 @@ import {
TestComponentBuilder TestComponentBuilder
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {Directive, Component, View, ViewMetadata, LifecycleEvent} from 'angular2/metadata'; import {
Directive,
Component,
View,
ViewMetadata,
OnChanges,
OnInit,
DoCheck,
AfterContentInit,
AfterContentChecked,
AfterViewInit,
AfterViewChecked
} from 'angular2/metadata';
export function main() { export function main() {
describe('directive lifecycle integration spec', () => { describe('directive lifecycle integration spec', () => {
@ -47,27 +59,16 @@ export function main() {
} }
@Directive({selector: '[lifecycle-dir]', lifecycle: [LifecycleEvent.DoCheck]}) @Directive({selector: '[lifecycle-dir]'})
class LifecycleDir { class LifecycleDir implements DoCheck {
constructor(private _log: Log) {} constructor(private _log: Log) {}
doCheck() { this._log.add("child_doCheck"); } doCheck() { this._log.add("child_doCheck"); }
} }
@Component({ @Component({selector: "[lifecycle]", properties: ['field']})
selector: "[lifecycle]",
properties: ['field'],
lifecycle: [
LifecycleEvent.OnChanges,
LifecycleEvent.OnInit,
LifecycleEvent.DoCheck,
LifecycleEvent.AfterContentInit,
LifecycleEvent.AfterContentChecked,
LifecycleEvent.AfterViewInit,
LifecycleEvent.AfterViewChecked
]
})
@View({template: `<div lifecycle-dir></div>`, directives: [LifecycleDir]}) @View({template: `<div lifecycle-dir></div>`, directives: [LifecycleDir]})
class LifecycleCmp { class LifecycleCmp implements OnChanges, OnInit, DoCheck, AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked {
field; field;
constructor(private _log: Log) {} constructor(private _log: Log) {}

View File

@ -1,4 +1,4 @@
import {Component, View, LifecycleEvent, ViewEncapsulation} from 'angular2/angular2'; import {Component, View, LifecycleEvent, ViewEncapsulation, OnChanges} from 'angular2/angular2';
import {TimerWrapper} from 'angular2/src/core/facade/async'; import {TimerWrapper} from 'angular2/src/core/facade/async';
import {isPresent} from 'angular2/src/core/facade/lang'; import {isPresent} from 'angular2/src/core/facade/lang';
@ -48,7 +48,6 @@ export class MdButton {
@Component({ @Component({
selector: 'a[md-button], a[md-raised-button], a[md-fab]', selector: 'a[md-button], a[md-raised-button], a[md-fab]',
properties: ['disabled'], properties: ['disabled'],
lifecycle: [LifecycleEvent.OnChanges],
host: { host: {
'(click)': 'onClick($event)', '(click)': 'onClick($event)',
'(mousedown)': 'onMousedown()', '(mousedown)': 'onMousedown()',
@ -63,7 +62,7 @@ export class MdButton {
templateUrl: 'package:angular2_material/src/components/button/button.html', templateUrl: 'package:angular2_material/src/components/button/button.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdAnchor extends MdButton { export class MdAnchor extends MdButton implements OnChanges {
tabIndex: number; tabIndex: number;
/** Whether the component is disabled. */ /** Whether the component is disabled. */

View File

@ -4,7 +4,9 @@ import {
ViewEncapsulation, ViewEncapsulation,
Host, Host,
SkipSelf, SkipSelf,
LifecycleEvent OnChanges,
OnDestroy,
AfterContentChecked
} from 'angular2/angular2'; } from 'angular2/angular2';
import {ListWrapper} from 'angular2/src/core/facade/collection'; import {ListWrapper} from 'angular2/src/core/facade/collection';
@ -25,16 +27,12 @@ class RowHeightMode {
} }
@Component({ @Component({selector: 'md-grid-list', properties: ['cols', 'rowHeight', 'gutterSize']})
selector: 'md-grid-list',
properties: ['cols', 'rowHeight', 'gutterSize'],
lifecycle: [LifecycleEvent.AfterContentChecked]
})
@View({ @View({
templateUrl: 'package:angular2_material/src/components/grid_list/grid_list.html', templateUrl: 'package:angular2_material/src/components/grid_list/grid_list.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdGridList { export class MdGridList implements AfterContentChecked {
/** Array of tiles that are being rendered. */ /** Array of tiles that are being rendered. */
tiles: MdGridTile[]; tiles: MdGridTile[];
@ -225,14 +223,14 @@ export class MdGridList {
'[style.left]': 'style.left', '[style.left]': 'style.left',
'[style.marginTop]': 'style.marginTop', '[style.marginTop]': 'style.marginTop',
'[style.paddingTop]': 'style.paddingTop', '[style.paddingTop]': 'style.paddingTop',
}, }
lifecycle: [LifecycleEvent.OnDestroy, LifecycleEvent.OnChanges]
}) })
@View({ @View({
templateUrl: 'package:angular2_material/src/components/grid_list/grid_tile.html', templateUrl: 'package:angular2_material/src/components/grid_list/grid_tile.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdGridTile { export class MdGridTile implements OnDestroy,
OnChanges {
gridList: MdGridList; gridList: MdGridList;
_rowspan: number; _rowspan: number;
_colspan: number; _colspan: number;

View File

@ -1,4 +1,11 @@
import {Directive, LifecycleEvent, Attribute, Host, SkipSelf} from 'angular2/angular2'; import {
Directive,
LifecycleEvent,
Attribute,
Host,
SkipSelf,
AfterContentChecked
} from 'angular2/angular2';
import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async'; import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async';
@ -9,13 +16,12 @@ import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async';
@Directive({ @Directive({
selector: 'md-input-container', selector: 'md-input-container',
lifecycle: [LifecycleEvent.AfterContentChecked],
host: { host: {
'[class.md-input-has-value]': 'inputHasValue', '[class.md-input-has-value]': 'inputHasValue',
'[class.md-input-focused]': 'inputHasFocus', '[class.md-input-focused]': 'inputHasFocus',
} }
}) })
export class MdInputContainer { export class MdInputContainer implements AfterContentChecked {
// The MdInput or MdTextarea inside of this container. // The MdInput or MdTextarea inside of this container.
_input: MdInput; _input: MdInput;

View File

@ -1,9 +1,15 @@
import {Component, LifecycleEvent, View, ViewEncapsulation, Attribute} from 'angular2/angular2'; import {
Component,
LifecycleEvent,
View,
ViewEncapsulation,
Attribute,
OnChanges
} from 'angular2/angular2';
import {CONST} from 'angular2/src/core/facade/lang'; import {CONST} from 'angular2/src/core/facade/lang';
import {isPresent, isBlank} from 'angular2/src/core/facade/lang'; import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {Math} from 'angular2/src/core/facade/math'; import {Math} from 'angular2/src/core/facade/math';
/** Different display / behavior modes for progress-linear. */ /** Different display / behavior modes for progress-linear. */
@CONST() @CONST()
class ProgressMode { class ProgressMode {
@ -15,7 +21,6 @@ class ProgressMode {
@Component({ @Component({
selector: 'md-progress-linear', selector: 'md-progress-linear',
lifecycle: [LifecycleEvent.OnChanges],
properties: ['value', 'bufferValue'], properties: ['value', 'bufferValue'],
host: { host: {
'role': 'progressbar', 'role': 'progressbar',
@ -29,7 +34,7 @@ class ProgressMode {
directives: [], directives: [],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdProgressLinear { export class MdProgressLinear implements OnChanges {
/** Value for the primary bar. */ /** Value for the primary bar. */
value_: number; value_: number;

View File

@ -6,7 +6,9 @@ import {
Host, Host,
SkipSelf, SkipSelf,
Attribute, Attribute,
Optional Optional,
OnChanges,
OnInit
} from 'angular2/angular2'; } from 'angular2/angular2';
import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/core/facade/lang'; import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/core/facade/lang';
@ -33,7 +35,6 @@ var _uniqueIdCounter: number = 0;
@Component({ @Component({
selector: 'md-radio-group', selector: 'md-radio-group',
lifecycle: [LifecycleEvent.OnChanges],
events: ['change'], events: ['change'],
properties: ['disabled', 'value'], properties: ['disabled', 'value'],
host: { host: {
@ -49,7 +50,7 @@ var _uniqueIdCounter: number = 0;
templateUrl: 'package:angular2_material/src/components/radio/radio_group.html', templateUrl: 'package:angular2_material/src/components/radio/radio_group.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdRadioGroup { export class MdRadioGroup implements OnChanges {
/** The selected value for the radio group. The value comes from the options. */ /** The selected value for the radio group. The value comes from the options. */
value: any; value: any;
@ -191,7 +192,6 @@ export class MdRadioGroup {
@Component({ @Component({
selector: 'md-radio-button', selector: 'md-radio-button',
lifecycle: [LifecycleEvent.OnInit],
properties: ['id', 'name', 'value', 'checked', 'disabled'], properties: ['id', 'name', 'value', 'checked', 'disabled'],
host: { host: {
'role': 'radio', 'role': 'radio',
@ -207,7 +207,7 @@ export class MdRadioGroup {
directives: [], directives: [],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class MdRadioButton { export class MdRadioButton implements OnInit {
/** Whether this radio is checked. */ /** Whether this radio is checked. */
checked: boolean; checked: boolean;

View File

@ -1,6 +1,6 @@
import {verifyNoBrowserErrors} from 'angular2/src/test_lib/e2e_util'; import {verifyNoBrowserErrors} from 'angular2/src/test_lib/e2e_util';
describe('Template-Driven Forms', function() { describe('Model-Driven Forms', function() {
afterEach(verifyNoBrowserErrors); afterEach(verifyNoBrowserErrors);

View File

@ -61,7 +61,7 @@ class _DirectiveMetadataVisitor extends Object
String _exportAs; String _exportAs;
bool _callOnDestroy; bool _callOnDestroy;
bool _callOnChange; bool _callOnChange;
bool _callOnCheck; bool _callDoCheck;
bool _callOnInit; bool _callOnInit;
bool _callAfterContentInit; bool _callAfterContentInit;
bool _callAfterContentChecked; bool _callAfterContentChecked;
@ -84,7 +84,7 @@ class _DirectiveMetadataVisitor extends Object
_exportAs = null; _exportAs = null;
_callOnDestroy = false; _callOnDestroy = false;
_callOnChange = false; _callOnChange = false;
_callOnCheck = false; _callDoCheck = false;
_callOnInit = false; _callOnInit = false;
_callAfterContentInit = false; _callAfterContentInit = false;
_callAfterContentChecked = false; _callAfterContentChecked = false;
@ -104,7 +104,7 @@ class _DirectiveMetadataVisitor extends Object
exportAs: _exportAs, exportAs: _exportAs,
callOnDestroy: _callOnDestroy, callOnDestroy: _callOnDestroy,
callOnChanges: _callOnChange, callOnChanges: _callOnChange,
callDoCheck: _callOnCheck, callDoCheck: _callDoCheck,
callOnInit: _callOnInit, callOnInit: _callOnInit,
callAfterContentInit: _callAfterContentInit, callAfterContentInit: _callAfterContentInit,
callAfterContentChecked: _callAfterContentChecked, callAfterContentChecked: _callAfterContentChecked,
@ -170,6 +170,7 @@ class _DirectiveMetadataVisitor extends Object
case 'host': case 'host':
_populateHost(node.expression); _populateHost(node.expression);
break; break;
// TODO(vicb) should come from the interfaces on the class
case 'lifecycle': case 'lifecycle':
_populateLifecycle(node.expression); _populateLifecycle(node.expression);
break; break;
@ -281,7 +282,7 @@ class _DirectiveMetadataVisitor extends Object
var lifecycleEvents = l.elements.map((s) => s.toSource().split('.').last); var lifecycleEvents = l.elements.map((s) => s.toSource().split('.').last);
_callOnDestroy = lifecycleEvents.contains("OnDestroy"); _callOnDestroy = lifecycleEvents.contains("OnDestroy");
_callOnChange = lifecycleEvents.contains("OnChanges"); _callOnChange = lifecycleEvents.contains("OnChanges");
_callOnCheck = lifecycleEvents.contains("DoCheck"); _callDoCheck = lifecycleEvents.contains("DoCheck");
_callOnInit = lifecycleEvents.contains("OnInit"); _callOnInit = lifecycleEvents.contains("OnInit");
_callAfterContentInit = lifecycleEvents.contains("AfterContentInit"); _callAfterContentInit = lifecycleEvents.contains("AfterContentInit");
_callAfterContentChecked = lifecycleEvents.contains("AfterContentChecked"); _callAfterContentChecked = lifecycleEvents.contains("AfterContentChecked");

View File

@ -21,7 +21,7 @@ const _ON_DESTROY_INTERFACES = const [
const ClassDescriptor( const ClassDescriptor(
'OnDestroy', 'package:angular2/src/core/compiler/interfaces.dart'), 'OnDestroy', 'package:angular2/src/core/compiler/interfaces.dart'),
]; ];
const _ON_CHECK_INTERFACES = const [ const _DO_CHECK_INTERFACES = const [
const ClassDescriptor('DoCheck', 'package:angular2/angular2.dart'), const ClassDescriptor('DoCheck', 'package:angular2/angular2.dart'),
const ClassDescriptor('DoCheck', 'package:angular2/metadata.dart'), const ClassDescriptor('DoCheck', 'package:angular2/metadata.dart'),
const ClassDescriptor( const ClassDescriptor(
@ -71,7 +71,7 @@ class InterfaceMatcher extends ClassMatcherBase {
return new InterfaceMatcher._([] return new InterfaceMatcher._([]
..addAll(_ON_CHANGE_INTERFACES) ..addAll(_ON_CHANGE_INTERFACES)
..addAll(_ON_DESTROY_INTERFACES) ..addAll(_ON_DESTROY_INTERFACES)
..addAll(_ON_CHECK_INTERFACES) ..addAll(_DO_CHECK_INTERFACES)
..addAll(_ON_INIT_INTERFACES) ..addAll(_ON_INIT_INTERFACES)
..addAll(_ON_AFTER_CONTENT_INIT_INTERFACES) ..addAll(_ON_AFTER_CONTENT_INIT_INTERFACES)
..addAll(_ON_AFTER_CONTENT_CHECKED_INTERFACES) ..addAll(_ON_AFTER_CONTENT_CHECKED_INTERFACES)
@ -88,8 +88,8 @@ class InterfaceMatcher extends ClassMatcherBase {
implements(firstMatch(typeName, assetId), _ON_DESTROY_INTERFACES); implements(firstMatch(typeName, assetId), _ON_DESTROY_INTERFACES);
/// Checks if an [Identifier] implements [DoCheck]. /// Checks if an [Identifier] implements [DoCheck].
bool isOnCheck(Identifier typeName, AssetId assetId) => bool isDoCheck(Identifier typeName, AssetId assetId) =>
implements(firstMatch(typeName, assetId), _ON_CHECK_INTERFACES); implements(firstMatch(typeName, assetId), _DO_CHECK_INTERFACES);
/// Checks if an [Identifier] implements [OnInit]. /// Checks if an [Identifier] implements [OnInit].
bool isOnInit(Identifier typeName, AssetId assetId) => bool isOnInit(Identifier typeName, AssetId assetId) =>

View File

@ -298,8 +298,7 @@ class _NgDepsDeclarationsVisitor extends Object with SimpleAstVisitor<Object> {
_factoryVisitor = new FactoryTransformVisitor(writer), _factoryVisitor = new FactoryTransformVisitor(writer),
_paramsVisitor = new ParameterTransformVisitor(writer), _paramsVisitor = new ParameterTransformVisitor(writer),
_metaVisitor = new AnnotationsTransformVisitor( _metaVisitor = new AnnotationsTransformVisitor(
writer, xhr, annotationMatcher, interfaceMatcher, assetId, writer, xhr, annotationMatcher, assetId, inlineViews: inlineViews),
inlineViews: inlineViews),
_annotationMatcher = annotationMatcher, _annotationMatcher = annotationMatcher,
_interfaceMatcher = interfaceMatcher, _interfaceMatcher = interfaceMatcher,
this.assetId = assetId, this.assetId = assetId,

View File

@ -3,11 +3,9 @@ library angular2.transform.directive_processor.visitors;
import 'dart:async'; import 'dart:async';
import 'package:analyzer/analyzer.dart'; import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/java_core.dart'; import 'package:analyzer/src/generated/java_core.dart';
import 'package:angular2/metadata.dart' show LifecycleEvent;
import 'package:angular2/src/core/render/xhr.dart' show XHR; import 'package:angular2/src/core/render/xhr.dart' show XHR;
import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/async_string_writer.dart'; import 'package:angular2/src/transform/common/async_string_writer.dart';
import 'package:angular2/src/transform/common/interface_matcher.dart';
import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/logging.dart';
import 'package:barback/barback.dart'; import 'package:barback/barback.dart';
@ -214,92 +212,24 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
final AsyncStringWriter writer; final AsyncStringWriter writer;
final XHR _xhr; final XHR _xhr;
final AnnotationMatcher _annotationMatcher; final AnnotationMatcher _annotationMatcher;
final InterfaceMatcher _interfaceMatcher;
final AssetId _assetId; final AssetId _assetId;
final bool _inlineViews; final bool _inlineViews;
final ConstantEvaluator _evaluator = new ConstantEvaluator(); final ConstantEvaluator _evaluator = new ConstantEvaluator();
final Set<String> _ifaceLifecycleEntries = new Set<String>();
bool _isLifecycleWritten = false;
bool _isProcessingView = false; bool _isProcessingView = false;
bool _isProcessingDirective = false; bool _isProcessingDirective = false;
String _ifaceLifecyclePrefix = '';
AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr, AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr,
this._annotationMatcher, this._interfaceMatcher, this._assetId, this._annotationMatcher, this._assetId, {bool inlineViews})
{bool inlineViews}) : writer = writer,
: this.writer = writer,
_inlineViews = inlineViews, _inlineViews = inlineViews,
super(writer); super(writer);
/// Determines if the `node` has interface-based lifecycle methods and
/// populates `_lifecycleValue` with the appropriate values if so. If none are
/// present, `_lifecycleValue` is not modified.
void _populateLifecycleValue(ClassDeclaration node) {
var populateImport = (Identifier name) {
if (_ifaceLifecyclePrefix.isNotEmpty) return;
var import = _interfaceMatcher.getMatchingImport(name, _assetId);
_ifaceLifecyclePrefix =
import != null && import.prefix != null ? '${import.prefix}.' : '';
};
var namesToTest = [];
if (node.implementsClause != null &&
node.implementsClause.interfaces != null &&
node.implementsClause.interfaces.isNotEmpty) {
namesToTest.addAll(node.implementsClause.interfaces.map((i) => i.name));
}
if (node.extendsClause != null) {
namesToTest.add(node.extendsClause.superclass.name);
}
namesToTest.forEach((name) {
if (_interfaceMatcher.isOnChange(name, _assetId)) {
_ifaceLifecycleEntries.add('${LifecycleEvent.OnChanges}');
populateImport(name);
}
if (_interfaceMatcher.isOnDestroy(name, _assetId)) {
_ifaceLifecycleEntries.add('${LifecycleEvent.OnDestroy}');
populateImport(name);
}
if (_interfaceMatcher.isOnCheck(name, _assetId)) {
_ifaceLifecycleEntries.add('${LifecycleEvent.DoCheck}');
populateImport(name);
}
if (_interfaceMatcher.isOnInit(name, _assetId)) {
_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);
}
});
}
void _resetState() { void _resetState() {
_isLifecycleWritten = _isProcessingView = _isProcessingDirective = false; _isProcessingView = _isProcessingDirective = false;
_ifaceLifecycleEntries.clear();
_ifaceLifecyclePrefix = '';
} }
@override @override
Object visitClassDeclaration(ClassDeclaration node) { Object visitClassDeclaration(ClassDeclaration node) {
_populateLifecycleValue(node);
writer.print('const ['); writer.print('const [');
var size = node.metadata.length; var size = node.metadata.length;
for (var i = 0; i < size; ++i) { for (var i = 0; i < size; ++i) {
@ -338,28 +268,11 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
} }
args[i].accept(this); args[i].accept(this);
} }
if (!_isLifecycleWritten && _isProcessingDirective) {
var lifecycleValue = _getLifecycleValue();
if (lifecycleValue.isNotEmpty) {
writer.print(', lifecycle: $lifecycleValue');
_isLifecycleWritten = true;
}
}
writer.print(')'); writer.print(')');
} }
return null; return null;
} }
String _getLifecycleValue() {
if (_ifaceLifecycleEntries.isNotEmpty) {
var entries = _ifaceLifecycleEntries.toList();
entries.sort();
return 'const [${_ifaceLifecyclePrefix}'
'${entries.join(", ${_ifaceLifecyclePrefix}")}]';
}
return '';
}
/// These correspond to the annotation parameters. /// These correspond to the annotation parameters.
@override @override
Object visitNamedExpression(NamedExpression node) { Object visitNamedExpression(NamedExpression node) {
@ -375,37 +288,9 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
var isSuccess = this._inlineView(keyString, node.expression); var isSuccess = this._inlineView(keyString, node.expression);
if (isSuccess) return null; if (isSuccess) return null;
} }
if (_isProcessingDirective && keyString == 'lifecycle') {
var isSuccess = _populateLifecycleFromNamedExpression(node.expression);
if (isSuccess) {
_isLifecycleWritten = true;
writer.print('lifecycle: ${_getLifecycleValue()}');
return null;
} else {
logger.warning('Failed to parse `lifecycle` value. '
'The following `LifecycleEvent`s may not be called: '
'(${_ifaceLifecycleEntries.join(', ')})');
_isLifecycleWritten = true;
// Do not return -- we will use the default processing here, maintaining
// the original value for `lifecycle`.
}
}
return super.visitNamedExpression(node); return super.visitNamedExpression(node);
} }
/// Populates the lifecycle values from explicitly declared values.
/// Returns whether `node` was successfully processed.
bool _populateLifecycleFromNamedExpression(AstNode node) {
var nodeVal = node.toSource();
for (var evt in LifecycleEvent.values) {
var evtStr = '$evt';
if (nodeVal.contains(evtStr)) {
_ifaceLifecycleEntries.add(evtStr);
}
}
return true;
}
/// Inlines the template and/or style refered to by `keyString`. /// Inlines the template and/or style refered to by `keyString`.
/// Returns whether the `keyString` value was successfully processed. /// Returns whether the `keyString` value was successfully processed.
bool _inlineView(String keyString, AstNode node) { bool _inlineView(String keyString, AstNode node) {

View File

@ -2,7 +2,7 @@ library examples.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart'; import 'hello.dart';
import 'package:angular2/angular2.dart' import 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, LifecycleEvent, ChangeDetectionStrategy; show Component, Directive, View, NgElement, ChangeDetectionStrategy;
var _visited = false; var _visited = false;
void initReflector(reflector) { void initReflector(reflector) {

View File

@ -2,7 +2,7 @@ library examples.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart'; import 'hello.dart';
import 'package:angular2/angular2.dart' import 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, LifecycleEvent; show Component, Directive, View, NgElement;
var _visited = false; var _visited = false;
void initReflector(reflector) { void initReflector(reflector) {

View File

@ -2,7 +2,7 @@ library examples.hello_world.index_common_dart.ng_deps.dart;
import 'hello.dart'; import 'hello.dart';
import 'package:angular2/angular2.dart' import 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, LifecycleEvent; show Component, Directive, View, NgElement;
var _visited = false; var _visited = false;
void initReflector(reflector) { void initReflector(reflector) {

View File

@ -104,10 +104,6 @@ void allTests() {
_testProcessor('should not include superclasses in `interfaces`.', _testProcessor('should not include superclasses in `interfaces`.',
'superclass_files/soup.dart'); 'superclass_files/soup.dart');
_testProcessor(
'should populate `lifecycle` when lifecycle interfaces are present.',
'interface_lifecycle_files/soup.dart');
_testProcessor('should populate multiple `lifecycle` values when necessary.', _testProcessor('should populate multiple `lifecycle` values when necessary.',
'multiple_interface_lifecycle_files/soup.dart'); 'multiple_interface_lifecycle_files/soup.dart');

View File

@ -1,99 +0,0 @@
library dinner.soup.ng_deps.dart;
import 'soup.dart';
export 'soup.dart';
import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
import 'package:angular2/metadata.dart';
var _visited = false;
void initReflector() {
if (_visited) return;
_visited = true;
_ngRef.reflector
..registerType(
OnChangeSoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]',
lifecycle: const [LifecycleEvent.OnChanges])
],
const [],
() => new OnChangeSoupComponent(),
const [OnChanges]))
..registerType(
OnDestroySoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]',
lifecycle: const [LifecycleEvent.OnDestroy])
],
const [],
() => new OnDestroySoupComponent(),
const [OnDestroy]))
..registerType(
OnCheckSoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]', lifecycle: const [LifecycleEvent.DoCheck])
],
const [],
() => new OnCheckSoupComponent(),
const [DoCheck]))
..registerType(
OnInitSoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]', lifecycle: const [LifecycleEvent.OnInit])
],
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(
const [
const Component(
selector: '[soup]',
lifecycle: const [LifecycleEvent.AfterContentChecked])
],
const [],
() => new AfterContentCheckedSoupComponent(),
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]));
}

View File

@ -1,27 +0,0 @@
library dinner.soup;
import 'package:angular2/metadata.dart';
@Component(selector: '[soup]')
class OnChangeSoupComponent implements OnChanges {}
@Component(selector: '[soup]')
class OnDestroySoupComponent implements OnDestroy {}
@Component(selector: '[soup]')
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 {}

View File

@ -14,40 +14,9 @@ void initReflector() {
MultiSoupComponent, MultiSoupComponent,
new _ngRef.ReflectionInfo( new _ngRef.ReflectionInfo(
const [ const [
const Component( const Component(selector: '[soup]')
selector: '[soup]',
lifecycle: const [
LifecycleEvent.OnChanges,
LifecycleEvent.OnDestroy,
LifecycleEvent.OnInit
])
], ],
const [], const [],
() => new MultiSoupComponent(), () => new MultiSoupComponent(),
const [OnChanges, OnDestroy, OnInit])) const [OnChanges, OnDestroy, OnInit]));
..registerType(
MixedSoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]',
lifecycle: const [
LifecycleEvent.DoCheck,
LifecycleEvent.OnChanges
])
],
const [],
() => new MixedSoupComponent(),
const [OnChanges]))
..registerType(
MatchedSoupComponent,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]',
lifecycle: const [LifecycleEvent.OnChanges])
],
const [],
() => new MatchedSoupComponent(),
const [OnChanges]));
} }

View File

@ -4,9 +4,3 @@ import 'package:angular2/metadata.dart';
@Component(selector: '[soup]') @Component(selector: '[soup]')
class MultiSoupComponent implements OnChanges, OnDestroy, OnInit {} class MultiSoupComponent implements OnChanges, OnDestroy, OnInit {}
@Component(selector: '[soup]', lifecycle: const [LifecycleEvent.DoCheck])
class MixedSoupComponent implements OnChanges {}
@Component(selector: '[soup]', lifecycle: const [LifecycleEvent.OnChanges])
class MatchedSoupComponent implements OnChanges {}

View File

@ -15,8 +15,7 @@ void initReflector() {
new _ngRef.ReflectionInfo( new _ngRef.ReflectionInfo(
const [ const [
const prefix.Component( const prefix.Component(
selector: '[soup]', selector: '[soup]')
lifecycle: const [prefix.LifecycleEvent.OnChanges])
], ],
const [], const [],
() => new OnChangeSoupComponent(), () => new OnChangeSoupComponent(),

View File

@ -14,6 +14,6 @@ void initReflector() {
OnChangeSoupComponent, OnChangeSoupComponent,
new _ngRef.ReflectionInfo(const [ new _ngRef.ReflectionInfo(const [
const Component( const Component(
selector: '[soup]', lifecycle: const [LifecycleEvent.OnChanges]) selector: '[soup]')
], const [], () => new OnChangeSoupComponent())); ], const [], () => new OnChangeSoupComponent()));
} }