mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
Merge pull request #1992 from NativeScript/nnikolov/BindingSameProperties
Fix for using same name properties in binding.
This commit is contained in:
@ -997,4 +997,129 @@ export function test_$ValueSupportWithinExpression() {
|
||||
model.set("anyColor", "red");
|
||||
|
||||
TKUnit.assertEqual(bindableObj.get("test"), "red", "When anyColor is red test property should be red too.");
|
||||
}
|
||||
|
||||
class DummyNestedClass extends observable.Observable {
|
||||
private _secondsobject: number;
|
||||
public get secondsobject(): number {
|
||||
return this._secondsobject;
|
||||
}
|
||||
public set secondsobject(value: number) {
|
||||
if (this._secondsobject !== value) {
|
||||
this._secondsobject = value;
|
||||
this.notifyPropertyChange('secondsobject', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DummyClassWithSamePropertyNames extends observable.Observable {
|
||||
private _seconds: number;
|
||||
private _secondsobject: DummyNestedClass;
|
||||
public get seconds(): number {
|
||||
return this._seconds;
|
||||
}
|
||||
public set seconds(value: number) {
|
||||
if (this._seconds !== value) {
|
||||
this._seconds = value;
|
||||
this.notifyPropertyChange('seconds', value);
|
||||
}
|
||||
}
|
||||
|
||||
public get secondsobject(): DummyNestedClass {
|
||||
return this._secondsobject;
|
||||
}
|
||||
public set secondsobject(value: DummyNestedClass) {
|
||||
if (this._secondsobject !== value) {
|
||||
this._secondsobject = value;
|
||||
this.notifyPropertyChange('secondsobject', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DummyModel extends observable.Observable {
|
||||
private _item: DummyClassWithSamePropertyNames;
|
||||
public get item(): DummyClassWithSamePropertyNames {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
public set item(value: DummyClassWithSamePropertyNames) {
|
||||
if (this._item !== value) {
|
||||
this._item = value;
|
||||
this.notifyPropertyChange("item", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function test_BindingToPropertiesWithSameNames() {
|
||||
var model = new DummyModel();
|
||||
model.item = new DummyClassWithSamePropertyNames();
|
||||
model.item.seconds = 1;
|
||||
var secondsobject = new DummyNestedClass();
|
||||
secondsobject.secondsobject = 1;
|
||||
model.item.secondsobject = secondsobject;
|
||||
|
||||
var target1 = new bindable.Bindable();
|
||||
target1.bind({
|
||||
sourceProperty: "item.seconds",
|
||||
targetProperty: "targetProperty",
|
||||
twoWay: true
|
||||
}, model);
|
||||
|
||||
var target2 = new bindable.Bindable();
|
||||
target2.bind({
|
||||
sourceProperty: "item.secondsobject.secondsobject",
|
||||
targetProperty: "targetProp",
|
||||
twoWay: true
|
||||
}, model);
|
||||
|
||||
model.item.set("seconds", model.item.seconds + 1);
|
||||
var newValue = (<any>model).item.secondsobject.secondsobject + 1;
|
||||
model.item.secondsobject.set("secondsobject", newValue);
|
||||
|
||||
TKUnit.assertEqual(target1.get("targetProperty"), model.item.get("seconds"));
|
||||
TKUnit.assertEqual(target2.get("targetProp"), newValue);
|
||||
|
||||
// calling this two times in order to ensure that adding and removing weak event listeners is working fine.
|
||||
newValue = model.item.secondsobject.secondsobject + 1;
|
||||
model.item.secondsobject.set("secondsobject", newValue);
|
||||
|
||||
TKUnit.assertEqual(target1.get("targetProperty"), model.item.get("seconds"));
|
||||
TKUnit.assertEqual(target2.get("targetProp"), newValue);
|
||||
}
|
||||
|
||||
export function test_BindingToPropertiesWithSameNamesSecondCase() {
|
||||
var model = new DummyModel();
|
||||
model.item = new DummyClassWithSamePropertyNames();
|
||||
model.item.seconds = 1;
|
||||
var secondsobject = new DummyNestedClass();
|
||||
secondsobject.secondsobject = 1;
|
||||
model.item.secondsobject = secondsobject;
|
||||
|
||||
var target1 = new bindable.Bindable();
|
||||
target1.bind({
|
||||
sourceProperty: "item.seconds",
|
||||
targetProperty: "targetProperty",
|
||||
twoWay: true
|
||||
}, model);
|
||||
|
||||
var target2 = new bindable.Bindable();
|
||||
target2.bind({
|
||||
sourceProperty: "item.secondsobject.secondsobject",
|
||||
targetProperty: "targetProp",
|
||||
twoWay: true
|
||||
}, model);
|
||||
|
||||
model.item.set("seconds", model.item.seconds + 1);
|
||||
var newValue = model.item.secondsobject.secondsobject + 1;
|
||||
model.item.set("secondsobject",{secondsobject: newValue});
|
||||
|
||||
TKUnit.assertEqual(target1.get("targetProperty"), model.item.get("seconds"));
|
||||
TKUnit.assertEqual(target2.get("targetProp"), newValue);
|
||||
|
||||
// calling this two times in order to ensure that adding and removing weak event listeners is working fine.
|
||||
newValue = model.item.secondsobject.secondsobject + 1;
|
||||
model.item.set("secondsobject",{secondsobject: newValue});
|
||||
|
||||
TKUnit.assertEqual(target1.get("targetProperty"), model.item.get("seconds"));
|
||||
TKUnit.assertEqual(target2.get("targetProp"), newValue);
|
||||
}
|
@ -280,13 +280,14 @@ export class Binding {
|
||||
return result;
|
||||
}
|
||||
|
||||
private addPropertyChangeListeners(source: WeakRef<Object>, sourceProperty: Array<string>) {
|
||||
private addPropertyChangeListeners(source: WeakRef<Object>, sourceProperty: Array<string>, parentProperies?: string) {
|
||||
var objectsAndProperties = this.resolveObjectsAndProperties(source.get(), sourceProperty)
|
||||
var objectsAndPropertiesLength = objectsAndProperties.length;
|
||||
if (objectsAndPropertiesLength > 0) {
|
||||
var i;
|
||||
var prop = parentProperies || "";
|
||||
for (i = 0; i < objectsAndPropertiesLength; i++) {
|
||||
var prop = objectsAndProperties[i].property;
|
||||
prop += "$" + objectsAndProperties[i].property;
|
||||
var currentObject = objectsAndProperties[i].instance;
|
||||
if (!this.propertyChangeListeners[prop] && currentObject instanceof observable.Observable) {
|
||||
weakEvents.addWeakEventListener(
|
||||
@ -406,6 +407,18 @@ export class Binding {
|
||||
}
|
||||
|
||||
public onSourcePropertyChanged(data: observable.PropertyChangeData) {
|
||||
var sourceProps = Binding.getProperties(this.options.sourceProperty);
|
||||
var sourcePropsLength = sourceProps.length;
|
||||
var changedPropertyIndex = sourceProps.indexOf(data.propertyName);
|
||||
var parentProps = "";
|
||||
if (changedPropertyIndex > -1) {
|
||||
parentProps = "$" + sourceProps.slice(0, changedPropertyIndex + 1).join("$");
|
||||
while (this.propertyChangeListeners[parentProps] !== data.object) {
|
||||
changedPropertyIndex += sourceProps.slice(changedPropertyIndex + 1).indexOf(data.propertyName) + 1;
|
||||
parentProps = "$" + sourceProps.slice(0, changedPropertyIndex + 1).join("$");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.expression) {
|
||||
var expressionValue = this._getExpressionValue(this.options.expression, false, undefined);
|
||||
if (expressionValue instanceof Error) {
|
||||
@ -415,14 +428,12 @@ export class Binding {
|
||||
this.updateTarget(expressionValue);
|
||||
}
|
||||
} else {
|
||||
var propIndex = this.getSourceProperties().indexOf(data.propertyName);
|
||||
if (propIndex > -1) {
|
||||
var props = this.getSourceProperties().slice(propIndex + 1);
|
||||
if (changedPropertyIndex > -1) {
|
||||
var props = sourceProps.slice(changedPropertyIndex + 1);
|
||||
var propsLength = props.length;
|
||||
if (propsLength > 0) {
|
||||
var value = data.value;
|
||||
var i;
|
||||
for (i = 0; i < propsLength; i++) {
|
||||
for (let i = 0; i < propsLength; i++) {
|
||||
value = value[props[i]];
|
||||
}
|
||||
this.updateTarget(value);
|
||||
@ -433,27 +444,29 @@ export class Binding {
|
||||
}
|
||||
}
|
||||
|
||||
var sourceProps = Binding.getProperties(this.options.sourceProperty);
|
||||
var sourcePropsLength = sourceProps.length;
|
||||
var changedPropertyIndex = sourceProps.indexOf(data.propertyName);
|
||||
if (changedPropertyIndex > -1) {
|
||||
var probablyChangedObject = this.propertyChangeListeners[sourceProps[changedPropertyIndex + 1]];
|
||||
var probablyChangedObject = this.propertyChangeListeners[parentProps];
|
||||
if (probablyChangedObject &&
|
||||
probablyChangedObject !== data.object[sourceProps[changedPropertyIndex]]) {
|
||||
// remove all weakevent listeners after change, because changed object replaces object that is hooked for
|
||||
// propertyChange event
|
||||
for (i = sourcePropsLength - 1; i > changedPropertyIndex; i--) {
|
||||
weakEvents.removeWeakEventListener(
|
||||
this.propertyChangeListeners[sourceProps[i]],
|
||||
observable.Observable.propertyChangeEvent,
|
||||
this.onSourcePropertyChanged,
|
||||
this);
|
||||
delete this.propertyChangeListeners[sourceProps[i]];
|
||||
for (let i = sourcePropsLength - 1; i > changedPropertyIndex; i--) {
|
||||
var prop = "$" + sourceProps.slice(0, i + 1).join("$");
|
||||
if (this.propertyChangeListeners[prop]) {
|
||||
weakEvents.removeWeakEventListener(
|
||||
this.propertyChangeListeners[prop],
|
||||
observable.Observable.propertyChangeEvent,
|
||||
this.onSourcePropertyChanged,
|
||||
this);
|
||||
delete this.propertyChangeListeners[prop];
|
||||
}
|
||||
}
|
||||
//var newProps = this.options.sourceProperty.substr(this.options.sourceProperty.indexOf(data.propertyName) + data.propertyName.length + 1);
|
||||
var newProps = sourceProps.slice(changedPropertyIndex + 1);
|
||||
// add new weakevent listeners
|
||||
this.addPropertyChangeListeners(new WeakRef(data.object[sourceProps[changedPropertyIndex]]), newProps);
|
||||
var newObject = data.object[sourceProps[changedPropertyIndex]]
|
||||
if (typeof newObject === 'object') {
|
||||
this.addPropertyChangeListeners(new WeakRef(data.object[sourceProps[changedPropertyIndex]]), newProps, parentProps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user