Skip to content

Commit

Permalink
refactor(LifecycleEvent): remove LifecycleEvent
Browse files Browse the repository at this point in the history
fixes angular#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() {
        }
      });
  • Loading branch information
vicb committed Sep 5, 2015
1 parent 15164a8 commit ecfed76
Show file tree
Hide file tree
Showing 42 changed files with 308 additions and 839 deletions.
3 changes: 2 additions & 1 deletion modules/angular2/metadata.ts
Expand Up @@ -14,7 +14,6 @@ export {
ComponentMetadata,
DirectiveMetadata,
PipeMetadata,
LifecycleEvent,
ViewMetadata,
ViewEncapsulation,
QueryMetadata,
Expand Down Expand Up @@ -50,6 +49,8 @@ export {
} from './src/core/metadata';

export {
// todo(vbe): LifecycleHook should not be exposed (fails test.typings)
LifecycleHook,
AfterContentInit,
AfterContentChecked,
AfterViewInit,
Expand Down
@@ -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);
}
54 changes: 26 additions & 28 deletions modules/angular2/src/core/compiler/directive_lifecycle_reflector.ts
@@ -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;
}
}
20 changes: 11 additions & 9 deletions modules/angular2/src/core/compiler/element_injector.ts
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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,

Expand Down
189 changes: 156 additions & 33 deletions modules/angular2/src/core/compiler/interfaces.ts
@@ -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.
* 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 OnChanges { onChanges(changes: StringMap<string, any>): void; }
export interface LifecycleHook {}

/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#OnInit `LifeCycleEvent.OnInit`}
* called when a directive is being checked the first time.
* 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 OnInit { onInit(): void; }
export class OnChanges implements LifecycleHook {
onChanges(changes: StringMap<string, any>): void {}
}

/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#DoCheck `LifeCycleEvent.DoCheck`}
* called when a directive is being checked.
* 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 DoCheck { doCheck(): boolean; }
export class OnInit implements LifecycleHook {
onInit(): void {}
}

/**
* Defines lifecycle method {@link metadata/LifeCycleEvent#OnDestroy `LifeCycleEvent.OnDestroy`}
* called when a directive is being destroyed.
* 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 OnDestroy { onDestroy(): void; }
export class DoCheck implements LifecycleHook {
doCheck(): 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.
* 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 AfterContentInit { afterContentInit(): void; }
export class OnDestroy implements LifecycleHook {
onDestroy(): 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 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 AfterContentChecked { afterContentChecked(): void; }
export class AfterContentInit implements LifecycleHook {
afterContentInit(): 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 (whether
* they have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterContentChecked {
* afterContentChecked(): void {
* }
* }
* ```
*/
export interface AfterViewInit { afterViewInit(): void; }
export class AfterContentChecked implements LifecycleHook {
afterContentChecked(): 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 view children have been checked the first time
* (whether they have changed or not).
*
* ## Example
*
* ```
* @Component(...)
* class MyComponent implements AfterViewInit {
* afterViewInit(): void {
* }
* }
* ```
*/
export interface AfterViewChecked { afterViewChecked(): 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 {}
}
10 changes: 3 additions & 7 deletions modules/angular2/src/core/directives/ng_class.ts
@@ -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 {
Expand Down Expand Up @@ -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 = [];
Expand Down

0 comments on commit ecfed76

Please sign in to comment.