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

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.
*

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 {ListWrapper} from 'angular2/src/core/facade/collection';
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
@ -52,10 +52,10 @@ const controlGroupBinding =
selector: '[ng-control-group]',
bindings: [controlGroupBinding],
properties: ['name: ng-control-group'],
lifecycle: [LifecycleEvent.OnInit, LifecycleEvent.OnDestroy],
exportAs: 'form'
})
export class NgControlGroup extends ControlContainer {
export class NgControlGroup extends ControlContainer implements OnInit,
OnDestroy {
_parent: ControlContainer;
constructor(@Host() @SkipSelf() _parent: ControlContainer) {
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 {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 {ControlContainer} from './control_container';
@ -76,10 +76,10 @@ const controlNameBinding =
bindings: [controlNameBinding],
properties: ['name: ngControl', 'model: ngModel'],
events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnDestroy, LifecycleEvent.OnChanges],
exportAs: 'form'
})
export class NgControlName extends NgControl {
export class NgControlName extends NgControl implements OnChanges,
OnDestroy {
_parent: ControlContainer;
update = new EventEmitter();
model: any;

View File

@ -1,7 +1,7 @@
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
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 {NgControl} from './ng_control';
@ -62,10 +62,9 @@ const formControlBinding =
bindings: [formControlBinding],
properties: ['form: ngFormControl', 'model: ngModel'],
events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnChanges],
exportAs: 'form'
})
export class NgFormControl extends NgControl {
export class NgFormControl extends NgControl implements OnChanges {
form: Control;
update = new EventEmitter();
_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 {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 {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group';
@ -84,14 +84,14 @@ const formDirectiveBinding =
selector: '[ng-form-model]',
bindings: [formDirectiveBinding],
properties: ['form: ng-form-model'],
lifecycle: [LifecycleEvent.OnChanges],
host: {
'(submit)': 'onSubmit()',
},
events: ['ngSubmit'],
exportAs: 'form'
})
export class NgFormModel extends ControlContainer implements Form {
export class NgFormModel extends ControlContainer implements Form,
OnChanges {
form: ControlGroup = null;
directives: NgControl[] = [];
ngSubmit = new EventEmitter();

View File

@ -1,7 +1,7 @@
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
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 {NgControl} from './ng_control';
@ -32,10 +32,9 @@ const formControlBinding = CONST_EXPR(new Binding(NgControl, {toAlias: forwardRe
bindings: [formControlBinding],
properties: ['model: ngModel'],
events: ['update: ngModel'],
lifecycle: [LifecycleEvent.OnChanges],
exportAs: 'form'
})
export class NgModel extends NgControl {
export class NgModel extends NgControl implements OnChanges {
_control = new Control();
_added = false;
update = new EventEmitter();

View File

@ -16,22 +16,10 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnChanges)
.toBe(false);
});
it("should be false when empty lifecycle", () {
expect(metadata(
DirectiveImplementingOnChanges, new Directive(lifecycle: []))
.callOnChanges).toBe(false);
});
});
describe("onDestroy", () {
@ -40,12 +28,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnDestroy)
.toBe(false);
@ -58,12 +40,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive()).callDoCheck)
.toBe(false);
@ -76,12 +52,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive()).callOnInit)
.toBe(false);
@ -95,12 +65,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive())
.callAfterContentInit).toBe(false);
@ -114,12 +78,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive())
.callAfterContentChecked).toBe(false);
@ -133,12 +91,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive())
.callAfterViewInit).toBe(false);
@ -152,12 +104,6 @@ main() {
.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", () {
expect(metadata(DirectiveNoHooks, new Directive())
.callAfterViewChecked).toBe(false);

View File

@ -13,7 +13,7 @@ import {
proxy
} 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 {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
@ -30,22 +30,9 @@ export function main() {
.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", () => {
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", () => {
@ -54,13 +41,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnDestroy).toBe(false);
});
@ -72,13 +52,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callOnInit).toBe(false);
});
@ -90,13 +63,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callDoCheck).toBe(false);
});
@ -109,13 +75,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentInit)
.toBe(false);
@ -129,13 +88,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterContentChecked)
.toBe(false);
@ -150,13 +102,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewInit).toBe(false);
});
@ -169,13 +114,6 @@ export function main() {
.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", () => {
expect(metadata(DirectiveNoHooks, new DirectiveMetadata()).callAfterViewChecked)
.toBe(false);
@ -200,7 +138,7 @@ class DirectiveWithOnCheckMethod {
}
class DirectiveWithOnDestroyMethod {
onDestroy(_) {}
onDestroy() {}
}
class DirectiveWithAfterContentInitMethod {

View File

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

View File

@ -36,7 +36,7 @@ import {
ViewQuery,
ComponentMetadata,
DirectiveMetadata,
LifecycleEvent
OnDestroy
} from 'angular2/metadata';
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';
@ -217,7 +217,7 @@ class B_Needs_A {
constructor(dep) {}
}
class DirectiveWithDestroy {
class DirectiveWithDestroy implements OnDestroy {
onDestroyCounter: number;
constructor() { this.onDestroyCounter = 0; }
@ -832,7 +832,7 @@ export function main() {
it("should call onDestroy on directives subscribed to this event", () => {
var inj = injector(ListWrapper.concat(
[DirectiveBinding.createFromType(DirectiveWithDestroy,
new DirectiveMetadata({lifecycle: [LifecycleEvent.OnDestroy]}))],
new DirectiveMetadata())],
extraBindings));
var destroy = inj.get(DirectiveWithDestroy);
inj.dehydrate();

View File

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

View File

@ -13,7 +13,19 @@ import {
TestComponentBuilder
} 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() {
describe('directive lifecycle integration spec', () => {
@ -47,27 +59,16 @@ export function main() {
}
@Directive({selector: '[lifecycle-dir]', lifecycle: [LifecycleEvent.DoCheck]})
class LifecycleDir {
@Directive({selector: '[lifecycle-dir]'})
class LifecycleDir implements DoCheck {
constructor(private _log: Log) {}
doCheck() { this._log.add("child_doCheck"); }
}
@Component({
selector: "[lifecycle]",
properties: ['field'],
lifecycle: [
LifecycleEvent.OnChanges,
LifecycleEvent.OnInit,
LifecycleEvent.DoCheck,
LifecycleEvent.AfterContentInit,
LifecycleEvent.AfterContentChecked,
LifecycleEvent.AfterViewInit,
LifecycleEvent.AfterViewChecked
]
})
@Component({selector: "[lifecycle]", properties: ['field']})
@View({template: `<div lifecycle-dir></div>`, directives: [LifecycleDir]})
class LifecycleCmp {
class LifecycleCmp implements OnChanges, OnInit, DoCheck, AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked {
field;
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 {isPresent} from 'angular2/src/core/facade/lang';
@ -48,7 +48,6 @@ export class MdButton {
@Component({
selector: 'a[md-button], a[md-raised-button], a[md-fab]',
properties: ['disabled'],
lifecycle: [LifecycleEvent.OnChanges],
host: {
'(click)': 'onClick($event)',
'(mousedown)': 'onMousedown()',
@ -63,7 +62,7 @@ export class MdButton {
templateUrl: 'package:angular2_material/src/components/button/button.html',
encapsulation: ViewEncapsulation.None
})
export class MdAnchor extends MdButton {
export class MdAnchor extends MdButton implements OnChanges {
tabIndex: number;
/** Whether the component is disabled. */

View File

@ -4,7 +4,9 @@ import {
ViewEncapsulation,
Host,
SkipSelf,
LifecycleEvent
OnChanges,
OnDestroy,
AfterContentChecked
} from 'angular2/angular2';
import {ListWrapper} from 'angular2/src/core/facade/collection';
@ -25,16 +27,12 @@ class RowHeightMode {
}
@Component({
selector: 'md-grid-list',
properties: ['cols', 'rowHeight', 'gutterSize'],
lifecycle: [LifecycleEvent.AfterContentChecked]
})
@Component({selector: 'md-grid-list', properties: ['cols', 'rowHeight', 'gutterSize']})
@View({
templateUrl: 'package:angular2_material/src/components/grid_list/grid_list.html',
encapsulation: ViewEncapsulation.None
})
export class MdGridList {
export class MdGridList implements AfterContentChecked {
/** Array of tiles that are being rendered. */
tiles: MdGridTile[];
@ -225,14 +223,14 @@ export class MdGridList {
'[style.left]': 'style.left',
'[style.marginTop]': 'style.marginTop',
'[style.paddingTop]': 'style.paddingTop',
},
lifecycle: [LifecycleEvent.OnDestroy, LifecycleEvent.OnChanges]
}
})
@View({
templateUrl: 'package:angular2_material/src/components/grid_list/grid_tile.html',
encapsulation: ViewEncapsulation.None
})
export class MdGridTile {
export class MdGridTile implements OnDestroy,
OnChanges {
gridList: MdGridList;
_rowspan: 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';
@ -9,13 +16,12 @@ import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async';
@Directive({
selector: 'md-input-container',
lifecycle: [LifecycleEvent.AfterContentChecked],
host: {
'[class.md-input-has-value]': 'inputHasValue',
'[class.md-input-focused]': 'inputHasFocus',
}
})
export class MdInputContainer {
export class MdInputContainer implements AfterContentChecked {
// The MdInput or MdTextarea inside of this container.
_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 {isPresent, isBlank} from 'angular2/src/core/facade/lang';
import {Math} from 'angular2/src/core/facade/math';
/** Different display / behavior modes for progress-linear. */
@CONST()
class ProgressMode {
@ -15,7 +21,6 @@ class ProgressMode {
@Component({
selector: 'md-progress-linear',
lifecycle: [LifecycleEvent.OnChanges],
properties: ['value', 'bufferValue'],
host: {
'role': 'progressbar',
@ -29,7 +34,7 @@ class ProgressMode {
directives: [],
encapsulation: ViewEncapsulation.None
})
export class MdProgressLinear {
export class MdProgressLinear implements OnChanges {
/** Value for the primary bar. */
value_: number;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,9 @@ library angular2.transform.directive_processor.visitors;
import 'dart:async';
import 'package:analyzer/analyzer.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/transform/common/annotation_matcher.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:barback/barback.dart';
@ -214,92 +212,24 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
final AsyncStringWriter writer;
final XHR _xhr;
final AnnotationMatcher _annotationMatcher;
final InterfaceMatcher _interfaceMatcher;
final AssetId _assetId;
final bool _inlineViews;
final ConstantEvaluator _evaluator = new ConstantEvaluator();
final Set<String> _ifaceLifecycleEntries = new Set<String>();
bool _isLifecycleWritten = false;
bool _isProcessingView = false;
bool _isProcessingDirective = false;
String _ifaceLifecyclePrefix = '';
AnnotationsTransformVisitor(AsyncStringWriter writer, this._xhr,
this._annotationMatcher, this._interfaceMatcher, this._assetId,
{bool inlineViews})
: this.writer = writer,
this._annotationMatcher, this._assetId, {bool inlineViews})
: writer = writer,
_inlineViews = inlineViews,
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() {
_isLifecycleWritten = _isProcessingView = _isProcessingDirective = false;
_ifaceLifecycleEntries.clear();
_ifaceLifecyclePrefix = '';
_isProcessingView = _isProcessingDirective = false;
}
@override
Object visitClassDeclaration(ClassDeclaration node) {
_populateLifecycleValue(node);
writer.print('const [');
var size = node.metadata.length;
for (var i = 0; i < size; ++i) {
@ -338,28 +268,11 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
}
args[i].accept(this);
}
if (!_isLifecycleWritten && _isProcessingDirective) {
var lifecycleValue = _getLifecycleValue();
if (lifecycleValue.isNotEmpty) {
writer.print(', lifecycle: $lifecycleValue');
_isLifecycleWritten = true;
}
}
writer.print(')');
}
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.
@override
Object visitNamedExpression(NamedExpression node) {
@ -375,37 +288,9 @@ class AnnotationsTransformVisitor extends ToSourceVisitor {
var isSuccess = this._inlineView(keyString, node.expression);
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);
}
/// 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`.
/// Returns whether the `keyString` value was successfully processed.
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 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, LifecycleEvent, ChangeDetectionStrategy;
show Component, Directive, View, NgElement, ChangeDetectionStrategy;
var _visited = false;
void initReflector(reflector) {

View File

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

View File

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

View File

@ -104,10 +104,6 @@ void allTests() {
_testProcessor('should not include superclasses in `interfaces`.',
'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.',
'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,
new _ngRef.ReflectionInfo(
const [
const Component(
selector: '[soup]',
lifecycle: const [
LifecycleEvent.OnChanges,
LifecycleEvent.OnDestroy,
LifecycleEvent.OnInit
])
const Component(selector: '[soup]')
],
const [],
() => new MultiSoupComponent(),
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]));
const [OnChanges, OnDestroy, OnInit]));
}

View File

@ -4,9 +4,3 @@ import 'package:angular2/metadata.dart';
@Component(selector: '[soup]')
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(
const [
const prefix.Component(
selector: '[soup]',
lifecycle: const [prefix.LifecycleEvent.OnChanges])
selector: '[soup]')
],
const [],
() => new OnChangeSoupComponent(),

View File

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