fix(change_detection): updated dynamic change detector not to mutate when throwing

Closes #1762
This commit is contained in:
vsavkin 2015-05-08 08:32:02 -07:00 committed by Misko Hevery
parent c68fa27444
commit d717529e9a
2 changed files with 46 additions and 18 deletions

View File

@ -90,9 +90,8 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
var bindingRecord = proto.bindingRecord; var bindingRecord = proto.bindingRecord;
var directiveRecord = bindingRecord.directiveRecord; var directiveRecord = bindingRecord.directiveRecord;
var change = this._check(proto); var change = this._check(proto, throwOnChange);
if (isPresent(change)) { if (isPresent(change)) {
if (throwOnChange) ChangeDetectionUtil.throwOnChange(proto, change);
this._updateDirectiveOrElement(change, bindingRecord); this._updateDirectiveOrElement(change, bindingRecord);
isChanged = true; isChanged = true;
changes = this._addChange(bindingRecord, change, changes); changes = this._addChange(bindingRecord, change, changes);
@ -144,19 +143,19 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
_getDetectorFor(directiveIndex) { return this.directives.getDetectorFor(directiveIndex); } _getDetectorFor(directiveIndex) { return this.directives.getDetectorFor(directiveIndex); }
_check(proto: ProtoRecord): SimpleChange { _check(proto: ProtoRecord, throwOnChange: boolean): SimpleChange {
try { try {
if (proto.mode === RECORD_TYPE_PIPE || proto.mode === RECORD_TYPE_BINDING_PIPE) { if (proto.mode === RECORD_TYPE_PIPE || proto.mode === RECORD_TYPE_BINDING_PIPE) {
return this._pipeCheck(proto); return this._pipeCheck(proto, throwOnChange);
} else { } else {
return this._referenceCheck(proto); return this._referenceCheck(proto, throwOnChange);
} }
} catch (e) { } catch (e) {
throw new ChangeDetectionError(proto, e); throw new ChangeDetectionError(proto, e);
} }
} }
_referenceCheck(proto: ProtoRecord) { _referenceCheck(proto: ProtoRecord, throwOnChange: boolean) {
if (this._pureFuncAndArgsDidNotChange(proto)) { if (this._pureFuncAndArgsDidNotChange(proto)) {
this._setChanged(proto, false); this._setChanged(proto, false);
return null; return null;
@ -166,12 +165,18 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
var currValue = this._calculateCurrValue(proto); var currValue = this._calculateCurrValue(proto);
if (!isSame(prevValue, currValue)) { if (!isSame(prevValue, currValue)) {
this._writeSelf(proto, currValue);
this._setChanged(proto, true);
if (proto.lastInBinding) { if (proto.lastInBinding) {
return ChangeDetectionUtil.simpleChange(prevValue, currValue); var change = ChangeDetectionUtil.simpleChange(prevValue, currValue);
if (throwOnChange) ChangeDetectionUtil.throwOnChange(proto, change);
this._writeSelf(proto, currValue);
this._setChanged(proto, true);
return change;
} else { } else {
this._writeSelf(proto, currValue);
this._setChanged(proto, true);
return null; return null;
} }
} else { } else {
@ -216,22 +221,28 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
} }
} }
_pipeCheck(proto: ProtoRecord) { _pipeCheck(proto: ProtoRecord, throwOnChange: boolean) {
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 prevValue = this._readSelf(proto);
var newValue = pipe.transform(context); var currValue = pipe.transform(context);
if (!isSame(prevValue, newValue)) { if (!isSame(prevValue, currValue)) {
newValue = ChangeDetectionUtil.unwrapValue(newValue); currValue = ChangeDetectionUtil.unwrapValue(currValue);
this._writeSelf(proto, newValue);
this._setChanged(proto, true);
if (proto.lastInBinding) { if (proto.lastInBinding) {
return ChangeDetectionUtil.simpleChange(prevValue, newValue); var change = ChangeDetectionUtil.simpleChange(prevValue, currValue);
if (throwOnChange) ChangeDetectionUtil.throwOnChange(proto, change);
this._writeSelf(proto, currValue);
this._setChanged(proto, true);
return change;
} else { } else {
this._writeSelf(proto, currValue);
this._setChanged(proto, true);
return null; return null;
} }
} else { } else {

View File

@ -420,6 +420,23 @@ export function main() {
cd.checkNoChanges(); cd.checkNoChanges();
}).toThrowError(new RegExp("Expression 'a in location' has changed after it was checked")); }).toThrowError(new RegExp("Expression 'a in location' has changed after it was checked"));
}); });
it("should not break the next run", () => {
var pcd = createProtoChangeDetector([
BindingRecord.createForElement(ast("a"), 0, "a")
]);
var dispatcher = new TestDispatcher();
var cd = pcd.instantiate(dispatcher);
cd.hydrate(new TestData('value'), null, null);
expect(() => cd.checkNoChanges()).toThrowError(new RegExp(
"Expression 'a in location' has changed after it was checked."));
cd.detectChanges();
expect(dispatcher.loggedValues).toEqual(['value']);
});
}); });
//TODO vsavkin: implement it //TODO vsavkin: implement it