Merge pull request #2064 from NativeScript/nnikolov/BindingChangingContextFix

Additional fix for changing binding context issue.
This commit is contained in:
Nedyalko Nikolov
2016-05-03 16:18:54 +03:00
2 changed files with 61 additions and 3 deletions

View File

@ -492,6 +492,7 @@ export var test_bindingToNestedPropertyWithValueSyntax = function () {
}, bindingSource);
TKUnit.assertEqual(testElement.get("targetPropertyName"), "testValue");
TKUnit.assertTrue(bindingSource['$value'] === undefined, "We should not add $value to bindingSource.");
}
export var test_TwoElementsBindingToSameBindingContext = function () {
@ -546,6 +547,58 @@ export var test_BindingToSource_FailsAfterBindingContextChange = function () {
helper.buildUIAndRunTest(createLabel(), testFunc);
}
export var test_BindingToParentView_ShouldNotLeaveGarbageInViewModel = function () {
var createStack = function () {
var stack = new stackLayoutModule.StackLayout();
var label = new labelModule.Label();
stack.addChild(label);
return stack;
}
var stackViewModel = new observable.Observable();
var expectedValue = "testValue";
stackViewModel.set("testProperty", expectedValue);
var testFunc = function (views: Array<viewModule.View>) {
let testStack = <stackLayoutModule.StackLayout>(views[0]);
testStack.bindingContext = stackViewModel;
let testLabel = <labelModule.Label>(testStack.getChildAt(0));
testLabel.bind({ sourceProperty: "$parent.testProperty", targetProperty: "text", expression: "$parent.testProperty"});
TKUnit.assertEqual(testLabel.text, expectedValue);
TKUnit.assertTrue(stackViewModel['$parent'] === undefined, "stackViewModel['$parent'] should be removed from parent binding context.");
TKUnit.assertTrue(testLabel.bindingContext['$parent'] === undefined, "testLabel.bindingContext['$parent'] should be removed from parent binding context.");
}
helper.buildUIAndRunTest(createStack(), testFunc);
}
export var test_BindingToParentsView_ShouldNotLeaveGarbageInViewModel = function () {
var createStack = function () {
var stack = new stackLayoutModule.StackLayout();
var label = new labelModule.Label();
stack.addChild(label);
return stack;
}
var stackViewModel = new observable.Observable();
var expectedValue = "testValue";
stackViewModel.set("testProperty", expectedValue);
var testFunc = function (views: Array<viewModule.View>) {
let testStack = <stackLayoutModule.StackLayout>(views[0]);
testStack.bindingContext = stackViewModel;
let testLabel = <labelModule.Label>(testStack.getChildAt(0));
testLabel.bind({ sourceProperty: "$parents['StackLayout'].testProperty", targetProperty: "text", expression: "$parents['StackLayout'].testProperty"});
TKUnit.assertEqual(testLabel.text, expectedValue);
TKUnit.assertTrue(stackViewModel['$parent'] === undefined, "stackViewModel['$parent'] should be removed from parent binding context.");
TKUnit.assertTrue(testLabel.bindingContext['$parents'] === undefined, "testLabel.bindingContext['$parents'] should be removed from parent binding context.");
}
helper.buildUIAndRunTest(createStack(), testFunc);
}
export function test_BindingToDictionaryAtAppLevel() {
var createLabel = function () {
var label = new labelModule.Label();
@ -998,6 +1051,7 @@ export function test_$ValueSupportWithinExpression() {
model.set("anyColor", "red");
TKUnit.assertEqual(bindableObj.get("test"), "red", "When anyColor is red test property should be red too.");
TKUnit.assertTrue(model['$value'] === undefined, "We should not add $value to binding context.");
}
class DummyNestedClass extends observable.Observable {

View File

@ -330,7 +330,7 @@ export class Binding {
}
let updateExpression = this.prepareExpressionForUpdate();
this.prepareContextForExpression(changedModel, updateExpression);
this.prepareContextForExpression(changedModel, updateExpression, undefined);
let expressionValue = this._getExpressionValue(updateExpression, true, changedModel);
if (expressionValue instanceof Error) {
@ -357,7 +357,7 @@ export class Binding {
}
}
this.prepareContextForExpression(context, expression);
this.prepareContextForExpression(context, expression, addedProps);
model[contextKey] = context;
let result = exp.getValue(model, isBackConvert, changedModel ? changedModel : model);
// clear added props
@ -443,17 +443,20 @@ export class Binding {
}
}
private prepareContextForExpression(model: Object, expression: string) {
private prepareContextForExpression(model: Object, expression: string, newProps: Array<string>) {
let parentViewAndIndex: { view: viewModule.View, index: number };
let parentView;
let addedProps = newProps || [];
if (expression.indexOf(bc.bindingValueKey) > -1) {
model[bc.bindingValueKey] = model;
addedProps.push(bc.bindingValueKey);
}
if (expression.indexOf(bc.parentValueKey) > -1) {
parentView = this.getParentView(this.target.get(), bc.parentValueKey).view;
if (parentView) {
model[bc.parentValueKey] = parentView.bindingContext;
addedProps.push(bc.parentValueKey);
}
}
@ -464,6 +467,7 @@ export class Binding {
if (parentViewAndIndex.view) {
model[bc.parentsValueKey] = model[bc.parentsValueKey] || {};
model[bc.parentsValueKey][parentViewAndIndex.index] = parentViewAndIndex.view.bindingContext;
addedProps.push(bc.parentsValueKey);
}
}
}