fix(change_detection): pass the correct previous value when using pipes

Closes #588
This commit is contained in:
vsavkin 2015-02-20 16:23:16 -08:00
parent 1d4ffd986d
commit 7f31036427
2 changed files with 86 additions and 43 deletions

View File

@ -157,11 +157,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
var newValue = pipe.transform(context); var newValue = pipe.transform(context);
if (! ChangeDetectionUtil.noChangeMarker(newValue)) { if (! ChangeDetectionUtil.noChangeMarker(newValue)) {
var prevValue = this._readSelf(proto);
this._writeSelf(proto, newValue); this._writeSelf(proto, newValue);
this._setChanged(proto, true); this._setChanged(proto, true);
if (proto.lastInBinding) { if (proto.lastInBinding) {
var prevValue = this._readSelf(proto);
return ChangeDetectionUtil.simpleChange(prevValue, newValue); return ChangeDetectionUtil.simpleChange(prevValue, newValue);
} else { } else {
return null; return null;

View File

@ -7,8 +7,9 @@ import {Parser} from 'angular2/src/change_detection/parser/parser';
import {Lexer} from 'angular2/src/change_detection/parser/lexer'; import {Lexer} from 'angular2/src/change_detection/parser/lexer';
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings, import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings,
PipeRegistry, NO_CHANGE, PipeRegistry, NO_CHANGE, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from 'angular2/change_detection';
CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from 'angular2/change_detection';
import {ChangeDetectionUtil} from 'angular2/src/change_detection/change_detection_util';
import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/change_detection/proto_change_detector'; import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/change_detection/proto_change_detector';
@ -190,48 +191,86 @@ export function main() {
expect(dispatcher.log).toEqual(["memo=BvalueA"]); expect(dispatcher.log).toEqual(["memo=BvalueA"]);
}); });
describe("group changes", () => { describe("change notification", () => {
it("should notify the dispatcher when a group of records changes", () => { describe("simple checks", () => {
var pcd = createProtoChangeDetector(); it("should pass a change record to the dispatcher", () => {
pcd.addAst(ast("1 + 2"), "memo", "1"); var person = new Person('bob');
pcd.addAst(ast("10 + 20"), "memo", "1"); var c = createChangeDetector('name', 'name', person);
pcd.addAst(ast("100 + 200"), "memo2", "2"); var cd = c["changeDetector"];
var dispatcher = c["dispatcher"];
var dispatcher = new TestDispatcher(); cd.detectChanges();
var cd = pcd.instantiate(dispatcher);
cd.detectChanges(); var changeRecord = dispatcher.changeRecords[0][0];
expect(dispatcher.loggedValues).toEqual([[3, 30], [300]]); expect(changeRecord.bindingMemento).toEqual('name');
expect(changeRecord.change.currentValue).toEqual('bob');
expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
});
}); });
it("should notify the dispatcher before switching to the next group", () => { describe("pipes", () => {
var pcd = createProtoChangeDetector(); it("should pass a change record to the dispatcher", () => {
pcd.addAst(ast("a()"), "a", "1"); var registry = new FakePipeRegistry('pipe', () => new CountingPipe());
pcd.addAst(ast("b()"), "b", "2");
pcd.addAst(ast("c()"), "c", "2");
var dispatcher = new TestDispatcher(); var person = new Person('bob');
var cd = pcd.instantiate(dispatcher); var c = createChangeDetector('name', 'name | pipe', person, registry);
var cd = c["changeDetector"];
var dispatcher = c["dispatcher"];
var tr = new TestRecord(); cd.detectChanges();
tr.a = () => {
dispatcher.logValue('InvokeA');
return 'a'
};
tr.b = () => {
dispatcher.logValue('InvokeB');
return 'b'
};
tr.c = () => {
dispatcher.logValue('InvokeC');
return 'c'
};
cd.setContext(tr);
cd.detectChanges(); var changeRecord = dispatcher.changeRecords[0][0];
expect(dispatcher.loggedValues).toEqual(['InvokeA', ['a'], 'InvokeB', 'InvokeC', ['b', 'c']]); expect(changeRecord.bindingMemento).toEqual('name');
expect(changeRecord.change.currentValue).toEqual('bob state:0');
expect(changeRecord.change.previousValue).toEqual(ChangeDetectionUtil.unitialized());
});
});
describe("group changes", () => {
it("should notify the dispatcher when a group of records changes", () => {
var pcd = createProtoChangeDetector();
pcd.addAst(ast("1 + 2"), "memo", "1");
pcd.addAst(ast("10 + 20"), "memo", "1");
pcd.addAst(ast("100 + 200"), "memo2", "2");
var dispatcher = new TestDispatcher();
var cd = pcd.instantiate(dispatcher);
cd.detectChanges();
expect(dispatcher.loggedValues).toEqual([[3, 30], [300]]);
});
it("should notify the dispatcher before switching to the next group", () => {
var pcd = createProtoChangeDetector();
pcd.addAst(ast("a()"), "a", "1");
pcd.addAst(ast("b()"), "b", "2");
pcd.addAst(ast("c()"), "c", "2");
var dispatcher = new TestDispatcher();
var cd = pcd.instantiate(dispatcher);
var tr = new TestRecord();
tr.a = () => {
dispatcher.logValue('InvokeA');
return 'a'
};
tr.b = () => {
dispatcher.logValue('InvokeB');
return 'b'
};
tr.c = () => {
dispatcher.logValue('InvokeC');
return 'c'
};
cd.setContext(tr);
cd.detectChanges();
expect(dispatcher.loggedValues).toEqual(['InvokeA', ['a'], 'InvokeB', 'InvokeC', ['b', 'c']]);
});
}); });
}); });
@ -576,6 +615,7 @@ class TestData {
class TestDispatcher extends ChangeDispatcher { class TestDispatcher extends ChangeDispatcher {
log:List; log:List;
loggedValues:List; loggedValues:List;
changeRecords:List;
onChange:Function; onChange:Function;
constructor() { constructor() {
@ -589,21 +629,24 @@ class TestDispatcher extends ChangeDispatcher {
clear() { clear() {
this.log = ListWrapper.create(); this.log = ListWrapper.create();
this.loggedValues = ListWrapper.create(); this.loggedValues = ListWrapper.create();
this.changeRecords = ListWrapper.create();
} }
logValue(value) { logValue(value) {
ListWrapper.push(this.loggedValues, value); ListWrapper.push(this.loggedValues, value);
} }
onRecordChange(group, updates:List) { onRecordChange(group, changeRecords:List) {
var value = updates[0].change.currentValue; var value = changeRecords[0].change.currentValue;
var memento = updates[0].bindingMemento; var memento = changeRecords[0].bindingMemento;
ListWrapper.push(this.log, memento + '=' + this._asString(value)); ListWrapper.push(this.log, memento + '=' + this._asString(value));
var values = ListWrapper.map(updates, (r) => r.change.currentValue); var values = ListWrapper.map(changeRecords, (r) => r.change.currentValue);
ListWrapper.push(this.loggedValues, values); ListWrapper.push(this.loggedValues, values);
this.onChange(group, updates); ListWrapper.push(this.changeRecords, changeRecords);
this.onChange(group, changeRecords);
} }