refactor(change_detection): removed NO_CHANGED and replaced it with WrappedValue
This commit is contained in:
parent
4c1e978536
commit
e4586249fa
|
@ -23,7 +23,7 @@ export {DynamicChangeDetector} from './src/change_detection/dynamic_change_detec
|
||||||
export {ChangeDetectorRef} from './src/change_detection/change_detector_ref';
|
export {ChangeDetectorRef} from './src/change_detection/change_detector_ref';
|
||||||
export {PipeRegistry} from './src/change_detection/pipes/pipe_registry';
|
export {PipeRegistry} from './src/change_detection/pipes/pipe_registry';
|
||||||
export {uninitialized} from './src/change_detection/change_detection_util';
|
export {uninitialized} from './src/change_detection/change_detection_util';
|
||||||
export {NO_CHANGE, Pipe} from './src/change_detection/pipes/pipe';
|
export {WrappedValue, Pipe} from './src/change_detection/pipes/pipe';
|
||||||
export {
|
export {
|
||||||
defaultPipes, DynamicChangeDetection, JitChangeDetection, defaultPipeRegistry
|
defaultPipes, DynamicChangeDetection, JitChangeDetection, defaultPipeRegistry
|
||||||
} from './src/change_detection/change_detection';
|
} from './src/change_detection/change_detection';
|
||||||
|
|
|
@ -156,7 +156,8 @@ if (${pipe} === ${UTIL}.unitialized()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
${newValue} = ${pipe}.transform(${context});
|
${newValue} = ${pipe}.transform(${context});
|
||||||
if (! ${UTIL}.noChangeMarker(${newValue})) {
|
if (${oldValue} !== ${newValue}) {
|
||||||
|
${newValue} = ${UTIL}.unwrapValue(${newValue});
|
||||||
${change} = true;
|
${change} = true;
|
||||||
${update}
|
${update}
|
||||||
${addToChanges}
|
${addToChanges}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {isPresent, isBlank, BaseException, Type} from 'angular2/src/facade/lang'
|
||||||
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {ProtoRecord} from './proto_record';
|
import {ProtoRecord} from './proto_record';
|
||||||
import {ExpressionChangedAfterItHasBeenChecked} from './exceptions';
|
import {ExpressionChangedAfterItHasBeenChecked} from './exceptions';
|
||||||
import {NO_CHANGE} from './pipes/pipe';
|
import {WrappedValue} from './pipes/pipe';
|
||||||
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
|
||||||
|
|
||||||
export var uninitialized = new Object();
|
export var uninitialized = new Object();
|
||||||
|
@ -109,8 +109,12 @@ export class ChangeDetectionUtil {
|
||||||
return obj[args[0]];
|
return obj[args[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
static noChangeMarker(value):boolean {
|
static unwrapValue(value:any):any {
|
||||||
return value === NO_CHANGE;
|
if (value instanceof WrappedValue) {
|
||||||
|
return value.wrapped;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static throwOnChange(proto:ProtoRecord, change) {
|
static throwOnChange(proto:ProtoRecord, change) {
|
||||||
|
|
|
@ -233,11 +233,13 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
_pipeCheck(proto:ProtoRecord) {
|
_pipeCheck(proto:ProtoRecord) {
|
||||||
var context = this._readContext(proto);
|
var context = this._readContext(proto);
|
||||||
var pipe = this._pipeFor(proto, context);
|
var pipe = this._pipeFor(proto, context);
|
||||||
|
var prevValue = this._readSelf(proto);
|
||||||
|
|
||||||
var newValue = pipe.transform(context);
|
var newValue = pipe.transform(context);
|
||||||
|
|
||||||
if (! ChangeDetectionUtil.noChangeMarker(newValue)) {
|
if (!isSame(prevValue, newValue)) {
|
||||||
var prevValue = this._readSelf(proto);
|
newValue = ChangeDetectionUtil.unwrapValue(newValue);
|
||||||
|
|
||||||
this._writeSelf(proto, newValue);
|
this._writeSelf(proto, newValue);
|
||||||
this._setChanged(proto, true);
|
this._setChanged(proto, true);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Observable, ObservableWrapper} from 'angular2/src/facade/async';
|
import {Observable, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {Pipe, NO_CHANGE} from './pipe';
|
import {Pipe, WrappedValue} from './pipe';
|
||||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,10 +67,10 @@ export class AsyncPipe extends Pipe {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._latestValue === this._latestReturnedValue) {
|
if (this._latestValue === this._latestReturnedValue) {
|
||||||
return NO_CHANGE;
|
return this._latestReturnedValue;
|
||||||
} else {
|
} else {
|
||||||
this._latestReturnedValue = this._latestValue;
|
this._latestReturnedValue = this._latestValue;
|
||||||
return this._latestValue;
|
return WrappedValue.wrap(this._latestValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
looseIdentical,
|
looseIdentical,
|
||||||
} from 'angular2/src/facade/lang';
|
} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {NO_CHANGE, Pipe} from './pipe';
|
import {WrappedValue, Pipe} from './pipe';
|
||||||
|
|
||||||
export class IterableChangesFactory {
|
export class IterableChangesFactory {
|
||||||
supports(obj):boolean {
|
supports(obj):boolean {
|
||||||
|
@ -117,9 +117,9 @@ export class IterableChanges extends Pipe {
|
||||||
|
|
||||||
transform(collection){
|
transform(collection){
|
||||||
if (this.check(collection)) {
|
if (this.check(collection)) {
|
||||||
return this;
|
return WrappedValue.wrap(this);
|
||||||
} else {
|
} else {
|
||||||
return NO_CHANGE;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {stringify, looseIdentical, isJsObject} from 'angular2/src/facade/lang';
|
import {stringify, looseIdentical, isJsObject} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {NO_CHANGE, Pipe} from './pipe';
|
import {WrappedValue, Pipe} from './pipe';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exportedAs angular2/pipes
|
* @exportedAs angular2/pipes
|
||||||
|
@ -54,9 +54,9 @@ export class KeyValueChanges extends Pipe {
|
||||||
|
|
||||||
transform(map){
|
transform(map){
|
||||||
if (this.check(map)) {
|
if (this.check(map)) {
|
||||||
return this;
|
return WrappedValue.wrap(this);
|
||||||
} else {
|
} else {
|
||||||
return NO_CHANGE;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {isBlank} from 'angular2/src/facade/lang';
|
import {isBlank} from 'angular2/src/facade/lang';
|
||||||
import {Pipe, NO_CHANGE} from './pipe';
|
import {Pipe, WrappedValue} from './pipe';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exportedAs angular2/pipes
|
* @exportedAs angular2/pipes
|
||||||
|
@ -35,9 +35,9 @@ export class NullPipe extends Pipe {
|
||||||
transform(value) {
|
transform(value) {
|
||||||
if (! this.called) {
|
if (! this.called) {
|
||||||
this.called = true;
|
this.called = true;
|
||||||
return null;
|
return WrappedValue.wrap(null);
|
||||||
} else {
|
} else {
|
||||||
return NO_CHANGE;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,33 @@
|
||||||
/**
|
/**
|
||||||
* Indicates that the result of a {@link Pipe} transformation has not changed since the last time the pipe was called.
|
* Indicates that the result of a {@link Pipe} transformation has changed even though the reference has not changed.
|
||||||
*
|
*
|
||||||
* Suppose we have a pipe that computes changes in an array by performing a simple diff operation. If
|
* The wrapped value will be unwrapped by change detection, and the unwrapped value will be stored.
|
||||||
* we call this pipe with the same array twice, it will return `NO_CHANGE` the second time.
|
|
||||||
*
|
*
|
||||||
* @exportedAs angular2/pipes
|
* @exportedAs angular2/pipes
|
||||||
*/
|
*/
|
||||||
|
export class WrappedValue {
|
||||||
|
wrapped:any;
|
||||||
|
|
||||||
export var NO_CHANGE = new Object();
|
constructor(wrapped:any) {
|
||||||
|
this.wrapped = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wrap(value:any):WrappedValue {
|
||||||
|
var w = _wrappedValues[_wrappedIndex++ % 5];
|
||||||
|
w.wrapped = value;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _wrappedValues = [
|
||||||
|
new WrappedValue(null),
|
||||||
|
new WrappedValue(null),
|
||||||
|
new WrappedValue(null),
|
||||||
|
new WrappedValue(null),
|
||||||
|
new WrappedValue(null)
|
||||||
|
];
|
||||||
|
|
||||||
|
var _wrappedIndex = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for extending the list of pipes known to Angular.
|
* An interface for extending the list of pipes known to Angular.
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {Lexer} from 'angular2/src/change_detection/parser/lexer';
|
||||||
import {Locals} from 'angular2/src/change_detection/parser/locals';
|
import {Locals} from 'angular2/src/change_detection/parser/locals';
|
||||||
|
|
||||||
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, BindingRecord, DirectiveRecord, DirectiveIndex,
|
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, BindingRecord, DirectiveRecord, DirectiveIndex,
|
||||||
PipeRegistry, Pipe, NO_CHANGE, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH, DEFAULT} from 'angular2/change_detection';
|
PipeRegistry, Pipe, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH, DEFAULT, WrappedValue} from 'angular2/change_detection';
|
||||||
|
|
||||||
import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/change_detection/proto_change_detector';
|
import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/change_detection/proto_change_detector';
|
||||||
|
|
||||||
|
@ -733,7 +733,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should do nothing when returns NO_CHANGE", () => {
|
it("should do nothing when no change", () => {
|
||||||
var registry = new FakePipeRegistry('pipe', () => new IdentityPipe())
|
var registry = new FakePipeRegistry('pipe', () => new IdentityPipe())
|
||||||
var ctx = new Person("Megatron");
|
var ctx = new Person("Megatron");
|
||||||
|
|
||||||
|
@ -741,16 +741,27 @@ export function main() {
|
||||||
var cd = c["changeDetector"];
|
var cd = c["changeDetector"];
|
||||||
var dispatcher = c["dispatcher"];
|
var dispatcher = c["dispatcher"];
|
||||||
|
|
||||||
cd.detectChanges();
|
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
|
|
||||||
expect(dispatcher.log).toEqual(['memo=Megatron']);
|
expect(dispatcher.log).toEqual(['memo=Megatron']);
|
||||||
|
|
||||||
ctx.name = "Optimus Prime";
|
|
||||||
dispatcher.clear();
|
dispatcher.clear();
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
|
|
||||||
expect(dispatcher.log).toEqual(['memo=Optimus Prime']);
|
expect(dispatcher.log).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should unwrap the wrapped value", () => {
|
||||||
|
var registry = new FakePipeRegistry('pipe', () => new WrappedPipe())
|
||||||
|
var ctx = new Person("Megatron");
|
||||||
|
|
||||||
|
var c = createChangeDetector("memo", "name | pipe", ctx, null, registry);
|
||||||
|
var cd = c["changeDetector"];
|
||||||
|
var dispatcher = c["dispatcher"];
|
||||||
|
|
||||||
|
cd.detectChanges();
|
||||||
|
|
||||||
|
expect(dispatcher.log).toEqual(['memo=Megatron']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -798,19 +809,14 @@ class OncePipe extends Pipe {
|
||||||
}
|
}
|
||||||
|
|
||||||
class IdentityPipe extends Pipe {
|
class IdentityPipe extends Pipe {
|
||||||
state:any;
|
|
||||||
|
|
||||||
supports(newValue) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
transform(value) {
|
transform(value) {
|
||||||
if (this.state === value) {
|
return value;
|
||||||
return NO_CHANGE;
|
}
|
||||||
} else {
|
}
|
||||||
this.state = value;
|
|
||||||
return value;
|
class WrappedPipe extends Pipe {
|
||||||
}
|
transform(value) {
|
||||||
|
return WrappedValue.wrap(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach,
|
||||||
AsyncTestCompleter, inject, proxy, SpyObject} from 'angular2/test_lib';
|
AsyncTestCompleter, inject, proxy, SpyObject} from 'angular2/test_lib';
|
||||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
|
import {WrappedValue} from 'angular2/src/change_detection/pipes/pipe';
|
||||||
import {AsyncPipe} from 'angular2/src/change_detection/pipes/async_pipe';
|
import {AsyncPipe} from 'angular2/src/change_detection/pipes/async_pipe';
|
||||||
import {NO_CHANGE} from 'angular2/src/change_detection/pipes/pipe';
|
|
||||||
import {ChangeDetectorRef} from 'angular2/src/change_detection/change_detector_ref';
|
import {ChangeDetectorRef} from 'angular2/src/change_detection/change_detector_ref';
|
||||||
import {EventEmitter, Observable, ObservableWrapper, PromiseWrapper} from 'angular2/src/facade/async';
|
import {EventEmitter, Observable, ObservableWrapper, PromiseWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
@ -36,25 +36,25 @@ export function main() {
|
||||||
expect(pipe.transform(emitter)).toBe(null);
|
expect(pipe.transform(emitter)).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the latest available value", inject([AsyncTestCompleter], (async) => {
|
it("should return the latest available value wrapped", inject([AsyncTestCompleter], (async) => {
|
||||||
pipe.transform(emitter);
|
pipe.transform(emitter);
|
||||||
|
|
||||||
ObservableWrapper.callNext(emitter, message);
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
PromiseWrapper.setTimeout(() => {
|
PromiseWrapper.setTimeout(() => {
|
||||||
expect(pipe.transform(emitter)).toEqual(message);
|
expect(pipe.transform(emitter)).toEqual(new WrappedValue(message));
|
||||||
async.done();
|
async.done();
|
||||||
}, 0)
|
}, 0)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should return NO_CHANGE when nothing has changed since the last call",
|
it("should return same value when nothing has changed since the last call",
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
pipe.transform(emitter);
|
pipe.transform(emitter);
|
||||||
ObservableWrapper.callNext(emitter, message);
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
PromiseWrapper.setTimeout(() => {
|
PromiseWrapper.setTimeout(() => {
|
||||||
pipe.transform(emitter);
|
pipe.transform(emitter);
|
||||||
expect(pipe.transform(emitter)).toBe(NO_CHANGE);
|
expect(pipe.transform(emitter)).toBe(message);
|
||||||
async.done();
|
async.done();
|
||||||
}, 0)
|
}, 0)
|
||||||
}));
|
}));
|
||||||
|
@ -66,11 +66,11 @@ export function main() {
|
||||||
var newEmitter = new EventEmitter();
|
var newEmitter = new EventEmitter();
|
||||||
expect(pipe.transform(newEmitter)).toBe(null);
|
expect(pipe.transform(newEmitter)).toBe(null);
|
||||||
|
|
||||||
// this should not affect the pipe, so it should return NO_CHANGE
|
// this should not affect the pipe
|
||||||
ObservableWrapper.callNext(emitter, message);
|
ObservableWrapper.callNext(emitter, message);
|
||||||
|
|
||||||
PromiseWrapper.setTimeout(() => {
|
PromiseWrapper.setTimeout(() => {
|
||||||
expect(pipe.transform(newEmitter)).toBe(NO_CHANGE);
|
expect(pipe.transform(newEmitter)).toBe(null);
|
||||||
async.done();
|
async.done();
|
||||||
}, 0)
|
}, 0)
|
||||||
}));
|
}));
|
||||||
|
|
Loading…
Reference in New Issue