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

@ -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 const CHECK_ONCE: string = "CHECK_ONCE";
export enum ChangeDetectionStrategy {
/**
* `CheckedOnce` means that after calling detectChanges the mode of the change detector
* will become `Checked`.
*/
CheckOnce,
/**
* CHECKED means that the change detector should be skipped until its mode changes to
* CHECK_ONCE or CHECK_ALWAYS.
*/
export const CHECKED: string = "CHECKED";
/**
* `Checked` means that the change detector should be skipped until its mode changes to
* `CheckOnce`.
*/
Checked,
/**
* CHECK_ALWAYS means that after calling detectChanges the mode of the change detector
* will remain CHECK_ALWAYS.
*/
export const CHECK_ALWAYS: string = "ALWAYS_CHECK";
/**
* `CheckAlways` means that after calling detectChanges the mode of the change detector
* will remain `CheckAlways`.
*/
CheckAlways,
/**
* 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` means that the change detector sub tree is not a part of the main tree and
* should be skipped.
*/
Detached,
/**
* ON_PUSH means that the change detector's mode will be set to CHECK_ONCE during hydration.
*/
export const ON_PUSH: string = "ON_PUSH";
/**
* `OnPush` means that the change detector's mode will be set to `CheckOnce` during hydration.
*/
OnPush,
/**
* DEFAULT means that the change detector's mode will be set to CHECK_ALWAYS during hydration.
*/
export const DEFAULT: string = "DEFAULT";
/**
* `Default` means that the change detector's mode will be set to `CheckAlways` during hydration.
*/
Default,
export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: string): boolean {
return isBlank(changeDetectionStrategy) || StringWrapper.equals(changeDetectionStrategy, DEFAULT);
/**
* This is an experimental feature. Works only in Dart.
*/
OnPushObserve
}
/**
* This is an experimental feature. Works only in Dart.
*/
export const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
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);
@ -35,4 +35,4 @@ export class DirectiveRecord {
isDefaultChangeDetection(): boolean {
return isDefaultChangeDetectionStrategy(this.changeDetection);
}
}
}

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'