refactor(change_detection): introduce enum ChangeDetectionStrategy

BREAKING CHANGE

Closes #2497

- change detection strategy type changes from string to ChangeDetectionStrategy
- CHECK_ONCE => ChangeDetectionStrategy.CheckOnce
- CHECKED => ChangeDetectionStrategy.Checked
- CHECK_ALWAYS => ChangeDetectionStrategy.CheckAlways
- DETACHED => ChangeDetectionStrategy.Detached
- ON_PUSH => ChangeDetectionStrategy.OnPush
- DEFAULT => ChangeDetectionStrategy.Default
- ON_PUSH_OBSERVE => ChangeDetectionStrategy.OnPushObserve
This commit is contained in:
Misko Hevery 2015-08-26 11:44:59 -07:00
parent e41d7451bf
commit 69926dd002
35 changed files with 388 additions and 365 deletions

View File

@ -5,12 +5,7 @@
*/
export {
CHECK_ONCE,
CHECK_ALWAYS,
DETACHED,
CHECKED,
ON_PUSH,
DEFAULT,
ChangeDetectionStrategy,
ExpressionChangedAfterItHasBeenCheckedException,
ChangeDetectionError,

View File

@ -12,10 +12,9 @@ import {
} from './exceptions';
import {BindingTarget} from './binding_record';
import {Locals} from './parser/locals';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
import {ChangeDetectionStrategy} from './constants';
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
import {isObservable} from './observable_facade';
import {ON_PUSH_OBSERVE} from './constants';
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
@ -36,7 +35,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
alreadyChecked: any = false;
context: T;
locals: Locals = null;
mode: string = null;
mode: ChangeDetectionStrategy = null;
pipes: Pipes = null;
propertyBindingIndex: number;
@ -46,7 +45,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
constructor(public id: string, public dispatcher: ChangeDispatcher,
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
public directiveIndices: DirectiveIndex[], public strategy: string) {
public directiveIndices: DirectiveIndex[], public strategy: ChangeDetectionStrategy) {
this.ref = new ChangeDetectorRef(this);
}
@ -79,14 +78,16 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
checkNoChanges(): void { throw new BaseException("Not implemented"); }
runDetectChanges(throwOnChange: boolean): void {
if (StringWrapper.equals(this.mode, DETACHED) || StringWrapper.equals(this.mode, CHECKED))
if (this.mode === ChangeDetectionStrategy.Detached ||
this.mode === ChangeDetectionStrategy.Checked)
return;
var s = _scope_check(this.id, throwOnChange);
this.detectChangesInRecords(throwOnChange);
this._detectChangesInLightDomChildren(throwOnChange);
if (throwOnChange === false) this.callOnAllChangesDone();
this._detectChangesInShadowDomChildren(throwOnChange);
if (StringWrapper.equals(this.mode, CHECK_ONCE)) this.mode = CHECKED;
if (this.mode === ChangeDetectionStrategy.CheckOnce)
this.mode = ChangeDetectionStrategy.Checked;
wtfLeave(s);
}
@ -121,7 +122,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
this.context = context;
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
this.observeComponent(context);
}
@ -140,7 +141,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this.dehydrateDirectives(true);
// This is an experimental feature. Works only in Dart.
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
this._unsubsribeFromObservables();
}
@ -171,12 +172,12 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
}
}
markAsCheckOnce(): void { this.mode = CHECK_ONCE; }
markAsCheckOnce(): void { this.mode = ChangeDetectionStrategy.CheckOnce; }
markPathToRootAsCheckOnce(): void {
var c: ChangeDetector = this;
while (isPresent(c) && !StringWrapper.equals(c.mode, DETACHED)) {
if (StringWrapper.equals(c.mode, CHECKED)) c.mode = CHECK_ONCE;
while (isPresent(c) && c.mode !== ChangeDetectionStrategy.Detached) {
if (c.mode === ChangeDetectionStrategy.Checked) c.mode = ChangeDetectionStrategy.CheckOnce;
c = c.parent;
}
}

View File

@ -48,7 +48,7 @@ export {
DebugContext,
ChangeDetectorGenConfig
} from './interfaces';
export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants';
export {ChangeDetectionStrategy} from './constants';
export {DynamicProtoChangeDetector} from './proto_change_detector';
export {BindingRecord, BindingTarget} from './binding_record';
export {DirectiveIndex, DirectiveRecord} from './directive_record';

View File

@ -12,6 +12,8 @@ import {codify} from './codegen_facade';
import {EventBinding} from './event_binding';
import {BindingTarget} from './binding_record';
import {ChangeDetectorGenConfig} from './interfaces';
import {ChangeDetectionStrategy} from './constants';
/**
@ -33,7 +35,7 @@ export class ChangeDetectorJITGenerator {
_names: CodegenNameUtil;
_typeName: string;
constructor(private id: string, private changeDetectionStrategy: string,
constructor(private id: string, private changeDetectionStrategy: ChangeDetectionStrategy,
private records: List<ProtoRecord>, private propertyBindingTargets: BindingTarget[],
private eventBindings: EventBinding[], private directiveRecords: List<any>,
private genConfig: ChangeDetectorGenConfig) {

View File

@ -8,13 +8,7 @@ import {
} from 'angular2/src/core/facade/lang';
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
import {ProtoRecord} from './proto_record';
import {
CHECK_ALWAYS,
CHECK_ONCE,
CHECKED,
DETACHED,
isDefaultChangeDetectionStrategy
} from './constants';
import {ChangeDetectionStrategy, isDefaultChangeDetectionStrategy} from './constants';
import {implementsOnDestroy} from './pipe_lifecycle_reflector';
import {BindingTarget} from './binding_record';
import {DirectiveIndex} from './directive_record';
@ -180,8 +174,9 @@ export class ChangeDetectionUtil {
}
}
static changeDetectionMode(strategy: string): string {
return isDefaultChangeDetectionStrategy(strategy) ? CHECK_ALWAYS : CHECK_ONCE;
static changeDetectionMode(strategy: ChangeDetectionStrategy): ChangeDetectionStrategy {
return isDefaultChangeDetectionStrategy(strategy) ? ChangeDetectionStrategy.CheckAlways :
ChangeDetectionStrategy.CheckOnce;
}
static simpleChange(previousValue: any, currentValue: any): SimpleChange {

View File

@ -1,5 +1,5 @@
import {ChangeDetector} from './interfaces';
import {CHECK_ONCE, DETACHED, CHECK_ALWAYS} from './constants';
import {ChangeDetectionStrategy} from './constants';
/**
* Controls change detection.
@ -14,7 +14,7 @@ export class ChangeDetectorRef {
constructor(private _cd: ChangeDetector) {}
/**
* Request to check all ON_PUSH ancestors.
* Request to check all OnPush ancestors.
*/
requestCheck(): void { this._cd.markPathToRootAsCheckOnce(); }
@ -23,7 +23,7 @@ export class ChangeDetectorRef {
*
* The detached change detector will not be checked until it is reattached.
*/
detach(): void { this._cd.mode = DETACHED; }
detach(): void { this._cd.mode = ChangeDetectionStrategy.Detached; }
/**
* Reattach the change detector to the change detector tree.
@ -33,7 +33,7 @@ export class ChangeDetectorRef {
* next change detection run.
*/
reattach(): void {
this._cd.mode = CHECK_ALWAYS;
this._cd.mode = ChangeDetectionStrategy.CheckAlways;
this.requestCheck();
}
}

View File

@ -11,14 +11,14 @@ import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
import {ProtoRecord, RecordType} from './proto_record';
import {BindingTarget} from './binding_record';
import {DirectiveRecord} from './directive_record';
import {ON_PUSH_OBSERVE} from './constants';
import {ChangeDetectionStrategy} from './constants';
/**
* Class responsible for providing change detection logic for chagne detector classes.
*/
export class CodegenLogicUtil {
constructor(private _names: CodegenNameUtil, private _utilName: string,
private _changeDetection: string) {}
private _changeDetection: ChangeDetectionStrategy) {}
/**
* Generates a statement which updates the local variable representing `protoRec` with the current
@ -119,7 +119,7 @@ export class CodegenLogicUtil {
_observe(exp: string, rec: ProtoRecord): string {
// This is an experimental feature. Works only in Dart.
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
if (this._changeDetection === ChangeDetectionStrategy.OnPushObserve) {
return `this.observeValue(${exp}, ${rec.selfIndex})`;
} else {
return exp;
@ -165,7 +165,7 @@ export class CodegenLogicUtil {
private _genReadDirective(index: number) {
// This is an experimental feature. Works only in Dart.
if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
if (this._changeDetection === ChangeDetectionStrategy.OnPushObserve) {
return `this.observeDirective(this.getDirectiveFor(directives, ${index}), ${index})`;
} else {
return `this.getDirectiveFor(directives, ${index})`;

View File

@ -1,46 +1,49 @@
// TODO:vsavkin Use enums after switching to TypeScript
import {StringWrapper, normalizeBool, isBlank} from 'angular2/src/core/facade/lang';
/**
* CHECK_ONCE means that after calling detectChanges the mode of the change detector
* will become CHECKED.
export enum ChangeDetectionStrategy {
/**
* `CheckedOnce` means that after calling detectChanges the mode of the change detector
* will become `Checked`.
*/
export const CHECK_ONCE: string = "CHECK_ONCE";
CheckOnce,
/**
* CHECKED means that the change detector should be skipped until its mode changes to
* CHECK_ONCE or CHECK_ALWAYS.
/**
* `Checked` means that the change detector should be skipped until its mode changes to
* `CheckOnce`.
*/
export const CHECKED: string = "CHECKED";
Checked,
/**
* CHECK_ALWAYS means that after calling detectChanges the mode of the change detector
* will remain CHECK_ALWAYS.
/**
* `CheckAlways` means that after calling detectChanges the mode of the change detector
* will remain `CheckAlways`.
*/
export const CHECK_ALWAYS: string = "ALWAYS_CHECK";
CheckAlways,
/**
* DETACHED means that the change detector sub tree is not a part of the main tree and
/**
* `Detached` means that the change detector sub tree is not a part of the main tree and
* should be skipped.
*/
export const DETACHED: string = "DETACHED";
Detached,
/**
* ON_PUSH means that the change detector's mode will be set to CHECK_ONCE during hydration.
/**
* `OnPush` means that the change detector's mode will be set to `CheckOnce` during hydration.
*/
export const ON_PUSH: string = "ON_PUSH";
OnPush,
/**
* DEFAULT means that the change detector's mode will be set to CHECK_ALWAYS during hydration.
/**
* `Default` means that the change detector's mode will be set to `CheckAlways` during hydration.
*/
export const DEFAULT: string = "DEFAULT";
Default,
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: string): boolean {
return isBlank(changeDetectionStrategy) || StringWrapper.equals(changeDetectionStrategy, DEFAULT);
}
/**
/**
* This is an experimental feature. Works only in Dart.
*/
export const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
OnPushObserve
}
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: ChangeDetectionStrategy):
boolean {
return isBlank(changeDetectionStrategy) ||
changeDetectionStrategy === ChangeDetectionStrategy.Default;
}

