Observable array now fires property change for length property.

This commit is contained in:
Nedyalko Nikolov
2015-03-05 14:54:46 +02:00
parent b04d1fcd3a
commit 4152e66195
7 changed files with 125 additions and 45 deletions

View File

@ -1,24 +1,32 @@
import pageModule = require("ui/page");
//import stackLayoutModule = require("ui/layouts/stack-layout");
//import textFieldModule = require("ui/text-field");
import buttonModule = require("ui/button");
import observableModule = require("data/observable");
import observableArray = require("data/observable-array");
import bindableModule = require("ui/core/bindable");
//import enums = require("ui/enums");
import trace = require("trace");
trace.setCategories(trace.categories.Test);
trace.setCategories(trace.categories.Test + "," + trace.categories.Binding);
trace.enable();
export function pageLoaded(args: observableModule.EventData) {
var page: pageModule.Page = <pageModule.Page>args.object;
var model = new observableModule.Observable();
var tasks = new observableArray.ObservableArray();
//tasks.push("tralala");
//var model = page.bindingContext;
model.set("tasks", tasks);
model.set("paramProperty", "%%%");
var toUpperConverter: bindableModule.ValueConverter = {
toModel: function (value, param1) {
return param1 + value.toLowerCase();
},
toView: function (value, param1) {
return value.toUpperCase();
if (value === 0) {
return "no items";
}
return value + " items";
}
};
model.set("toUpper", toUpperConverter);
@ -27,6 +35,12 @@ export function pageLoaded(args: observableModule.EventData) {
page.bindingContext = model;
}
export function onTap(args: observableModule.EventData) {
var button: buttonModule.Button = <buttonModule.Button>args.object;
trace.write("tasks: " + button.bindingContext.get("tasks"), trace.categories.Test, trace.messageType.info);
button.bindingContext.get("tasks").push("alabala");
}
//export function createPage() {
// var stackLayout = new stackLayoutModule.StackLayout();
// var firstTextField = new textFieldModule.TextField();

View File

@ -1,7 +1,6 @@
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
<StackLayout padding="7">
<TextField text="{{ testProperty, testProperty | toUpper(paramProperty) }}" />
<!--<TextField text="{{ testProperty | toUpper }}" />-->
<TextField text="{{ testProperty }}" />
<TextField text="{{ tasks.length, tasks.length === 0 ? 'zero items' : tasks.length + ' items', false }}" />
<Button text="Click" tap="onTap" />
</StackLayout>
</Page>

View File

@ -1,4 +1,5 @@
import TKUnit = require("./TKUnit");
import bindableModule = require("ui/core/bindable");
require("globals");
// <snippet module="data/observable-array" title="observable-array">
@ -80,34 +81,6 @@ export var test_ObservableArray_concatShouldReturnNewArrayWithNewItemsAtTheEnd =
TKUnit.assert(result.length === 6 && result[4] === 5, "ObservableArray concat() should add items at the end!");
};
export var test_ObservableArray_concatShouldReturnNewArrayWithNewItemsAtTheEndAndRaiseChangeEventWithCorrectArgs = function () {
var result: observableArrayModule.ChangedData<number>;
// <snippet module="data/observable-array" title="observable-array">
// ### Use concat() method to append array to ObservableArray and handle "change" event.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
array.on(observableArrayModule.knownEvents.change, (args: observableArrayModule.ChangedData<number>) => {
//// Argument (args) is ChangedData<T>.
//// args.eventName is "change".
//// args.action is "add".
//// args.index is equal to the array length.
//// args.removed.length is 0.
//// args.addedCount is equal to number of added items.
// <hide>
result = args;
// </hide>
});
array.concat([4, 5, 6]);
// ```
// </snippet>
TKUnit.assert(result.eventName === "change" && result.action === observableArrayModule.ChangeType.Add &&
result.removed.length === 0 && result.index === 3 && result.addedCount === 3, "ObservableArray concat() should raise 'change' event with correct args!");
};
export var test_ObservableArray_joinShouldReturnStringWithAllItemsSeparatedWithComma = function () {
// <snippet module="data/observable-array" title="observable-array">
// ### Use join() method to convert ObservableArray to comma separated string.
@ -135,10 +108,16 @@ export var test_ObservableArray_popShouldRemoveTheLastElement = function () {
// ### Use pop() method to remove the last element.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.pop();
// ```
// </snippet>
TKUnit.assert(result === 3 && array.length === 2, "ObservableArray pop() should remove last element!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_popShouldRemoveTheLastElementAndRaiseChangeEventWithCorrectArgs = function () {
@ -176,10 +155,16 @@ export var test_ObservableArray_pushShouldAppendNewElement = function () {
// ### Use push() method to add single element to the array.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.push(4);
// ```
// </snippet>
TKUnit.assert(result === 4 && array.getItem(3) === 4, "ObservableArray push() should append new element!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_pushShouldAppendNewElementAndRaiseChangeEventWithCorrectArgs = function () {
@ -215,10 +200,16 @@ export var test_ObservableArray_pushShouldAppendNewElements = function () {
// ### Use push() method to add multiple elements to the array.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.push(4, 5, 6);
// ```
// </snippet>
TKUnit.assert(result === 6 && array.getItem(5) === 6, "ObservableArray push() should append new elements!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_pushShouldAppendNewElementsAndRaiseChangeEventWithCorrectArgs = function () {
@ -254,10 +245,16 @@ export var test_ObservableArray_pushShouldAppendNewElementsFromSourceArray = fun
// ### Use push() method to add multiple elements from source array to the ObservableArray.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.push([4, 5, 6]);
// ```
// </snippet>
TKUnit.assert(result === 6 && array.getItem(5) === 6, "ObservableArray push() should append new elements from source array!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_pushShouldAppendNewElementsFromSourceArrayAndRaiseChangeEventWithCorrectArgs = function () {
@ -304,10 +301,16 @@ export var test_ObservableArray_shiftShouldRemoveTheFirstElement = function () {
// ### Use shift() method to remove the first element of the array.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.shift();
// ```
// </snippet>
TKUnit.assert(result === 1 && array.length === 2, "ObservableArray shift() should remove first element!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_shiftShouldRemoveTheFirstElementAndRaiseChangeEventWithCorrectArgs = function () {
@ -388,11 +391,17 @@ export var test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStart
// ### Use splice(start, deleteCount) method to delete elements in the array.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray(["one", "two", "three"]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.splice(1, 2);
// ```
// </snippet>
TKUnit.assert(result.length === 2 && result[0] === "two" && array.length === 1 && array.getItem(0) === "one",
"ObservableArray splice() should remove specified number of elements starting from specified index!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () {
@ -470,11 +479,17 @@ export var test_ObservableArray_unshiftShouldInsertNewElementsFromTheStart = fun
// ### Use unshift(item1, item2... itemN) method to insert elements from the start of the array.
// ``` JavaScript
var array = new observableArrayModule.ObservableArray([1, 2, 3]);
// <hide>
var bindable = new bindableModule.Bindable();
bindable.set("testProperty", 0);
bindable.bind({ sourceProperty: "length", targetProperty: "testProperty" }, array);
// </hide>
var result = array.unshift(4, 5);
// ```
// </snippet>
TKUnit.assert(array.getItem(0) === 4 && result === 5 && array.length === 5, "ObservableArray unshift() should insert new elements from the start!");
TKUnit.assert(bindable.get("testProperty") === array.length, "Expected: " + array.length + ", Actual: " + bindable.get("testProperty"));
};
export var test_ObservableArray_unshiftShouldInsertNewElementsFromTheStartAndRaiseChangeEventWithCorrectArgs = function () {

View File

@ -380,3 +380,43 @@ export var test_Bindable_BindingContext_String_DoesNotThrow = function () {
TKUnit.assert(obj.get("test") === 6, "Expected: 6; Actual: " + obj.get("test"));
}
export var test_getBindableOptionsFromStringFullFormat = function () {
var bindingExpression = "bindProperty, bindProperty * 2, false";
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual:" + bindOptions.expression);
TKUnit.assert(bindOptions.twoWay === false, "Expected: false, Actual: " + bindOptions.twoWay);
}
export var test_getBindableOptionsFromStringShortFormatExpression = function () {
var bindingExpression = "bindProperty * 2";
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual: " + bindOptions.expression);
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
}
export var test_getBindableOptionsFromStringShortFormatProperty = function () {
var bindingExpression = "bindProperty";
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
TKUnit.assert(bindOptions.expression === null, "Expected: null, Actual: " + bindOptions.expression);
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
}
export var test_getBindableOptionsFromStringTwoParamsFormat = function () {
var bindingExpression = "bindProperty, bindProperty * 2";
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual:" + bindOptions.expression);
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
}

View File

@ -88,13 +88,7 @@ export class ObservableArray<T> extends observable.Observable implements observa
*/
concat(): T[] {
this._addArgs.index = this._array.length;
var result = this._array.concat.apply(this._array, arguments);
this._addArgs.addedCount = result.length - this._array.length;
this.notify(this._addArgs);
return result;
}
@ -117,6 +111,7 @@ export class ObservableArray<T> extends observable.Observable implements observa
this._deleteArgs.removed = [result];
this.notify(this._deleteArgs);
this._notifyLengthChange();
return result;
}
@ -143,10 +138,16 @@ export class ObservableArray<T> extends observable.Observable implements observa
this._addArgs.addedCount = this._array.length - this._addArgs.index;
this.notify(this._addArgs);
this._notifyLengthChange();
return this._array.length;
}
_notifyLengthChange() {
var lengthChangedData = this._createPropertyChangeData("length", this._array.length);
this.notify(lengthChangedData);
}
/**
* Reverses the elements in an Array.
*/
@ -164,6 +165,7 @@ export class ObservableArray<T> extends observable.Observable implements observa
this._deleteArgs.removed = [result];
this.notify(this._deleteArgs);
this._notifyLengthChange();
return result;
}
@ -202,6 +204,9 @@ export class ObservableArray<T> extends observable.Observable implements observa
removed: result,
addedCount: this._array.length > length ? this._array.length - length : 0
});
if (this._array.length !== length) {
this._notifyLengthChange();
}
return result;
}
@ -218,6 +223,7 @@ export class ObservableArray<T> extends observable.Observable implements observa
this._addArgs.addedCount = result - length;
this.notify(this._addArgs);
this._notifyLengthChange();
return result;
}

View File

@ -114,7 +114,7 @@ export function getComponentModule(elementName: string, namespace: string, attri
gridLayoutModule.GridLayout.setColumnSpan(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === ROW_SPAN) {
gridLayoutModule.GridLayout.setRowSpan(instance, !isNaN(+attrValue) && +attrValue);
} if (attr === LEFT) {
} else if (attr === LEFT) {
absoluteLayoutDef.AbsoluteLayout.setLeft(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === TOP) {
absoluteLayoutDef.AbsoluteLayout.setTop(instance, !isNaN(+attrValue) && +attrValue);

View File

@ -120,7 +120,7 @@ export class Bindable extends dependencyObservable.DependencyObservable implemen
private static extractPropertyNameFromExpression(expression: string): string {
var firstExpressionSymbolIndex = expression.search(expressionSymbolsRegex);
if (firstExpressionSymbolIndex > -1) {
return expression.substr(0, firstExpressionSymbolIndex);
return expression.substr(0, firstExpressionSymbolIndex).trim();
}
else {
return expression;
@ -135,9 +135,16 @@ export class Bindable extends dependencyObservable.DependencyObservable implemen
};
if (types.isString(bindingExpression)) {
var params = bindingExpression.split(",");
result.sourceProperty = Bindable.extractPropertyNameFromExpression(params[0]);
result.expression = params[1];
result.twoWay = params[2] ? params[2].toLowerCase() === "true" : true;
if (params.length === 1) {
result.sourceProperty = Bindable.extractPropertyNameFromExpression(params[0].trim());
result.expression = params[0].search(expressionSymbolsRegex) > -1 ? params[0].trim() : null;
result.twoWay = true;
}
else {
result.sourceProperty = Bindable.extractPropertyNameFromExpression(params[0].trim());
result.expression = params[1].trim();
result.twoWay = params[2] ? params[2].toLowerCase().trim() === "true" : true;
}
}
return result;
}
@ -276,7 +283,6 @@ export class Binding {
this.sourceOptions.property in sourceOptionsInstance) {
value = sourceOptionsInstance[this.sourceOptions.property];
}
return value;
}