diff --git a/apps/automated/src/data/observable-array-tests.ts b/apps/automated/src/data/observable-array-tests.ts index 3c4d0e8b9..1d41cb036 100644 --- a/apps/automated/src/data/observable-array-tests.ts +++ b/apps/automated/src/data/observable-array-tests.ts @@ -360,6 +360,85 @@ export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsSta export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () { let result: ChangedData; + // >> observable-array-splice-change + const array = new ObservableArray([1, 2, 3, 4]); + + array.on(ObservableArray.changeEvent, (args: ChangedData) => { + // Argument (args) is ChangedData. + // args.eventName is "change". + // args.action is "splice". + // args.index is the start index. + // args.removed.length is equal to the number of deleted items. + // args.addedCount is 0. + + // >> (hide) + result = args; + // << (hide) + }); + + array.splice(1, 2); + // << observable-array-splice-change + + TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Splice && result.removed.length === 2 && result.index === 1 && result.addedCount === 0, "ObservableArray splice() should raise 'change' event with correct args!"); +}; + +export const test_ObservableArray_spliceShouldAddSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () { + let result: ChangedData; + + // >> observable-array-splice-change + const array = new ObservableArray([0]); + + array.on(ObservableArray.changeEvent, (args: ChangedData) => { + // Argument (args) is ChangedData. + // args.eventName is "change". + // args.action is "splice". + // args.index is the start index. + // args.removed.length is equal to the number of deleted items. + // args.addedCount is 0. + + // >> (hide) + result = args; + // << (hide) + }); + + // Because their is only one item in the above array the item index should be + // normalized to Index 1. + array.splice(2, 0, 1); + // << observable-array-splice-change + + TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Splice && result.removed.length === 0 && result.index === 1 && result.addedCount === 1, "ObservableArray splice() should raise 'change' event with correct args!"); +}; + +export const test_ObservableArray_spliceShouldAddDeleteSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectArgs = function () { + let result: ChangedData; + + // >> observable-array-splice-change + const array = new ObservableArray([0]); + + array.on(ObservableArray.changeEvent, (args: ChangedData) => { + // Argument (args) is ChangedData. + // args.eventName is "change". + // args.action is "splice". + // args.index is the start index. + // args.removed.length is equal to the number of deleted items. + // args.addedCount is 1. + + // >> (hide) + result = args; + // << (hide) + }); + + // Because we are starting at index 2, their is NOTHING to delete + // So the Starting index should actually be normalized to Index 1 + array.splice(2, 2, 1); + // << observable-array-splice-change + + TKUnit.assert(result.eventName === ObservableArray.changeEvent && result.action === ChangeType.Splice && result.removed.length === 0 && result.index === 1 && result.addedCount === 1, "ObservableArray splice() should raise 'change' event with correct args!"); +}; + +export const test_ObservableArray_spliceShouldRemoveSpecifiedNumberOfElementsStartingFromSpecifiedIndexAndRaiseChangeEventWithCorrectedArgs = function () { + let result: ChangedData; + // >> observable-array-splice-change const array = new ObservableArray([1, 2, 3]); @@ -526,6 +605,28 @@ export const test_ObservableArray_settingLengthToSomethingPerformsSplice = funct TKUnit.assertTrue(changeRaised); }; +export const test_ObservableArray_settingLengthToSomethingPerformsSpliceAdded = function () { + const array = new ObservableArray([1, 2, 3]); + let changeRaised = false; + + array.on('change', (args: ChangedData) => { + changeRaised = true; + TKUnit.assertEqual(args.object, array); + TKUnit.assertEqual(args.eventName, 'change'); + TKUnit.assertEqual(args.action, ChangeType.Splice); + + // Because the array only has 3 elements, the index it starts the change at is #2 + TKUnit.assertEqual(args.index, 3); + TKUnit.assertEqual(args.addedCount, 2); + TKUnit.arrayAssert(args.removed, []); + }); + + array.length = 5; + + TKUnit.assertEqual(array.length, 5); + TKUnit.assertTrue(changeRaised); +}; + const array = new ObservableArray(); // We do not have indexer! diff --git a/packages/core/data/observable-array/index.ts b/packages/core/data/observable-array/index.ts index 6f1123e19..1ad212a9c 100644 --- a/packages/core/data/observable-array/index.ts +++ b/packages/core/data/observable-array/index.ts @@ -32,6 +32,7 @@ export interface ChangedData extends EventData { * Number of added items. */ addedCount: number; + } const CHANGE = 'change'; @@ -113,7 +114,11 @@ export class ObservableArray extends Observable { set length(value: number) { if (types.isNumber(value) && this._array && this._array.length !== value) { - this.splice(value, this._array.length - value); + let added=[]; + for (let i=this._array.length;i < value;++i) { + added.push(undefined); + } + this.splice(value, this._array.length - value, ...added); } } @@ -246,7 +251,15 @@ export class ObservableArray extends Observable { eventName: CHANGE, object: this, action: ChangeType.Splice, - index: Math.max(Math.min(start, this._array.length-1), 0), + + // The logic here is a bit weird; so lets explain why it is written this way + // First of all, if you ADD any items to the array, we want the index to point to + // the first value of the index, so this fixes it when you put a value to high in + // If you remove items from the array, then the index needs to point to the INDEX + // where you removed the item. + // If you add and remove items, the index will point to the remove location as that + // is the index you passed in. + index: Math.max(Math.min(start, length - (result.length > 0 ? 1 : 0)), 0), removed: result, addedCount: this._array.length + result.length - length, }); diff --git a/packages/core/ui/text-base/formatted-string.ts b/packages/core/ui/text-base/formatted-string.ts index 96f5401f3..1251df8dc 100644 --- a/packages/core/ui/text-base/formatted-string.ts +++ b/packages/core/ui/text-base/formatted-string.ts @@ -103,7 +103,7 @@ export class FormattedString extends ViewBase implements FormattedStringDefiniti // First add to logical tree so that inherited properties are set. this._addView(span); - // Then attach handlers - we skip the first nofitication because + // Then attach handlers - we skip the first notification because // we raise change for the whole instance. this.addPropertyChangeHandler(span); }