View File

@ -1,5 +1,5 @@
import {StringWrapper, normalizeBool, isBlank} from 'angular2/src/core/facade/lang';
import {isDefaultChangeDetectionStrategy} from './constants';
import {isDefaultChangeDetectionStrategy, ChangeDetectionStrategy} from './constants';
export class DirectiveIndex {
constructor(public elementIndex: number, public directiveIndex: number) {}
@ -13,7 +13,7 @@ export class DirectiveRecord {
callOnChange: boolean;
callOnCheck: boolean;
callOnInit: boolean;
changeDetection: string;
changeDetection: ChangeDetectionStrategy;
constructor({directiveIndex, callOnAllChangesDone, callOnChange, callOnCheck, callOnInit,
changeDetection}: {
@ -22,7 +22,7 @@ export class DirectiveRecord {
callOnChange?: boolean,
callOnCheck?: boolean,
callOnInit?: boolean,
changeDetection?: string
changeDetection?: ChangeDetectionStrategy
} = {}) {
this.directiveIndex = directiveIndex;
this.callOnAllChangesDone = normalizeBool(callOnAllChangesDone);

View File

@ -14,7 +14,7 @@ import {DirectiveRecord, DirectiveIndex} from './directive_record';
import {Locals} from './parser/locals';
import {ChangeDetectorGenConfig} from './interfaces';
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
import {ON_PUSH_OBSERVE} from './constants';
import {ChangeDetectionStrategy} from './constants';
import {ProtoRecord, RecordType} from './proto_record';
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
@ -26,7 +26,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
constructor(id: string, dispatcher: any, numberOfPropertyProtoRecords: number,
propertyBindingTargets: BindingTarget[], directiveIndices: DirectiveIndex[],
strategy: string, private records: ProtoRecord[],
strategy: ChangeDetectionStrategy, private records: ProtoRecord[],
private eventBindings: EventBinding[], private directiveRecords: DirectiveRecord[],
private genConfig: ChangeDetectorGenConfig) {
super(id, dispatcher, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices,
@ -88,7 +88,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
this.values[0] = this.context;
this.directives = directives;
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
for (var i = 0; i < this.directiveIndices.length; ++i) {
var index = this.directiveIndices[i];
super.observeDirective(directives.getDirectiveFor(index), i);
@ -219,7 +219,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
}
var currValue = this._calculateCurrValue(proto, values, locals);
if (StringWrapper.equals(this.strategy, ON_PUSH_OBSERVE)) {
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
super.observeValue(currValue, proto.selfIndex);
}

View File

@ -3,6 +3,7 @@ import {CONST} from 'angular2/src/core/facade/lang';
import {Locals} from './parser/locals';
import {BindingTarget, BindingRecord} from './binding_record';
import {DirectiveIndex, DirectiveRecord} from './directive_record';
import {ChangeDetectionStrategy} from './constants';
import {ChangeDetectorRef} from './change_detector_ref';
/**
@ -55,7 +56,7 @@ export interface ChangeDispatcher {
export interface ChangeDetector {
parent: ChangeDetector;
mode: string;
mode: ChangeDetectionStrategy;
ref: ChangeDetectorRef;
addChild(cd: ChangeDetector): void;
@ -80,8 +81,8 @@ export class ChangeDetectorGenConfig {
}
export class ChangeDetectorDefinition {
constructor(public id: string, public strategy: string, public variableNames: List<string>,
public bindingRecords: BindingRecord[], public eventRecords: BindingRecord[],
public directiveRecords: DirectiveRecord[],
constructor(public id: string, public strategy: ChangeDetectionStrategy,
public variableNames: List<string>, public bindingRecords: BindingRecord[],
public eventRecords: BindingRecord[], public directiveRecords: DirectiveRecord[],
public genConfig: ChangeDetectorGenConfig) {}
}

View File

@ -7,7 +7,7 @@ export 'dart:core' show List;
export 'package:angular2/src/core/change_detection/abstract_change_detector.dart'
show AbstractChangeDetector;
export 'package:angular2/src/core/change_detection/change_detection.dart'
show preGeneratedProtoDetectors;
show preGeneratedProtoDetectors, ChangeDetectionStrategy;
export 'package:angular2/src/core/change_detection/directive_record.dart'
show DirectiveIndex, DirectiveRecord;
export 'package:angular2/src/core/change_detection/interfaces.dart'

View File

@ -16,7 +16,7 @@ import {
BindingRecord,
DirectiveRecord,
ProtoChangeDetector,
DEFAULT,
ChangeDetectionStrategy,
ChangeDetectorDefinition,
ChangeDetectorGenConfig,
ASTWithSource
@ -305,7 +305,7 @@ function _getChangeDetectorDefinitions(
bindingRecordsCreator.getEventBindingRecords(elementBinders, allRenderDirectiveMetadata);
var directiveRecords =
bindingRecordsCreator.getDirectiveRecords(elementBinders, allRenderDirectiveMetadata);
var strategyName = DEFAULT;
var strategyName = ChangeDetectionStrategy.Default;
if (pvWithIndex.renderProtoView.type === ViewType.COMPONENT) {
strategyName = hostComponentMetadata.changeDetection;
}

View File

@ -1,6 +1,7 @@
library angular2.src.core.metadata;
import "package:angular2/src/core/facade/collection.dart" show List;
import 'package:angular2/src/core/change_detection/change_detection.dart';
import "./metadata/di.dart";
import "./metadata/directives.dart";
import "./metadata/view.dart";
@ -35,7 +36,7 @@ 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,
bool compileChildren, List viewBindings, String changeDetection})
bool compileChildren, List viewBindings, ChangeDetectionStrategy changeDetection})
: super(
selector: selector,
properties: properties,

View File

@ -33,6 +33,7 @@ import {
} from './metadata/directives';
import {ViewMetadata, ViewEncapsulation} from './metadata/view';
import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection/change_detection';
import {makeDecorator, makeParamDecorator, TypeDecorator, Class} from './util/decorators';
import {Type} from 'angular2/src/core/facade/lang';
@ -191,7 +192,7 @@ export interface ComponentFactory {
exportAs?: string,
compileChildren?: boolean,
viewBindings?: List<any>,
changeDetection?: string,
changeDetection?: ChangeDetectionStrategy,
}): ComponentDecorator;
new (obj: {
selector?: string,
@ -203,7 +204,7 @@ export interface ComponentFactory {
exportAs?: string,
compileChildren?: boolean,
viewBindings?: List<any>,
changeDetection?: string,
changeDetection?: ChangeDetectionStrategy,
}): ComponentMetadata;
}

View File

@ -1,7 +1,7 @@
import {CONST, CONST_EXPR} from 'angular2/src/core/facade/lang';
import {List} from 'angular2/src/core/facade/collection';
import {InjectableMetadata} from 'angular2/src/core/di/metadata';
import {DEFAULT} from 'angular2/change_detection';
import {ChangeDetectionStrategy} from 'angular2/change_detection';
/**
* Directives allow you to attach behavior to elements in the DOM.
@ -795,14 +795,12 @@ export class ComponentMetadata extends DirectiveMetadata {
* Defines the used change detection strategy.
*
* When a component is instantiated, Angular creates a change detector, which is responsible for
* propagating
* the component's bindings.
* propagating the component's bindings.
*
* The `changeDetection` property defines, whether the change detection will be checked every time
* or only when the component
* tells it to do so.
* or only when the component tells it to do so.
*/
changeDetection: string;
changeDetection: ChangeDetectionStrategy;
/**
* Defines the set of injectable objects that are visible to its view dom children.
@ -847,7 +845,7 @@ export class ComponentMetadata extends DirectiveMetadata {
viewBindings: List<any>;
constructor({selector, properties, events, host, exportAs, lifecycle, bindings, viewBindings,
changeDetection = DEFAULT, compileChildren = true}: {
changeDetection = ChangeDetectionStrategy.Default, compileChildren = true}: {
selector?: string,
properties?: List<string>,
events?: List<string>,
@ -857,7 +855,7 @@ export class ComponentMetadata extends DirectiveMetadata {
exportAs?: string,
compileChildren?: boolean,
viewBindings?: List<any>,
changeDetection?: string,
changeDetection?: ChangeDetectionStrategy,
} = {}) {
super({
selector: selector,

View File

@ -46,7 +46,7 @@ var _observableStrategy = new ObservableStrategy();
* ```
* @Component({
* selector: "task-cmp",
* changeDetection: ON_PUSH
* changeDetection: ChangeDetectionStrategy.OnPush
* })
* @View({
* template: "Task Description {{ description | async }}"

View File

@ -7,7 +7,10 @@ import {
StringMap,
StringMapWrapper
} from 'angular2/src/core/facade/collection';
import {ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
import {
ASTWithSource,
ChangeDetectionStrategy
} from 'angular2/src/core/change_detection/change_detection';
/**
* General notes:
@ -155,7 +158,7 @@ export class RenderDirectiveMetadata {
callOnCheck: boolean;
callOnInit: boolean;
callOnAllChangesDone: boolean;
changeDetection: string;
changeDetection: ChangeDetectionStrategy;
exportAs: string;
hostListeners: Map<string, string>;
hostProperties: Map<string, string>;
@ -185,7 +188,7 @@ export class RenderDirectiveMetadata {
callOnCheck?: boolean,
callOnInit?: boolean,
callOnAllChangesDone?: boolean,
changeDetection?: string,
changeDetection?: ChangeDetectionStrategy,
exportAs?: string
}) {
this.id = id;
@ -224,7 +227,7 @@ export class RenderDirectiveMetadata {
callOnCheck?: boolean,
callOnInit?: boolean,
callOnAllChangesDone?: boolean,
changeDetection?: string,
changeDetection?: ChangeDetectionStrategy,
exportAs?: string
}): RenderDirectiveMetadata {
let hostListeners = new Map();

View File

@ -1,67 +0,0 @@
import {ListWrapper, MapWrapper} from 'angular2/src/core/facade/collection';
import {isPresent, isArray} from 'angular2/src/core/facade/lang';
import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
/**
* Converts a [DirectiveMetadata] to a map representation. This creates a copy,
* that is, subsequent changes to `meta` will not be mirrored in the map.
*/
export function directiveMetadataToMap(meta: RenderDirectiveMetadata): Map<string, any> {
return MapWrapper.createFromPairs([
['id', meta.id],
['selector', meta.selector],
['compileChildren', meta.compileChildren],
['hostProperties', _cloneIfPresent(meta.hostProperties)],
['hostListeners', _cloneIfPresent(meta.hostListeners)],
['hostActions', _cloneIfPresent(meta.hostActions)],
['hostAttributes', _cloneIfPresent(meta.hostAttributes)],
['properties', _cloneIfPresent(meta.properties)],
['readAttributes', _cloneIfPresent(meta.readAttributes)],
['type', meta.type],
['exportAs', meta.exportAs],
['callOnDestroy', meta.callOnDestroy],
['callOnCheck', meta.callOnCheck],
['callOnInit', meta.callOnInit],
['callOnChange', meta.callOnChange],
['callOnAllChangesDone', meta.callOnAllChangesDone],
['events', meta.events],
['changeDetection', meta.changeDetection],
['version', 1],
]);
}
/**
* Converts a map representation of [DirectiveMetadata] into a
* [DirectiveMetadata] object. This creates a copy, that is, subsequent changes
* to `map` will not be mirrored in the [DirectiveMetadata] object.
*/
export function directiveMetadataFromMap(map: Map<string, any>): RenderDirectiveMetadata {
return new RenderDirectiveMetadata({
id:<string>map.get('id'),
selector:<string>map.get('selector'),
compileChildren:<boolean>map.get('compileChildren'),
hostProperties:<Map<string, string>>_cloneIfPresent(map.get('hostProperties')),
hostListeners:<Map<string, string>>_cloneIfPresent(map.get('hostListeners')),
hostActions:<Map<string, string>>_cloneIfPresent(map.get('hostActions')),
hostAttributes:<Map<string, string>>_cloneIfPresent(map.get('hostAttributes')),
properties:<List<string>>_cloneIfPresent(map.get('properties')),
readAttributes:<List<string>>_cloneIfPresent(map.get('readAttributes')),
type:<number>map.get('type'),
exportAs:<string>map.get('exportAs'),
callOnDestroy:<boolean>map.get('callOnDestroy'),
callOnCheck:<boolean>map.get('callOnCheck'),
callOnChange:<boolean>map.get('callOnChange'),
callOnInit:<boolean>map.get('callOnInit'),
callOnAllChangesDone:<boolean>map.get('callOnAllChangesDone'),
events:<List<string>>_cloneIfPresent(map.get('events')),
changeDetection:<string>map.get('changeDetection'),
});
}
/**
* Clones the [List] or [Map] `o` if it is present.
*/
function _cloneIfPresent(o): any {
if (!isPresent(o)) return null;
return isArray(o) ? ListWrapper.clone(o) : MapWrapper.clone(o);
}

View File

@ -1,8 +1,7 @@
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
import {
DEFAULT,
ON_PUSH,
ChangeDetectionStrategy,
BindingRecord,
ChangeDetectorDefinition,
DirectiveIndex,
@ -12,7 +11,6 @@ import {
Parser,
ChangeDetectorGenConfig
} from 'angular2/src/core/change_detection/change_detection';
import {ON_PUSH_OBSERVE} from 'angular2/src/core/change_detection/constants';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
@ -109,15 +107,17 @@ export function getDefinition(id: string): TestDefinition {
} else if (id == "onPushObserveBinding") {
var records = _createBindingRecords("a");
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], records, [], [], genConfig);
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], records,
[], [], genConfig);
testDef = new TestDefinition(id, cdDef, null);
} else if (id == "onPushObserveComponent") {
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], [], [], [], genConfig);
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], [], [],
[], genConfig);
testDef = new TestDefinition(id, cdDef, null);
} else if (id == "onPushObserveDirective") {
let cdDef = new ChangeDetectorDefinition(id, ON_PUSH_OBSERVE, [], [], [],
let cdDef = new ChangeDetectorDefinition(id, ChangeDetectionStrategy.OnPushObserve, [], [], [],
[_DirectiveUpdating.recordNoCallbacks], genConfig);
testDef = new TestDefinition(id, cdDef, null);
} else if (id == "updateElementProduction") {
@ -196,7 +196,7 @@ class _ExpressionWithLocals {
}
class _ExpressionWithMode {
constructor(private _strategy: string, private _withRecords: boolean,
constructor(private _strategy: ChangeDetectionStrategy, private _withRecords: boolean,
private _withEvents: boolean) {}
createChangeDetectorDefinition(): ChangeDetectorDefinition {
@ -205,10 +205,14 @@ class _ExpressionWithMode {
var directiveRecords = [];
var eventRecords = [];
var dirRecordWithDefault =
new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0), changeDetection: DEFAULT});
var dirRecordWithOnPush =
new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 1), changeDetection: ON_PUSH});
var dirRecordWithDefault = new DirectiveRecord({
directiveIndex: new DirectiveIndex(0, 0),
changeDetection: ChangeDetectionStrategy.Default
});
var dirRecordWithOnPush = new DirectiveRecord({
directiveIndex: new DirectiveIndex(0, 1),
changeDetection: ChangeDetectionStrategy.OnPush
});
if (this._withRecords) {
var updateDirWithOnDefaultRecord =
@ -240,11 +244,14 @@ class _ExpressionWithMode {
* Definitions in this map define conditions which allow testing various change detector modes.
*/
static availableDefinitions: StringMap<string, _ExpressionWithMode> = {
'emptyUsingDefaultStrategy': new _ExpressionWithMode(DEFAULT, false, false),
'emptyUsingOnPushStrategy': new _ExpressionWithMode(ON_PUSH, false, false),
'onPushRecordsUsingDefaultStrategy': new _ExpressionWithMode(DEFAULT, true, false),
'onPushWithEvent': new _ExpressionWithMode(ON_PUSH, false, true),
'onPushWithHostEvent': new _ExpressionWithMode(ON_PUSH, false, true)
'emptyUsingDefaultStrategy':
new _ExpressionWithMode(ChangeDetectionStrategy.Default, false, false),
'emptyUsingOnPushStrategy':
new _ExpressionWithMode(ChangeDetectionStrategy.OnPush, false, false),
'onPushRecordsUsingDefaultStrategy':
new _ExpressionWithMode(ChangeDetectionStrategy.Default, true, false),
'onPushWithEvent': new _ExpressionWithMode(ChangeDetectionStrategy.OnPush, false, true),
'onPushWithHostEvent': new _ExpressionWithMode(ChangeDetectionStrategy.OnPush, false, true)
};
}

View File

@ -32,12 +32,7 @@ import {
DirectiveIndex,
PipeTransform,
PipeOnDestroy,
CHECK_ALWAYS,
CHECK_ONCE,
CHECKED,
DETACHED,
ON_PUSH,
DEFAULT,
ChangeDetectionStrategy,
WrappedValue,
DynamicProtoChangeDetector,
ChangeDetectorDefinition,
@ -673,26 +668,26 @@ export function main() {
});
describe('mode', () => {
it('should set the mode to CHECK_ALWAYS when the default change detection is used', () => {
it('should set the mode to CheckAlways when the default change detection is used', () => {
var cd = _createWithoutHydrate('emptyUsingDefaultStrategy').changeDetector;
expect(cd.mode).toEqual(null);
cd.hydrate(_DEFAULT_CONTEXT, null, null, null);
expect(cd.mode).toEqual(CHECK_ALWAYS);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckAlways);
});
it('should set the mode to CHECK_ONCE when the push change detection is used', () => {
it('should set the mode to CheckOnce when the push change detection is used', () => {
var cd = _createWithoutHydrate('emptyUsingOnPushStrategy').changeDetector;
cd.hydrate(_DEFAULT_CONTEXT, null, null, null);
expect(cd.mode).toEqual(CHECK_ONCE);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
});
it('should not check a detached change detector', () => {
var val = _createChangeDetector('a', new TestData('value'));
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, null, null);
val.changeDetector.mode = DETACHED;
val.changeDetector.mode = ChangeDetectionStrategy.Detached;
val.changeDetector.detectChanges();
expect(val.dispatcher.log).toEqual([]);
@ -702,33 +697,33 @@ export function main() {
var val = _createChangeDetector('a', new TestData('value'));
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, null, null);
val.changeDetector.mode = CHECKED;
val.changeDetector.mode = ChangeDetectionStrategy.Checked;
val.changeDetector.detectChanges();
expect(val.dispatcher.log).toEqual([]);
});
it('should change CHECK_ONCE to CHECKED', () => {
it('should change CheckOnce to Checked', () => {
var cd = _createChangeDetector('10').changeDetector;
cd.hydrate(_DEFAULT_CONTEXT, null, null, null);
cd.mode = CHECK_ONCE;
cd.mode = ChangeDetectionStrategy.CheckOnce;
cd.detectChanges();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
});
it('should not change the CHECK_ALWAYS', () => {
it('should not change the CheckAlways', () => {
var cd = _createChangeDetector('10').changeDetector;
cd.hydrate(_DEFAULT_CONTEXT, null, null, null);
cd.mode = CHECK_ALWAYS;
cd.mode = ChangeDetectionStrategy.CheckAlways;
cd.detectChanges();
expect(cd.mode).toEqual(CHECK_ALWAYS);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckAlways);
});
describe('marking ON_PUSH detectors as CHECK_ONCE after an update', () => {
describe('marking OnPush detectors as CheckOnce after an update', () => {
var childDirectiveDetectorRegular;
var childDirectiveDetectorOnPush;
var directives;
@ -736,53 +731,53 @@ export function main() {
beforeEach(() => {
childDirectiveDetectorRegular = _createWithoutHydrate('10').changeDetector;
childDirectiveDetectorRegular.hydrate(_DEFAULT_CONTEXT, null, null, null);
childDirectiveDetectorRegular.mode = CHECK_ALWAYS;
childDirectiveDetectorRegular.mode = ChangeDetectionStrategy.CheckAlways;
childDirectiveDetectorOnPush =
_createWithoutHydrate('emptyUsingOnPushStrategy').changeDetector;
childDirectiveDetectorOnPush.hydrate(_DEFAULT_CONTEXT, null, null, null);
childDirectiveDetectorOnPush.mode = CHECKED;
childDirectiveDetectorOnPush.mode = ChangeDetectionStrategy.Checked;
directives =
new FakeDirectives([new TestData(null), new TestData(null)],
[childDirectiveDetectorRegular, childDirectiveDetectorOnPush]);
});
it('should set the mode to CHECK_ONCE when a binding is updated', () => {
it('should set the mode to CheckOnce when a binding is updated', () => {
var parentDetector =
_createWithoutHydrate('onPushRecordsUsingDefaultStrategy').changeDetector;
parentDetector.hydrate(_DEFAULT_CONTEXT, null, directives, null);
parentDetector.detectChanges();
// making sure that we only change the status of ON_PUSH components
expect(childDirectiveDetectorRegular.mode).toEqual(CHECK_ALWAYS);
// making sure that we only change the status of OnPush components
expect(childDirectiveDetectorRegular.mode).toEqual(ChangeDetectionStrategy.CheckAlways);
expect(childDirectiveDetectorOnPush.mode).toEqual(CHECK_ONCE);
expect(childDirectiveDetectorOnPush.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
});
it('should mark ON_PUSH detectors as CHECK_ONCE after an event', () => {
it('should mark OnPush detectors as CheckOnce after an event', () => {
var cd = _createWithoutHydrate('onPushWithEvent').changeDetector;
cd.hydrate(_DEFAULT_CONTEXT, null, directives, null);
cd.mode = CHECKED;
cd.mode = ChangeDetectionStrategy.Checked;
cd.handleEvent("event", 0, null);
expect(cd.mode).toEqual(CHECK_ONCE);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
});
it('should mark ON_PUSH detectors as CHECK_ONCE after a host event', () => {
it('should mark OnPush detectors as CheckOnce after a host event', () => {
var cd = _createWithoutHydrate('onPushWithHostEvent').changeDetector;
cd.hydrate(_DEFAULT_CONTEXT, null, directives, null);
cd.handleEvent("host-event", 0, null);
expect(childDirectiveDetectorOnPush.mode).toEqual(CHECK_ONCE);
expect(childDirectiveDetectorOnPush.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
});
if (IS_DART) {
describe('ON_PUSH_OBSERVE', () => {
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable fires an event',
describe('OnPushObserve', () => {
it('should mark OnPushObserve detectors as CheckOnce when an observable fires an event',
fakeAsync(() => {
var context = new TestDirective();
context.a = createObservableModel();
@ -791,15 +786,15 @@ export function main() {
cd.hydrate(context, null, directives, null);
cd.detectChanges();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
context.a.pushUpdate();
tick();
expect(cd.mode).toEqual(CHECK_ONCE);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
}));
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable context fires an event',
it('should mark OnPushObserve detectors as CheckOnce when an observable context fires an event',
fakeAsync(() => {
var context = createObservableModel();
@ -807,15 +802,15 @@ export function main() {
cd.hydrate(context, null, directives, null);
cd.detectChanges();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
context.pushUpdate();
tick();
expect(cd.mode).toEqual(CHECK_ONCE);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
}));
it('should mark ON_PUSH_OBSERVE detectors as CHECK_ONCE when an observable directive fires an event',
it('should mark OnPushObserve detectors as CheckOnce when an observable directive fires an event',
fakeAsync(() => {
var dir = createObservableModel();
var directives = new FakeDirectives([dir], []);
@ -824,12 +819,12 @@ export function main() {
cd.hydrate(_DEFAULT_CONTEXT, null, directives, null);
cd.detectChanges();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
dir.pushUpdate();
tick();
expect(cd.mode).toEqual(CHECK_ONCE);
expect(cd.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
}));
it('should unsubscribe from an old observable when an object changes',
@ -843,14 +838,14 @@ export function main() {
cd.detectChanges();
context.a = createObservableModel();
cd.mode = CHECK_ONCE;
cd.mode = ChangeDetectionStrategy.CheckOnce;
cd.detectChanges();
// Updating this model will not reenable the detector. This model is not longer
// used.
originalModel.pushUpdate();
tick();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
}));
it('should unsubscribe from observables when dehydrating', fakeAsync(() => {
@ -872,7 +867,7 @@ export function main() {
// used.
originalModel.pushUpdate();
tick();
expect(cd.mode).toEqual(CHECKED);
expect(cd.mode).toEqual(ChangeDetectionStrategy.Checked);
}));
});
}
@ -887,22 +882,22 @@ export function main() {
return val.changeDetector;
}
it('should mark all checked detectors as CHECK_ONCE until reaching a detached one', () => {
var root = changeDetector(CHECK_ALWAYS, null);
var disabled = changeDetector(DETACHED, root);
var parent = changeDetector(CHECKED, disabled);
var checkAlwaysChild = changeDetector(CHECK_ALWAYS, parent);
var checkOnceChild = changeDetector(CHECK_ONCE, checkAlwaysChild);
var checkedChild = changeDetector(CHECKED, checkOnceChild);
it('should mark all checked detectors as CheckOnce until reaching a detached one', () => {
var root = changeDetector(ChangeDetectionStrategy.CheckAlways, null);
var disabled = changeDetector(ChangeDetectionStrategy.Detached, root);
var parent = changeDetector(ChangeDetectionStrategy.Checked, disabled);
var checkAlwaysChild = changeDetector(ChangeDetectionStrategy.CheckAlways, parent);
var checkOnceChild = changeDetector(ChangeDetectionStrategy.CheckOnce, checkAlwaysChild);
var checkedChild = changeDetector(ChangeDetectionStrategy.Checked, checkOnceChild);
checkedChild.markPathToRootAsCheckOnce();
expect(root.mode).toEqual(CHECK_ALWAYS);
expect(disabled.mode).toEqual(DETACHED);
expect(parent.mode).toEqual(CHECK_ONCE);
expect(checkAlwaysChild.mode).toEqual(CHECK_ALWAYS);
expect(checkOnceChild.mode).toEqual(CHECK_ONCE);
expect(checkedChild.mode).toEqual(CHECK_ONCE);
expect(root.mode).toEqual(ChangeDetectionStrategy.CheckAlways);
expect(disabled.mode).toEqual(ChangeDetectionStrategy.Detached);
expect(parent.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
expect(checkAlwaysChild.mode).toEqual(ChangeDetectionStrategy.CheckAlways);
expect(checkOnceChild.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
expect(checkedChild.mode).toEqual(ChangeDetectionStrategy.CheckOnce);
});
});

View File

@ -7,6 +7,7 @@ import 'package:angular2/test_lib.dart';
import 'package:observe/observe.dart';
import 'package:angular2/src/core/directives/observable_list_diff.dart';
import 'package:angular2/src/core/change_detection/differs/default_iterable_differ.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
class MockException implements Error {
var message;
@ -281,7 +282,7 @@ class OnChangeComponent implements OnChange {
@Component(
selector: 'component-with-observable-list',
changeDetection: ON_PUSH,
changeDetection: ChangeDetectionStrategy.OnPush,
properties: const ['list'],
bindings: const [
const Binding(IterableDiffers,

View File

@ -58,7 +58,7 @@ import {
import {
PipeTransform,
ChangeDetectorRef,
ON_PUSH,
ChangeDetectionStrategy,
ChangeDetection,
DynamicChangeDetection,
ChangeDetectorGenConfig
@ -635,7 +635,7 @@ export function main() {
}));
});
describe("ON_PUSH components", () => {
describe("OnPush components", () => {
it("should use ChangeDetectorRef to manually request a check",
inject([TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async) => {
@ -1672,7 +1672,8 @@ class DirectiveWithTitleAndHostProperty {
title: string;
}
@Component({selector: 'push-cmp', properties: ['prop'], changeDetection: ON_PUSH})
@Component(
{selector: 'push-cmp', properties: ['prop'], changeDetection: ChangeDetectionStrategy.OnPush})
@View({template: '{{field}}'})
@Injectable()
class PushCmp {
@ -1687,7 +1688,11 @@ class PushCmp {
}
}
@Component({selector: 'push-cmp-with-ref', properties: ['prop'], changeDetection: ON_PUSH})
@Component({
selector: 'push-cmp-with-ref',
properties: ['prop'],
changeDetection: ChangeDetectionStrategy.OnPush
})
@View({template: '{{field}}'})
@Injectable()
class PushCmpWithRef {
@ -1708,7 +1713,7 @@ class PushCmpWithRef {
propagate() { this.ref.requestCheck(); }
}
@Component({selector: 'push-cmp-with-async', changeDetection: ON_PUSH})
@Component({selector: 'push-cmp-with-async', changeDetection: ChangeDetectionStrategy.OnPush})
@View({template: '{{field | async}}'})
@Injectable()
class PushCmpWithAsyncPipe {

View File

@ -1,95 +0,0 @@
import {MapWrapper} from 'angular2/src/core/facade/collection';
import {RenderDirectiveMetadata} from 'angular2/src/core/render/api';
import {
directiveMetadataFromMap,
directiveMetadataToMap
} from 'angular2/src/core/render/dom/convert';
import {ddescribe, describe, expect, it} from 'angular2/test_lib';
export function main() {
describe('convert', () => {
it('directiveMetadataToMap', () => {
var someComponent = new RenderDirectiveMetadata({
compileChildren: false,
hostListeners: MapWrapper.createFromPairs([['LKey', 'LVal']]),
hostProperties: MapWrapper.createFromPairs([['PKey', 'PVal']]),
hostActions: MapWrapper.createFromPairs([['AcKey', 'AcVal']]),
hostAttributes: MapWrapper.createFromPairs([['AtKey', 'AtVal']]),
id: 'someComponent',
properties: ['propKey: propVal'],
readAttributes: ['read1', 'read2'],
selector: 'some-comp',
type: RenderDirectiveMetadata.COMPONENT_TYPE,
exportAs: 'aaa',
callOnDestroy: true,
callOnChange: true,
callOnCheck: true,
callOnInit: true,
callOnAllChangesDone: true,
events: ['onFoo', 'onBar'],
changeDetection: 'CHECK_ONCE'
});
var map = directiveMetadataToMap(someComponent);
expect(map.get('compileChildren')).toEqual(false);
expect(map.get('hostListeners')).toEqual(MapWrapper.createFromPairs([['LKey', 'LVal']]));
expect(map.get('hostProperties')).toEqual(MapWrapper.createFromPairs([['PKey', 'PVal']]));
expect(map.get('hostActions')).toEqual(MapWrapper.createFromPairs([['AcKey', 'AcVal']]));
expect(map.get('hostAttributes')).toEqual(MapWrapper.createFromPairs([['AtKey', 'AtVal']]));
expect(map.get('id')).toEqual('someComponent');
expect(map.get('properties')).toEqual(['propKey: propVal']);
expect(map.get('readAttributes')).toEqual(['read1', 'read2']);
expect(map.get('selector')).toEqual('some-comp');
expect(map.get('type')).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
expect(map.get('callOnDestroy')).toEqual(true);
expect(map.get('callOnCheck')).toEqual(true);
expect(map.get('callOnChange')).toEqual(true);
expect(map.get('callOnInit')).toEqual(true);
expect(map.get('callOnAllChangesDone')).toEqual(true);
expect(map.get('exportAs')).toEqual('aaa');
expect(map.get('events')).toEqual(['onFoo', 'onBar']);
expect(map.get('changeDetection')).toEqual('CHECK_ONCE');
});
it('mapToDirectiveMetadata', () => {
var map = MapWrapper.createFromPairs([
['compileChildren', false],
['hostProperties', MapWrapper.createFromPairs([['PKey', 'testVal']])],
['hostListeners', MapWrapper.createFromPairs([['LKey', 'testVal']])],
['hostActions', MapWrapper.createFromPairs([['AcKey', 'testVal']])],
['hostAttributes', MapWrapper.createFromPairs([['AtKey', 'testVal']])],
['id', 'testId'],
['properties', ['propKey: propVal']],
['readAttributes', ['readTest1', 'readTest2']],
['selector', 'testSelector'],
['type', RenderDirectiveMetadata.DIRECTIVE_TYPE],
['exportAs', 'aaa'],
['callOnDestroy', true],
['callOnCheck', true],
['callOnInit', true],
['callOnChange', true],
['callOnAllChangesDone', true],
['events', ['onFoo', 'onBar']],
['changeDetection', 'CHECK_ONCE']
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
expect(meta.hostProperties).toEqual(MapWrapper.createFromPairs([['PKey', 'testVal']]));
expect(meta.hostListeners).toEqual(MapWrapper.createFromPairs([['LKey', 'testVal']]));
expect(meta.hostActions).toEqual(MapWrapper.createFromPairs([['AcKey', 'testVal']]));
expect(meta.hostAttributes).toEqual(MapWrapper.createFromPairs([['AtKey', 'testVal']]));
expect(meta.id).toEqual('testId');
expect(meta.properties).toEqual(['propKey: propVal']);
expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']);
expect(meta.selector).toEqual('testSelector');
expect(meta.type).toEqual(RenderDirectiveMetadata.DIRECTIVE_TYPE);
expect(meta.exportAs).toEqual('aaa');
expect(meta.callOnDestroy).toEqual(true);
expect(meta.callOnCheck).toEqual(true);
expect(meta.callOnInit).toEqual(true);
expect(meta.callOnChange).toEqual(true);
expect(meta.callOnAllChangesDone).toEqual(true);
expect(meta.events).toEqual(['onFoo', 'onBar']);
expect(meta.changeDetection).toEqual('CHECK_ONCE');
});
});
}

View File

@ -15,8 +15,7 @@ import {
ChangeDetectorGenConfig,
BindingRecord,
DirectiveRecord,
DirectiveIndex,
DEFAULT
DirectiveIndex
} from 'angular2/src/core/change_detection/change_detection';

View File

@ -5,7 +5,7 @@ import "package:angular2/src/core/facade/collection.dart"
import "common.dart"
show Company, Opportunity, Offering, Account, CustomDate, STATUS_LIST;
import "package:angular2/directives.dart" show NgFor;
import "package:angular2/angular2.dart" show Component, Directive, View;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
class HasStyle {
int cellWidth;
@ -17,7 +17,7 @@ class HasStyle {
@Component(
selector: "company-name",
properties: const ["width: cell-width", "company"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
@ -29,7 +29,7 @@ class CompanyNameComponent extends HasStyle {
@Component(
selector: "opportunity-name",
properties: const ["width: cell-width", "opportunity"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
@ -41,7 +41,7 @@ class OpportunityNameComponent extends HasStyle {
@Component(
selector: "offering-name",
properties: const ["width: cell-width", "offering"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
@ -59,7 +59,7 @@ class Stage {
@Component(
selector: "stage-buttons",
properties: const ["width: cell-width", "offering"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(directives: const [NgFor], template: '''
<div [style.width.px]="cellWidth">
@ -103,7 +103,7 @@ class StageButtonsComponent extends HasStyle {
@Component(
selector: "account-cell",
properties: const ["width: cell-width", "account"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(directives: const [], template: '''
<div [style.width.px]="cellWidth">
@ -117,7 +117,7 @@ class AccountCellComponent extends HasStyle {
@Component(
selector: "formatted-cell",
properties: const ["width: cell-width", "value"],
changeDetection: "ON_PUSH_OBSERVE"
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],

View File

@ -2,7 +2,7 @@ library benchmarks.src.naive_infinite_scroll.scroll_area;
import "package:angular2/src/core/facade/collection.dart" show ListWrapper;
import "package:angular2/src/core/facade/math.dart" show Math;
import "package:angular2/angular2.dart" show Component, Directive, View;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
import "common.dart"
show
Offering,
@ -16,7 +16,7 @@ import "random_data.dart" show generateOfferings;
import "scroll_item.dart" show ScrollItemComponent;
import "package:angular2/directives.dart" show NgFor;
@Component(selector: "scroll-area", changeDetection: "ON_PUSH_OBSERVE")
@Component(selector: "scroll-area", changeDetection: ChangeDetectionStrategy.OnPushObserve)
@View(directives: const [ScrollItemComponent, NgFor], template: '''
<div>
<div id="scrollDiv"

View File

@ -8,7 +8,7 @@ import "cells.dart"
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent;
import "package:angular2/angular2.dart" show Component, Directive, View;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
import "common.dart"
show
Offering,
@ -25,7 +25,8 @@ import "common.dart"
END_DATE_WIDTH,
AAT_STATUS_WIDTH;
@Component(selector: "scroll-item", properties: const ["offering"], changeDetection: "ON_PUSH_OBSERVE")
@Component(selector: "scroll-item", properties: const ["offering"],
changeDetection: ChangeDetectionStrategy.OnPushObserve)
@View(
directives: const [
CompanyNameComponent,

View File

@ -0,0 +1,71 @@
library angular2.transform.common.convert;
import "package:angular2/src/core/facade/collection.dart"
show ListWrapper, MapWrapper;
import "package:angular2/src/core/facade/lang.dart" show isPresent, isArray;
import "package:angular2/src/core/render/api.dart" show RenderDirectiveMetadata;
import "package:angular2/src/core/change_detection/change_detection.dart"
show ChangeDetectionStrategy;
/**
* Converts a [DirectiveMetadata] to a map representation. This creates a copy,
* that is, subsequent changes to `meta` will not be mirrored in the map.
*/
Map<String, dynamic> directiveMetadataToMap(RenderDirectiveMetadata meta) {
return MapWrapper.createFromPairs([
["id", meta.id],
["selector", meta.selector],
["compileChildren", meta.compileChildren],
["hostProperties", _cloneIfPresent(meta.hostProperties)],
["hostListeners", _cloneIfPresent(meta.hostListeners)],
["hostAttributes", _cloneIfPresent(meta.hostAttributes)],
["properties", _cloneIfPresent(meta.properties)],
["readAttributes", _cloneIfPresent(meta.readAttributes)],
["type", meta.type],
["exportAs", meta.exportAs],
["callOnDestroy", meta.callOnDestroy],
["callOnCheck", meta.callOnCheck],
["callOnInit", meta.callOnInit],
["callOnChange", meta.callOnChange],
["callOnAllChangesDone", meta.callOnAllChangesDone],
["events", meta.events],
["changeDetection", meta.changeDetection == null ? null : meta.changeDetection.index],
["version", 1]
]);
}
/**
* Converts a map representation of [DirectiveMetadata] into a
* [DirectiveMetadata] object. This creates a copy, that is, subsequent changes
* to `map` will not be mirrored in the [DirectiveMetadata] object.
*/
RenderDirectiveMetadata directiveMetadataFromMap(Map<String, dynamic> map) {
return new RenderDirectiveMetadata(
id: (map["id"] as String),
selector: (map["selector"] as String),
compileChildren: (map["compileChildren"] as bool),
hostProperties: (_cloneIfPresent(
map["hostProperties"]) as Map<String, String>),
hostListeners: (_cloneIfPresent(
map["hostListeners"]) as Map<String, String>),
hostAttributes: (_cloneIfPresent(
map["hostAttributes"]) as Map<String, String>),
properties: (_cloneIfPresent(map["properties"]) as List<String>),
readAttributes: (_cloneIfPresent(map["readAttributes"]) as List<String>),
type: (map["type"] as num),
exportAs: (map["exportAs"] as String),
callOnDestroy: (map["callOnDestroy"] as bool),
callOnCheck: (map["callOnCheck"] as bool),
callOnChange: (map["callOnChange"] as bool),
callOnInit: (map["callOnInit"] as bool),
callOnAllChangesDone: (map["callOnAllChangesDone"] as bool),
events: (_cloneIfPresent(map["events"]) as List<String>),
changeDetection: map["changeDetection"] == null ? null
: ChangeDetectionStrategy.values[map["changeDetection"] as int]);
}
/**
* Clones the [List] or [Map] `o` if it is present.
*/
dynamic _cloneIfPresent(o) {
if (!isPresent(o)) return null;
return isArray(o) ? ListWrapper.clone(o) : MapWrapper.clone(o);
}

View File

@ -3,6 +3,7 @@ library angular2.transform.common.directive_metadata_reader;
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
/// Reads [RenderDirectiveMetadata] from the `node`. `node` is expected to be an
/// instance of [Annotation], [NodeList<Annotation>], ListLiteral, or
@ -63,7 +64,7 @@ class _DirectiveMetadataVisitor extends Object
bool _callOnCheck;
bool _callOnInit;
bool _callOnAllChangesDone;
String _changeDetection;
ChangeDetectionStrategy _changeDetection;
List<String> _events;
final ConstantEvaluator _evaluator = new ConstantEvaluator();
@ -283,6 +284,9 @@ class _DirectiveMetadataVisitor extends Object
void _populateChangeDetection(Expression value) {
_checkMeta();
_changeDetection = _expressionToString(value, 'Directive#changeDetection');
_changeDetection = changeDetectionStrategies[value.toSource()];
}
}
final Map<String, ChangeDetectionStrategy> changeDetectionStrategies
= new Map.fromIterable(ChangeDetectionStrategy.values, key: (v) => v.toString());

View File

@ -1,7 +1,7 @@
library angular2.transform.common.ng_meta;
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/render/dom/convert.dart';
import 'convert.dart';
import 'logging.dart';
/// Metadata about directives and directive aliases.

View File

@ -1,5 +1,6 @@
library angular2.transform.template_compiler.change_detector_codegen;
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/core/change_detection/change_detection_util.dart';
import 'package:angular2/src/core/change_detection/codegen_facade.dart';
import 'package:angular2/src/core/change_detection/codegen_logic_util.dart';
@ -75,7 +76,7 @@ class _CodegenState {
/// The name of the generated change detector class. This is an implementation
/// detail and should not be visible to users.
final String _changeDetectorTypeName;
final String _changeDetectionStrategy;
final ChangeDetectionStrategy _changeDetectionStrategy;
final List<DirectiveRecord> _directiveRecords;
final List<ProtoRecord> _records;
final List<EventBinding> _eventBindings;
@ -84,6 +85,9 @@ class _CodegenState {
final ChangeDetectorGenConfig _genConfig;
final List<BindingTarget> _propertyBindingTargets;
String get _changeDetectionStrategyAsCode =>
_changeDetectionStrategy == null ? 'null' : '${_GEN_PREFIX}.${_changeDetectionStrategy}';
_CodegenState._(
this._changeDetectorDefId,
this._contextTypeName,
@ -129,7 +133,7 @@ class _CodegenState {
dispatcher, ${_records.length},
${_changeDetectorTypeName}.gen_propertyBindingTargets,
${_changeDetectorTypeName}.gen_directiveIndices,
${codify(_changeDetectionStrategy)}) {
${_changeDetectionStrategyAsCode}) {
dehydrateDirectives(false);
}

View File

@ -0,0 +1,97 @@
library angular2.test.transform.common.convert_spec;
import "package:angular2/src/core/facade/collection.dart" show MapWrapper;
import "package:angular2/src/core/render/api.dart" show RenderDirectiveMetadata;
import "package:angular2/src/transform/common/convert.dart"
show directiveMetadataFromMap, directiveMetadataToMap;
import "package:angular2/test_lib.dart" show ddescribe, describe, expect, it;
import "package:angular2/src/core/change_detection/change_detection.dart"
show ChangeDetectionStrategy;
main() {
describe("convert", () {
it("directiveMetadataToMap", () {
var someComponent = new RenderDirectiveMetadata(
compileChildren: false,
hostListeners: MapWrapper.createFromPairs([["LKey", "LVal"]]),
hostProperties: MapWrapper.createFromPairs([["PKey", "PVal"]]),
hostAttributes: MapWrapper.createFromPairs([["AtKey", "AtVal"]]),
id: "someComponent",
properties: ["propKey: propVal"],
readAttributes: ["read1", "read2"],
selector: "some-comp",
type: RenderDirectiveMetadata.COMPONENT_TYPE,
exportAs: "aaa",
callOnDestroy: true,
callOnChange: true,
callOnCheck: true,
callOnInit: true,
callOnAllChangesDone: true,
events: ["onFoo", "onBar"],
changeDetection: ChangeDetectionStrategy.CheckOnce);
var map = directiveMetadataToMap(someComponent);
expect(map["compileChildren"]).toEqual(false);
expect(map["hostListeners"])
.toEqual(MapWrapper.createFromPairs([["LKey", "LVal"]]));
expect(map["hostProperties"])
.toEqual(MapWrapper.createFromPairs([["PKey", "PVal"]]));
expect(map["hostAttributes"])
.toEqual(MapWrapper.createFromPairs([["AtKey", "AtVal"]]));
expect(map["id"]).toEqual("someComponent");
expect(map["properties"]).toEqual(["propKey: propVal"]);
expect(map["readAttributes"]).toEqual(["read1", "read2"]);
expect(map["selector"]).toEqual("some-comp");
expect(map["type"]).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
expect(map["callOnDestroy"]).toEqual(true);
expect(map["callOnCheck"]).toEqual(true);
expect(map["callOnChange"]).toEqual(true);
expect(map["callOnInit"]).toEqual(true);
expect(map["callOnAllChangesDone"]).toEqual(true);
expect(map["exportAs"]).toEqual("aaa");
expect(map["events"]).toEqual(["onFoo", "onBar"]);
expect(map["changeDetection"]).toEqual(ChangeDetectionStrategy.CheckOnce.index);
});
it("mapToDirectiveMetadata", () {
var map = MapWrapper.createFromPairs([
["compileChildren", false],
["hostProperties", MapWrapper.createFromPairs([["PKey", "testVal"]])],
["hostListeners", MapWrapper.createFromPairs([["LKey", "testVal"]])],
["hostAttributes", MapWrapper.createFromPairs([["AtKey", "testVal"]])],
["id", "testId"],
["properties", ["propKey: propVal"]],
["readAttributes", ["readTest1", "readTest2"]],
["selector", "testSelector"],
["type", RenderDirectiveMetadata.DIRECTIVE_TYPE],
["exportAs", "aaa"],
["callOnDestroy", true],
["callOnCheck", true],
["callOnInit", true],
["callOnChange", true],
["callOnAllChangesDone", true],
["events", ["onFoo", "onBar"]],
["changeDetection", ChangeDetectionStrategy.CheckOnce.index]
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
expect(meta.hostProperties)
.toEqual(MapWrapper.createFromPairs([["PKey", "testVal"]]));
expect(meta.hostListeners)
.toEqual(MapWrapper.createFromPairs([["LKey", "testVal"]]));
expect(meta.hostAttributes)
.toEqual(MapWrapper.createFromPairs([["AtKey", "testVal"]]));
expect(meta.id).toEqual("testId");
expect(meta.properties).toEqual(["propKey: propVal"]);
expect(meta.readAttributes).toEqual(["readTest1", "readTest2"]);
expect(meta.selector).toEqual("testSelector");
expect(meta.type).toEqual(RenderDirectiveMetadata.DIRECTIVE_TYPE);
expect(meta.exportAs).toEqual("aaa");
expect(meta.callOnDestroy).toEqual(true);
expect(meta.callOnCheck).toEqual(true);
expect(meta.callOnInit).toEqual(true);
expect(meta.callOnChange).toEqual(true);
expect(meta.callOnAllChangesDone).toEqual(true);
expect(meta.events).toEqual(["onFoo", "onBar"]);
expect(meta.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
});
});
}

View File

@ -2,7 +2,8 @@ library angular2.test.transform.directive_metadata_extractor.all_tests;
import 'dart:async';
import 'package:angular2/src/core/render/api.dart';
import 'package:angular2/src/core/render/dom/convert.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/transform/common/convert.dart';
import 'package:angular2/src/transform/common/directive_metadata_reader.dart';
import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/ng_deps.dart';
@ -122,7 +123,7 @@ void allTests() {
it('should parse changeDetection.', () async {
var metadata = await readMetadata('directive_metadata_extractor/'
'directive_metadata_files/changeDetection.ng_deps.dart');
expect(metadata.changeDetection).toEqual('CHECK_ONCE');
expect(metadata.changeDetection).toEqual(ChangeDetectionStrategy.CheckOnce);
});
it('should fail when a class is annotated with multiple Directives.',

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, LifecycleEvent, ChangeDetectionStrategy;
var _visited = false;
void initReflector(reflector) {
@ -12,7 +12,7 @@ void initReflector(reflector) {
..registerType(
HelloCmp,
new ReflectionInfo(
const [const Component(changeDetection: 'CHECK_ONCE')],
const [const Component(changeDetection: ChangeDetectionStrategy.CheckOnce)],
const [const []],
() => new HelloCmp()));
}