fix(ivy): QueryList not instance of exported QueryList (#27942)

Fixes Ivy's `QueryList` not being an instance of the exported ViewEnginer `QueryList`.

Also reworks `first`, `last` and `length` to be regular properties, rather than setters. Reworking `length` was required to be able to extend the ViewEngine `QueryList`, but I reworked `first` and `last` as well since getters generate a lot more code when transpiled to ES5.

These changes fix FW-706.

PR Close #27942
This commit is contained in:
Kristiyan Kostadinov
2019-01-05 14:43:58 +02:00
committed by Kara Erickson
parent 9de9c8ad03
commit c1dacdd890
6 changed files with 13 additions and 200 deletions

View File

@ -121,7 +121,6 @@ export {
} from './pipe';
export {
QueryList,
query,
queryRefresh,
} from './query';

View File

@ -12,7 +12,7 @@ import {Observable} from 'rxjs';
import {EventEmitter} from '../event_emitter';
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
import {QueryList as viewEngine_QueryList} from '../linker/query_list';
import {QueryList} from '../linker/query_list';
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
import {Type} from '../type';
import {getSymbolIterator} from '../util';
@ -27,7 +27,7 @@ import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, u
import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
import {LView, TVIEW} from './interfaces/view';
import {getIsParent, getLView, getOrCreateCurrentQueries} from './state';
import {flatten, isContentQueryHost} from './util';
import {isContentQueryHost} from './util';
import {createElementRef, createTemplateRef} from './view_engine_compatibility';
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4;
@ -95,9 +95,8 @@ export class LQueries_ implements LQueries {
public parent: LQueries_|null, private shallow: LQuery<any>|null,
private deep: LQuery<any>|null) {}
track<T>(
queryList: viewEngine_QueryList<T>, predicate: Type<T>|string[], descend?: boolean,
read?: Type<T>): void {
track<T>(queryList: QueryList<T>, predicate: Type<T>|string[], descend?: boolean, read?: Type<T>):
void {
if (descend) {
this.deep = createQuery(this.deep, queryList, predicate, read != null ? read : null);
} else {
@ -355,92 +354,7 @@ function createQuery<T>(
};
}
class QueryList_<T>/* implements viewEngine_QueryList<T> */ {
readonly dirty = true;
readonly changes: Observable<T> = new EventEmitter();
private _values: T[] = [];
/** @internal */
_valuesTree: any[] = [];
get length(): number { return this._values.length; }
get first(): T|null {
let values = this._values;
return values.length ? values[0] : null;
}
get last(): T|null {
let values = this._values;
return values.length ? values[values.length - 1] : null;
}
/**
* See
* [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
*/
map<U>(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[] {
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 {
return this._values.find(fn);
}
/**
* See
* [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
*/
reduce<U>(fn: (prevValue: U, curValue: T, curIndex: number, array: T[]) => U, init: U): U {
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 {
return this._values.some(fn);
}
toArray(): T[] { return this._values.slice(0); }
[getSymbolIterator()](): Iterator<T> { 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 { (this.changes as EventEmitter<any>).emit(this); }
setDirty(): void { (this as{dirty: boolean}).dirty = true; }
destroy(): void {
(this.changes as EventEmitter<any>).complete();
(this.changes as EventEmitter<any>).unsubscribe();
}
}
// NOTE: this hack is here because IQueryList has private members and therefore
// it can't be implemented only extended.
export type QueryList<T> = viewEngine_QueryList<T>;
export const QueryList: typeof viewEngine_QueryList = QueryList_ as any;
type QueryList_<T> = QueryList<T>& {_valuesTree: any[]};
/**
* Creates and returns a QueryList.
@ -459,6 +373,7 @@ export function query<T>(
ngDevMode && assertPreviousIsParent(getIsParent());
const queryList = new QueryList<T>();
const queries = getOrCreateCurrentQueries(LQueries_);
(queryList as QueryList_<T>)._valuesTree = [];
queries.track(queryList, predicate, descend, read);
storeCleanupWithContext(getLView(), queryList, queryList.destroy);
if (memoryIndex != null) {
@ -475,7 +390,7 @@ export function query<T>(
export function queryRefresh(queryList: QueryList<any>): boolean {
const queryListImpl = (queryList as any as QueryList_<any>);
if (queryList.dirty) {
queryList.reset(queryListImpl._valuesTree);
queryList.reset(queryListImpl._valuesTree || []);
queryList.notifyOnChanges();
return true;
}