From 0dfd287ec33a72e040480caf54fec008b4b04a0f Mon Sep 17 00:00:00 2001 From: vsavkin Date: Fri, 20 Feb 2015 15:50:12 -0800 Subject: [PATCH] fix(change_detection): handle locals when invoking a method Closes #660 --- .../change_detection_jit_generator.es6 | 17 ++++++++++++++++- .../change_detection/dynamic_change_detector.js | 12 ++++++++++-- .../change_detection/change_detection_spec.js | 8 ++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.es6 b/modules/angular2/src/change_detection/change_detection_jit_generator.es6 index b612d5efa2..9ba4a302be 100644 --- a/modules/angular2/src/change_detection/change_detection_jit_generator.es6 +++ b/modules/angular2/src/change_detection/change_detection_jit_generator.es6 @@ -203,6 +203,17 @@ if (${TEMP_LOCAL} instanceof ContextWithVariableBindings) { `; } +function invokeMethodTemplate(name:string, args:string, context:string, newValue:string) { + return ` +${TEMP_LOCAL} = ${UTIL}.findContext("${name}", ${context}); +if (${TEMP_LOCAL} instanceof ContextWithVariableBindings) { + ${newValue} = ${TEMP_LOCAL}.get('${name}').apply(null, [${args}]); +} else { + ${newValue} = ${context}.${name}(${args}); +} +`; +} + function localDefinitionsTemplate(names:List):string { return names.map((n) => `var ${n};`).join("\n"); } @@ -366,7 +377,11 @@ export class ChangeDetectorJITGenerator { } case RECORD_TYPE_INVOKE_METHOD: - return assignmentTemplate(newValue, `${context}.${r.name}(${args})`); + if (r.contextIndex == 0) { // only the first property read can be a local + return invokeMethodTemplate(r.name, args, context, newValue); + } else { + return assignmentTemplate(newValue, `${context}.${r.name}(${args})`); + } case RECORD_TYPE_INVOKE_CLOSURE: return assignmentTemplate(newValue, `${context}(${args})`); diff --git a/modules/angular2/src/change_detection/dynamic_change_detector.js b/modules/angular2/src/change_detection/dynamic_change_detector.js index 8dee6b5e63..051fb027fb 100644 --- a/modules/angular2/src/change_detection/dynamic_change_detector.js +++ b/modules/angular2/src/change_detection/dynamic_change_detector.js @@ -132,8 +132,16 @@ export class DynamicChangeDetector extends AbstractChangeDetector { break; case RECORD_TYPE_INVOKE_METHOD: - var methodInvoker:Function = proto.funcOrValue; - return methodInvoker(this._readContext(proto), this._readArgs(proto)); + var context = this._readContext(proto); + var args = this._readArgs(proto); + var c = ChangeDetectionUtil.findContext(proto.name, context); + if (c instanceof ContextWithVariableBindings) { + return FunctionWrapper.apply(c.get(proto.name), args); + } else { + var methodInvoker:Function = proto.funcOrValue; + return methodInvoker(c, args); + } + break; case RECORD_TYPE_KEYED_ACCESS: var arg = this._readArgs(proto)[0]; diff --git a/modules/angular2/test/change_detection/change_detection_spec.js b/modules/angular2/test/change_detection/change_detection_spec.js index c6f1d76f03..f2bc3f0edd 100644 --- a/modules/angular2/test/change_detection/change_detection_spec.js +++ b/modules/angular2/test/change_detection/change_detection_spec.js @@ -318,6 +318,14 @@ export function main() { .toEqual(['key=value']); }); + it('should invoke a function from ContextWithVariableBindings', () => { + var locals = new ContextWithVariableBindings(null, + MapWrapper.createFromPairs([["key", () => "value"]])); + + expect(executeWatch('key', 'key()', locals)) + .toEqual(['key=value']); + }); + it('should handle nested ContextWithVariableBindings', () => { var nested = new ContextWithVariableBindings(null, MapWrapper.createFromPairs([["key", "value"]]));