diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index e0ddd05508..562fad7b2e 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -12,6 +12,7 @@ import {Observable} from 'rxjs/Observable'; import {QueryList as viewEngine_QueryList} from '../linker/query_list'; import {Type} from '../type'; +import {getSymbolIterator} from '../util'; import {assertEqual, assertNotNull} from './assert'; import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di'; @@ -298,57 +299,77 @@ function createPredicate( class QueryList_/* implements viewEngine_QueryList */ { readonly dirty = true; readonly changes: Observable; - private _values: T[]|null = null; + private _values: T[] = []; /** @internal */ _valuesTree: any[] = []; - get length(): number { - ngDevMode && assertNotNull(this._values, 'refreshed'); - return this._values !.length; - } + get length(): number { return this._values.length; } get first(): T|null { - ngDevMode && assertNotNull(this._values, 'refreshed'); - let values = this._values !; + let values = this._values; return values.length ? values[0] : null; } get last(): T|null { - ngDevMode && assertNotNull(this._values, 'refreshed'); - let values = this._values !; + let values = this._values; return values.length ? values[values.length - 1] : null; } - map(fn: (item: T, index: number, array: T[]) => U): U[] { - throw new Error('Method not implemented.'); - } + /** + * See + * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) + */ + map(fn: (item: T, index: number, array: T[]) => U): U[] { return this._values.map(fn); } + + /** + * See + * [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) + */ filter(fn: (item: T, index: number, array: T[]) => boolean): T[] { - throw new Error('Method not implemented.'); + return this._values.filter(fn); } + + /** + * See + * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) + */ find(fn: (item: T, index: number, array: T[]) => boolean): T|undefined { - throw new Error('Method not implemented.'); + return this._values.find(fn); } + + /** + * See + * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) + */ reduce(fn: (prevValue: U, curValue: T, curIndex: number, array: T[]) => U, init: U): U { - throw new Error('Method not implemented.'); - } - forEach(fn: (item: T, index: number, array: T[]) => void): void { - throw new Error('Method not implemented.'); + return this._values.reduce(fn, init); } + + /** + * See + * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) + */ + forEach(fn: (item: T, index: number, array: T[]) => void): void { this._values.forEach(fn); } + + /** + * See + * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) + */ some(fn: (value: T, index: number, array: T[]) => boolean): boolean { - throw new Error('Method not implemented.'); - } - toArray(): T[] { - ngDevMode && assertNotNull(this._values, 'refreshed'); - return this._values !; - } - toString(): string { - ngDevMode && assertNotNull(this._values, 'refreshed'); - return this._values !.toString(); + return this._values.some(fn); } + + toArray(): T[] { return this._values.slice(0); } + + [getSymbolIterator()](): Iterator { return (this._values as any)[getSymbolIterator()](); } + + toString(): string { return this._values.toString(); } + reset(res: (any[]|T)[]): void { this._values = flatten(res); (this as{dirty: boolean}).dirty = false; } + notifyOnChanges(): void { throw new Error('Method not implemented.'); } setDirty(): void { (this as{dirty: boolean}).dirty = true; } destroy(): void { throw new Error('Method not implemented.'); } diff --git a/packages/core/test/render3/query_list_spec.ts b/packages/core/test/render3/query_list_spec.ts new file mode 100644 index 0000000000..648d27eadc --- /dev/null +++ b/packages/core/test/render3/query_list_spec.ts @@ -0,0 +1,94 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {QueryList} from '../../src/render3/query'; + +describe('QueryList', () => { + let q: QueryList; + + beforeEach(() => { q = new QueryList(); }); + + describe('dirty and reset', () => { + + it('should be dirty and empty initially', () => { + expect(q.dirty).toBeTruthy(); + expect(q.length).toBe(0); + }); + + it('should be not dirty after reset', () => { + expect(q.dirty).toBeTruthy(); + q.reset([1, 2, 3]); + expect(q.dirty).toBeFalsy(); + expect(q.length).toBe(3); + }); + + }); + + describe('elements access', () => { + + it('should give access to the first / last element', () => { + q.reset([1, 2, 3]); + expect(q.length).toBe(3); + expect(q.first).toBe(1); + expect(q.last).toBe(3); + }); + + it('should return copy of matched elements as an array', () => { + q.reset([1, 2, 3]); + + const result = q.toArray(); + expect(result).toEqual([1, 2, 3]); + + // mutate returned result to make sure that oryginal values in query are not mutated + result.push(4); + expect(q.toArray()).toEqual([1, 2, 3]); + }); + + }); + + describe('array-like methods', () => { + + it('should support map method', () => { + q.reset([1, 2, 3]); + expect(q.map((item: number, idx: number) => { + return item + idx; + })).toEqual([1, 3, 5]); + }); + + it('should support filter method', () => { + q.reset([1, 2, 3]); + expect(q.filter((item: number, idx: number) => { return item > 2; })).toEqual([3]); + }); + + it('should support find method', () => { + q.reset([1, 2, 3]); + expect(q.find((item: number, idx: number) => { return item > 0; })).toBe(1); + }); + + it('should support reduce method', () => { + q.reset([1, 2, 3]); + expect(q.reduce((prevValue: number, curValue: number, curIndex: number) => { + return prevValue + curValue + curIndex; + }, 0)).toBe(9); + }); + + it('should support forEach method', () => { + let itemIdxSum = 0; + q.reset([1, 2, 3]); + q.forEach((item: number, idx: number) => { itemIdxSum += item + idx; }); + expect(itemIdxSum).toBe(9); + }); + + it('should support some method', () => { + q.reset([1, 2, 3]); + expect(q.some((item: number, idx: number) => { return item > 0; })).toBe(true); + }); + + }); + +});