fix(ivy): support static ViewChild queries (#28811)
This commit adds support for the `static: true` flag in `ViewChild` queries. Prior to this commit, all `ViewChild` queries were resolved after change detection ran. This is a problem for backwards compatibility because View Engine also supported "static" queries which would resolve before change detection. Now if users add a `static: true` option, the query will be resolved in creation mode (before change detection runs). For example: ```ts @ViewChild(TemplateRef, {static: true}) template !: TemplateRef; ``` This feature will come in handy for components that need to create components dynamically. PR Close #28811
This commit is contained in:
parent
ae16378ee7
commit
a4638d5a81
|
@ -12,7 +12,7 @@
|
|||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 1440,
|
||||
"main": 12885,
|
||||
"main": 13019,
|
||||
"polyfills": 38390
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,6 +229,9 @@ export function extractQueryMetadata(
|
|||
const node = unwrapForwardRef(args[0], reflector);
|
||||
const arg = evaluator.evaluate(node);
|
||||
|
||||
/** Whether or not this query should collect only static results (see view/api.ts) */
|
||||
let isStatic: boolean = false;
|
||||
|
||||
// Extract the predicate
|
||||
let predicate: Expression|string[]|null = null;
|
||||
if (arg instanceof Reference) {
|
||||
|
@ -263,13 +266,28 @@ export function extractQueryMetadata(
|
|||
}
|
||||
descendants = descendantsValue;
|
||||
}
|
||||
|
||||
if (options.has('static')) {
|
||||
const staticValue = evaluator.evaluate(options.get('static') !);
|
||||
if (typeof staticValue !== 'boolean') {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, node, `@${name} options.static must be a boolean`);
|
||||
}
|
||||
isStatic = staticValue;
|
||||
}
|
||||
|
||||
} else if (args.length > 2) {
|
||||
// Too many arguments.
|
||||
throw new Error(`@${name} has too many arguments`);
|
||||
}
|
||||
|
||||
return {
|
||||
propertyName, predicate, first, descendants, read,
|
||||
propertyName,
|
||||
predicate,
|
||||
first,
|
||||
descendants,
|
||||
read,
|
||||
static: isStatic,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1376,8 +1376,8 @@ describe('compiler compliance', () => {
|
|||
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
|
||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵviewQuery(SomeDirective, true);
|
||||
$r3$.ɵviewQuery(SomeDirective, true);
|
||||
$r3$.ɵviewQuery(SomeDirective, true, null);
|
||||
$r3$.ɵviewQuery(SomeDirective, true, null);
|
||||
}
|
||||
if (rf & 2) {
|
||||
var $tmp$;
|
||||
|
@ -1434,8 +1434,8 @@ describe('compiler compliance', () => {
|
|||
…
|
||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵviewQuery($e0_attrs$, true);
|
||||
$r3$.ɵviewQuery($e1_attrs$, true);
|
||||
$r3$.ɵviewQuery($e0_attrs$, true, null);
|
||||
$r3$.ɵviewQuery($e1_attrs$, true, null);
|
||||
}
|
||||
if (rf & 2) {
|
||||
var $tmp$;
|
||||
|
@ -1452,6 +1452,67 @@ describe('compiler compliance', () => {
|
|||
expectEmit(source, ViewQueryComponentDefinition, 'Invalid ViewQuery declaration');
|
||||
});
|
||||
|
||||
it('should support static view queries', () => {
|
||||
const files = {
|
||||
app: {
|
||||
...directive,
|
||||
'view_query.component.ts': `
|
||||
import {Component, NgModule, ViewChild} from '@angular/core';
|
||||
import {SomeDirective} from './some.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'view-query-component',
|
||||
template: \`
|
||||
<div someDir></div>
|
||||
\`
|
||||
})
|
||||
export class ViewQueryComponent {
|
||||
@ViewChild(SomeDirective, {static: true}) someDir !: SomeDirective;
|
||||
@ViewChild('foo', {static: false}) foo !: ElementRef;
|
||||
}
|
||||
|
||||
@NgModule({declarations: [SomeDirective, ViewQueryComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const ViewQueryComponentDefinition = `
|
||||
const $refs$ = ["foo"];
|
||||
const $e0_attrs$ = ["someDir",""];
|
||||
…
|
||||
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||
type: ViewQueryComponent,
|
||||
selectors: [["view-query-component"]],
|
||||
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
|
||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵstaticViewQuery(SomeDirective, true, null);
|
||||
$r3$.ɵviewQuery($refs$, true, null);
|
||||
}
|
||||
if (rf & 2) {
|
||||
var $tmp$;
|
||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDir = $tmp$.first));
|
||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.foo = $tmp$.first));
|
||||
}
|
||||
},
|
||||
consts: 1,
|
||||
vars: 0,
|
||||
template: function ViewQueryComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵelement(0, "div", $e0_attrs$);
|
||||
}
|
||||
},
|
||||
directives: function () { return [SomeDirective]; },
|
||||
encapsulation: 2
|
||||
});`;
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
const source = result.source;
|
||||
|
||||
expectEmit(source, ViewQueryComponentDefinition, 'Invalid ViewQuery declaration');
|
||||
});
|
||||
|
||||
it('should support view queries with read tokens specified', () => {
|
||||
const files = {
|
||||
app: {
|
||||
|
@ -1555,8 +1616,8 @@ describe('compiler compliance', () => {
|
|||
},
|
||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true);
|
||||
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false);
|
||||
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true, null);
|
||||
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false, null);
|
||||
}
|
||||
if (rf & 2) {
|
||||
var $tmp$;
|
||||
|
@ -1615,8 +1676,8 @@ describe('compiler compliance', () => {
|
|||
…
|
||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true);
|
||||
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false);
|
||||
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true, null);
|
||||
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false, null);
|
||||
}
|
||||
if (rf & 2) {
|
||||
var $tmp$;
|
||||
|
|
|
@ -17,13 +17,13 @@ const trim = (input: string): string => input.replace(/\s+/g, ' ').trim();
|
|||
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
||||
|
||||
const viewQueryRegExp = (descend: boolean, ref?: string): RegExp => {
|
||||
const maybeRef = ref ? `, ${ref}` : ``;
|
||||
return new RegExp(`i0\\.ɵviewQuery\\(\\w+, ${descend}${maybeRef}\\)`);
|
||||
const maybeRef = ref ? `${ref}` : `null`;
|
||||
return new RegExp(`i0\\.ɵviewQuery\\(\\w+, ${descend}, ${maybeRef}\\)`);
|
||||
};
|
||||
|
||||
const contentQueryRegExp = (predicate: string, descend: boolean, ref?: string): RegExp => {
|
||||
const maybeRef = ref ? `, ${ref}` : ``;
|
||||
return new RegExp(`i0\\.ɵcontentQuery\\(dirIndex, ${predicate}, ${descend}${maybeRef}\\)`);
|
||||
const maybeRef = ref ? `${ref}` : `null`;
|
||||
return new RegExp(`i0\\.ɵcontentQuery\\(dirIndex, ${predicate}, ${descend}, ${maybeRef}\\)`);
|
||||
};
|
||||
|
||||
describe('ngtsc behavioral tests', () => {
|
||||
|
@ -1017,7 +1017,7 @@ describe('ngtsc behavioral tests', () => {
|
|||
expect(jsContents).toMatch(varRegExp('accessor'));
|
||||
// match `i0.ɵcontentQuery(dirIndex, _c1, true, TemplateRef)`
|
||||
expect(jsContents).toMatch(contentQueryRegExp('\\w+', true, 'TemplateRef'));
|
||||
// match `i0.ɵviewQuery(_c2, true)`
|
||||
// match `i0.ɵviewQuery(_c2, true, null)`
|
||||
expect(jsContents).toMatch(viewQueryRegExp(true));
|
||||
});
|
||||
|
||||
|
@ -1039,9 +1039,9 @@ describe('ngtsc behavioral tests', () => {
|
|||
|
||||
env.driveMain();
|
||||
const jsContents = env.getContents('test.js');
|
||||
// match `i0.ɵcontentQuery(dirIndex, TemplateRef, true)`
|
||||
// match `i0.ɵcontentQuery(dirIndex, TemplateRef, true, null)`
|
||||
expect(jsContents).toMatch(contentQueryRegExp('TemplateRef', true));
|
||||
// match `i0.ɵcontentQuery(dirIndex, ViewContainerRef, true)`
|
||||
// match `i0.ɵcontentQuery(dirIndex, ViewContainerRef, true, null)`
|
||||
expect(jsContents).toMatch(contentQueryRegExp('ViewContainerRef', true));
|
||||
});
|
||||
|
||||
|
|
|
@ -150,6 +150,7 @@ export interface R3QueryMetadataFacade {
|
|||
predicate: any|string[];
|
||||
descendants: boolean;
|
||||
read: any|null;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
export interface ParseSourceSpan {
|
||||
|
|
|
@ -199,6 +199,7 @@ function convertToR3QueryMetadata(facade: R3QueryMetadataFacade): R3QueryMetadat
|
|||
predicate: Array.isArray(facade.predicate) ? facade.predicate :
|
||||
new WrappedNodeExpr(facade.predicate),
|
||||
read: facade.read ? new WrappedNodeExpr(facade.read) : null,
|
||||
static: facade.static
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,7 @@ export class Identifiers {
|
|||
|
||||
static queryRefresh: o.ExternalReference = {name: 'ɵqueryRefresh', moduleName: CORE};
|
||||
static viewQuery: o.ExternalReference = {name: 'ɵviewQuery', moduleName: CORE};
|
||||
static staticViewQuery: o.ExternalReference = {name: 'ɵstaticViewQuery', moduleName: CORE};
|
||||
static loadViewQuery: o.ExternalReference = {name: 'ɵloadViewQuery', moduleName: CORE};
|
||||
static contentQuery: o.ExternalReference = {name: 'ɵcontentQuery', moduleName: CORE};
|
||||
static loadContentQuery: o.ExternalReference = {name: 'ɵloadContentQuery', moduleName: CORE};
|
||||
|
|
|
@ -229,6 +229,21 @@ export interface R3QueryMetadata {
|
|||
* for a given node is to be returned.
|
||||
*/
|
||||
read: o.Expression|null;
|
||||
|
||||
/**
|
||||
* Whether or not this query should collect only static results.
|
||||
*
|
||||
* If static is true, the query's results will be set on the component after nodes are created,
|
||||
* but before change detection runs. This means that any results that relied upon change detection
|
||||
* to run (e.g. results inside *ngIf or *ngFor views) will not be collected. Query results are
|
||||
* available in the ngOnInit hook.
|
||||
*
|
||||
* If static is false, the query's results will be set on the component after change detection
|
||||
* runs. This means that the query results can contain nodes inside *ngIf or *ngFor views, but
|
||||
* the results will not be available in the ngOnInit hook (only in the ngAfterContentInit for
|
||||
* content hooks and ngAfterViewInit for view hooks).
|
||||
*/
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -457,6 +457,7 @@ function queriesFromGlobalMetadata(
|
|||
first: query.first,
|
||||
predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
|
||||
descendants: query.descendants, read,
|
||||
static: !!query.static
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -490,10 +491,8 @@ function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool):
|
|||
const parameters = [
|
||||
getQueryPredicate(query, constantPool),
|
||||
o.literal(query.descendants),
|
||||
query.read || o.literal(null),
|
||||
];
|
||||
if (query.read) {
|
||||
parameters.push(query.read);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
@ -590,9 +589,11 @@ function createViewQueriesFunction(
|
|||
const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
|
||||
|
||||
meta.viewQueries.forEach((query: R3QueryMetadata) => {
|
||||
const queryInstruction = query.static ? R3.staticViewQuery : R3.viewQuery;
|
||||
|
||||
// creation, e.g. r3.viewQuery(somePredicate, true);
|
||||
const queryDefinition =
|
||||
o.importExpr(R3.viewQuery).callFn(prepareQueryParams(query, constantPool));
|
||||
o.importExpr(queryInstruction).callFn(prepareQueryParams(query, constantPool));
|
||||
createStatements.push(queryDefinition.toStmt());
|
||||
|
||||
// update, e.g. (r3.queryRefresh(tmp = r3.loadViewQuery()) && (ctx.someDir = tmp));
|
||||
|
|
|
@ -150,6 +150,7 @@ export interface R3QueryMetadataFacade {
|
|||
predicate: any|string[];
|
||||
descendants: boolean;
|
||||
read: any|null;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
export interface ParseSourceSpan {
|
||||
|
|
|
@ -81,6 +81,7 @@ export {
|
|||
containerRefreshEnd as ɵcontainerRefreshEnd,
|
||||
queryRefresh as ɵqueryRefresh,
|
||||
viewQuery as ɵviewQuery,
|
||||
staticViewQuery as ɵstaticViewQuery,
|
||||
loadViewQuery as ɵloadViewQuery,
|
||||
contentQuery as ɵcontentQuery,
|
||||
loadContentQuery as ɵloadContentQuery,
|
||||
|
|
|
@ -124,6 +124,7 @@ export {
|
|||
export {
|
||||
queryRefresh,
|
||||
viewQuery,
|
||||
staticViewQuery,
|
||||
loadViewQuery,
|
||||
contentQuery,
|
||||
loadContentQuery,
|
||||
|
|
|
@ -37,7 +37,7 @@ import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTEXT, DECLARATION_VIEW, Expa
|
|||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||
import {appendChild, appendProjectedNode, createTextNode, getLViewChild, insertView, removeView} from './node_manipulation';
|
||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode} from './state';
|
||||
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode,} from './state';
|
||||
import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
|
||||
import {BoundPlayerFactory} from './styling/player_factory';
|
||||
import {ANIMATION_PROP_PREFIX, allocateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContext, hasClassInput, hasStyleInput, hasStyling, isAnimationProp} from './styling/util';
|
||||
|
@ -784,6 +784,7 @@ export function createTView(
|
|||
expandoStartIndex: initialViewLength,
|
||||
expandoInstructions: null,
|
||||
firstTemplatePass: true,
|
||||
staticViewQueries: false,
|
||||
initHooks: null,
|
||||
checkHooks: null,
|
||||
contentHooks: null,
|
||||
|
@ -2922,20 +2923,23 @@ export function checkView<T>(hostView: LView, component: T) {
|
|||
|
||||
try {
|
||||
namespaceHTML();
|
||||
creationMode && executeViewQueryFn(hostView, hostTView, component);
|
||||
creationMode && executeViewQueryFn(RenderFlags.Create, hostTView, component);
|
||||
templateFn(getRenderFlags(hostView), component);
|
||||
refreshDescendantViews(hostView);
|
||||
!creationMode && executeViewQueryFn(hostView, hostTView, component);
|
||||
// Only check view queries again in creation mode if there are static view queries
|
||||
if (!creationMode || hostTView.staticViewQueries) {
|
||||
executeViewQueryFn(RenderFlags.Update, hostTView, component);
|
||||
}
|
||||
} finally {
|
||||
leaveView(oldView);
|
||||
}
|
||||
}
|
||||
|
||||
function executeViewQueryFn<T>(lView: LView, tView: TView, component: T): void {
|
||||
function executeViewQueryFn<T>(flags: RenderFlags, tView: TView, component: T): void {
|
||||
const viewQuery = tView.viewQuery;
|
||||
if (viewQuery) {
|
||||
setCurrentQueryIndex(tView.viewQueryStartIndex);
|
||||
viewQuery(getRenderFlags(lView), component);
|
||||
viewQuery(flags, component);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -376,6 +376,14 @@ export interface TView {
|
|||
*/
|
||||
expandoStartIndex: number;
|
||||
|
||||
/**
|
||||
* Whether or not there are any static view queries tracked on this view.
|
||||
*
|
||||
* We store this so we know whether or not we should do a view query
|
||||
* refresh after creation mode to collect static query results.
|
||||
*/
|
||||
staticViewQueries: boolean;
|
||||
|
||||
/**
|
||||
* The index where the viewQueries section of `LView` begins. This section contains
|
||||
* view queries defined for a component/directive.
|
||||
|
|
|
@ -169,7 +169,8 @@ export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3Qu
|
|||
predicate: convertToR3QueryPredicate(ann.selector),
|
||||
descendants: ann.descendants,
|
||||
first: ann.first,
|
||||
read: ann.read ? ann.read : null
|
||||
read: ann.read ? ann.read : null,
|
||||
static: !!ann.static
|
||||
};
|
||||
}
|
||||
function extractQueriesMetadata(
|
||||
|
|
|
@ -88,6 +88,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
|||
'ɵpipe': r3.pipe,
|
||||
'ɵqueryRefresh': r3.queryRefresh,
|
||||
'ɵviewQuery': r3.viewQuery,
|
||||
'ɵstaticViewQuery': r3.staticViewQuery,
|
||||
'ɵloadViewQuery': r3.loadViewQuery,
|
||||
'ɵcontentQuery': r3.contentQuery,
|
||||
'ɵloadContentQuery': r3.loadContentQuery,
|
||||
|
|
|
@ -24,7 +24,7 @@ import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
|||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
||||
import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
||||
import {CONTENT_QUERIES, HEADER_OFFSET, LView, QUERIES, TVIEW} from './interfaces/view';
|
||||
import {getCurrentQueryIndex, getIsParent, getLView, setCurrentQueryIndex} from './state';
|
||||
import {getCurrentQueryIndex, getIsParent, getLView, isCreationMode, setCurrentQueryIndex} from './state';
|
||||
import {createElementRef, createTemplateRef} from './view_engine_compatibility';
|
||||
|
||||
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4;
|
||||
|
@ -338,7 +338,7 @@ function createQuery<T>(
|
|||
};
|
||||
}
|
||||
|
||||
type QueryList_<T> = QueryList<T>& {_valuesTree: any[]};
|
||||
type QueryList_<T> = QueryList<T>& {_valuesTree: any[], _static: boolean};
|
||||
|
||||
/**
|
||||
* Creates and returns a QueryList.
|
||||
|
@ -350,12 +350,13 @@ type QueryList_<T> = QueryList<T>& {_valuesTree: any[]};
|
|||
*/
|
||||
export function query<T>(
|
||||
// TODO: "read" should be an AbstractType (FW-486)
|
||||
predicate: Type<any>| string[], descend?: boolean, read?: any): QueryList<T> {
|
||||
predicate: Type<any>| string[], descend: boolean, read: any): QueryList<T> {
|
||||
ngDevMode && assertPreviousIsParent(getIsParent());
|
||||
const lView = getLView();
|
||||
const queryList = new QueryList<T>();
|
||||
const queryList = new QueryList<T>() as QueryList_<T>;
|
||||
const queries = lView[QUERIES] || (lView[QUERIES] = new LQueries_(null, null, null));
|
||||
(queryList as QueryList_<T>)._valuesTree = [];
|
||||
queryList._valuesTree = [];
|
||||
queryList._static = false;
|
||||
queries.track(queryList, predicate, descend, read);
|
||||
storeCleanupWithContext(lView, queryList, queryList.destroy);
|
||||
return queryList;
|
||||
|
@ -368,7 +369,10 @@ export function query<T>(
|
|||
*/
|
||||
export function queryRefresh(queryList: QueryList<any>): boolean {
|
||||
const queryListImpl = (queryList as any as QueryList_<any>);
|
||||
if (queryList.dirty) {
|
||||
const creationMode = isCreationMode();
|
||||
|
||||
// if creation mode and static or update mode and not static
|
||||
if (queryList.dirty && creationMode === queryListImpl._static) {
|
||||
queryList.reset(queryListImpl._valuesTree || []);
|
||||
queryList.notifyOnChanges();
|
||||
return true;
|
||||
|
@ -376,6 +380,24 @@ export function queryRefresh(queryList: QueryList<any>): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new QueryList for a static view query.
|
||||
*
|
||||
* @param predicate The type for which the query will search
|
||||
* @param descend Whether or not to descend into children
|
||||
* @param read What to save in the query
|
||||
*/
|
||||
export function staticViewQuery<T>(
|
||||
// TODO(FW-486): "read" should be an AbstractType
|
||||
predicate: Type<any>| string[], descend: boolean, read: any): void {
|
||||
const queryList = viewQuery(predicate, descend, read) as QueryList_<T>;
|
||||
const tView = getLView()[TVIEW];
|
||||
queryList._static = true;
|
||||
if (!tView.staticViewQueries) {
|
||||
tView.staticViewQueries = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new QueryList, stores the reference in LView and returns QueryList.
|
||||
*
|
||||
|
@ -385,8 +407,8 @@ export function queryRefresh(queryList: QueryList<any>): boolean {
|
|||
* @returns QueryList<T>
|
||||
*/
|
||||
export function viewQuery<T>(
|
||||
// TODO: "read" should be an AbstractType (FW-486)
|
||||
predicate: Type<any>| string[], descend?: boolean, read?: any): QueryList<T> {
|
||||
// TODO(FW-486): "read" should be an AbstractType
|
||||
predicate: Type<any>| string[], descend: boolean, read: any): QueryList<T> {
|
||||
const lView = getLView();
|
||||
const tView = lView[TVIEW];
|
||||
if (tView.firstTemplatePass) {
|
||||
|
@ -419,9 +441,9 @@ export function loadViewQuery<T>(): T {
|
|||
* @returns QueryList<T>
|
||||
*/
|
||||
export function contentQuery<T>(
|
||||
directiveIndex: number, predicate: Type<any>| string[], descend?: boolean,
|
||||
directiveIndex: number, predicate: Type<any>| string[], descend: boolean,
|
||||
// TODO: "read" should be an AbstractType (FW-486)
|
||||
read?: any): QueryList<T> {
|
||||
read: any): QueryList<T> {
|
||||
const lView = getLView();
|
||||
const tView = lView[TVIEW];
|
||||
const contentQuery: QueryList<T> = query<T>(predicate, descend, read);
|
||||
|
@ -448,4 +470,4 @@ export function loadContentQuery<T>(): QueryList<T> {
|
|||
|
||||
setCurrentQueryIndex(index + 1);
|
||||
return lView[CONTENT_QUERIES] ![index];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ describe('query logic', () => {
|
|||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComp, QueryComp, SimpleCompA, SimpleCompB, StaticViewQueryComp, TextDirective,
|
||||
SubclassStaticViewQueryComp, StaticContentQueryComp, SubclassStaticContentQueryComp
|
||||
SubclassStaticViewQueryComp, StaticContentQueryComp, SubclassStaticContentQueryComp,
|
||||
QueryCompWithChanges
|
||||
]
|
||||
});
|
||||
});
|
||||
|
@ -87,48 +88,78 @@ describe('query logic', () => {
|
|||
expect(comp.viewChildren.length).toBe(2);
|
||||
});
|
||||
|
||||
fixmeIvy('Must support static view queries in Ivy')
|
||||
.it('should set static view child queries in creation mode (and just in creation mode)',
|
||||
() => {
|
||||
const fixture = TestBed.createComponent(StaticViewQueryComp);
|
||||
const component = fixture.componentInstance;
|
||||
it('should set static view child queries in creation mode (and just in creation mode)', () => {
|
||||
const fixture = TestBed.createComponent(StaticViewQueryComp);
|
||||
const component = fixture.componentInstance;
|
||||
|
||||
// static ViewChild query should be set in creation mode, before CD runs
|
||||
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(component.textDir.text).toEqual('');
|
||||
expect(component.setEvents).toEqual(['textDir set']);
|
||||
// static ViewChild query should be set in creation mode, before CD runs
|
||||
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(component.textDir.text).toEqual('');
|
||||
expect(component.setEvents).toEqual(['textDir set']);
|
||||
|
||||
// dynamic ViewChild query should not have been resolved yet
|
||||
expect(component.foo).not.toBeDefined();
|
||||
// dynamic ViewChild query should not have been resolved yet
|
||||
expect(component.foo).not.toBeDefined();
|
||||
|
||||
const span = fixture.nativeElement.querySelector('span');
|
||||
fixture.detectChanges();
|
||||
expect(component.textDir.text).toEqual('some text');
|
||||
expect(component.foo.nativeElement).toBe(span);
|
||||
expect(component.setEvents).toEqual(['textDir set', 'foo set']);
|
||||
});
|
||||
const span = fixture.nativeElement.querySelector('span');
|
||||
fixture.detectChanges();
|
||||
expect(component.textDir.text).toEqual('some text');
|
||||
expect(component.foo.nativeElement).toBe(span);
|
||||
expect(component.setEvents).toEqual(['textDir set', 'foo set']);
|
||||
});
|
||||
|
||||
fixmeIvy('Must support static view queries in Ivy')
|
||||
.it('should support static view child queries inherited from superclasses', () => {
|
||||
const fixture = TestBed.createComponent(SubclassStaticViewQueryComp);
|
||||
const component = fixture.componentInstance;
|
||||
const divs = fixture.nativeElement.querySelectorAll('div');
|
||||
const spans = fixture.nativeElement.querySelectorAll('span');
|
||||
it('should support static view child queries inherited from superclasses', () => {
|
||||
const fixture = TestBed.createComponent(SubclassStaticViewQueryComp);
|
||||
const component = fixture.componentInstance;
|
||||
const divs = fixture.nativeElement.querySelectorAll('div');
|
||||
const spans = fixture.nativeElement.querySelectorAll('span');
|
||||
|
||||
// static ViewChild queries should be set in creation mode, before CD runs
|
||||
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(component.textDir.text).toEqual('');
|
||||
expect(component.bar.nativeElement).toEqual(divs[1]);
|
||||
// static ViewChild queries should be set in creation mode, before CD runs
|
||||
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(component.textDir.text).toEqual('');
|
||||
expect(component.bar.nativeElement).toEqual(divs[1]);
|
||||
|
||||
// dynamic ViewChild queries should not have been resolved yet
|
||||
expect(component.foo).not.toBeDefined();
|
||||
expect(component.baz).not.toBeDefined();
|
||||
// dynamic ViewChild queries should not have been resolved yet
|
||||
expect(component.foo).not.toBeDefined();
|
||||
expect(component.baz).not.toBeDefined();
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(component.textDir.text).toEqual('some text');
|
||||
expect(component.foo.nativeElement).toBe(spans[0]);
|
||||
expect(component.baz.nativeElement).toBe(spans[1]);
|
||||
});
|
||||
fixture.detectChanges();
|
||||
expect(component.textDir.text).toEqual('some text');
|
||||
expect(component.foo.nativeElement).toBe(spans[0]);
|
||||
expect(component.baz.nativeElement).toBe(spans[1]);
|
||||
});
|
||||
|
||||
it('should support multiple static view queries (multiple template passes)', () => {
|
||||
const template = `
|
||||
<static-view-query-comp></static-view-query-comp>
|
||||
<static-view-query-comp></static-view-query-comp>
|
||||
`;
|
||||
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
||||
const fixture = TestBed.createComponent(AppComp);
|
||||
|
||||
const firstComponent = fixture.debugElement.children[0].injector.get(StaticViewQueryComp);
|
||||
const secondComponent = fixture.debugElement.children[1].injector.get(StaticViewQueryComp);
|
||||
|
||||
// static ViewChild query should be set in creation mode, before CD runs
|
||||
expect(firstComponent.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(secondComponent.textDir).toBeAnInstanceOf(TextDirective);
|
||||
expect(firstComponent.textDir.text).toEqual('');
|
||||
expect(secondComponent.textDir.text).toEqual('');
|
||||
expect(firstComponent.setEvents).toEqual(['textDir set']);
|
||||
expect(secondComponent.setEvents).toEqual(['textDir set']);
|
||||
|
||||
// dynamic ViewChild query should not have been resolved yet
|
||||
expect(firstComponent.foo).not.toBeDefined();
|
||||
expect(secondComponent.foo).not.toBeDefined();
|
||||
|
||||
const spans = fixture.nativeElement.querySelectorAll('span');
|
||||
fixture.detectChanges();
|
||||
expect(firstComponent.textDir.text).toEqual('some text');
|
||||
expect(secondComponent.textDir.text).toEqual('some text');
|
||||
expect(firstComponent.foo.nativeElement).toBe(spans[0]);
|
||||
expect(secondComponent.foo.nativeElement).toBe(spans[1]);
|
||||
expect(firstComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
||||
expect(secondComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
@ -290,6 +321,30 @@ describe('query logic', () => {
|
|||
expect(component.baz.nativeElement).toBe(spans[1]);
|
||||
});
|
||||
|
||||
describe('observable interface', () => {
|
||||
|
||||
it('should allow observing changes to query list', () => {
|
||||
const fixture = TestBed.createComponent(QueryCompWithChanges);
|
||||
let changes = 0;
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.foos.changes.subscribe((value: any) => {
|
||||
changes += 1;
|
||||
expect(value).toBe(fixture.componentInstance.foos);
|
||||
});
|
||||
|
||||
// refresh without setting dirty - no emit
|
||||
fixture.detectChanges();
|
||||
expect(changes).toBe(0);
|
||||
|
||||
// refresh with setting dirty - emit
|
||||
fixture.componentInstance.showing = true;
|
||||
fixture.detectChanges();
|
||||
expect(changes).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function initWithTemplate(compType: Type<any>, template: string) {
|
||||
|
@ -406,3 +461,15 @@ class SubclassStaticContentQueryComp extends StaticContentQueryComp {
|
|||
@ContentChild('baz', {static: false})
|
||||
baz !: ElementRef;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'query-with-changes',
|
||||
template: `
|
||||
<div *ngIf="showing" #foo></div>
|
||||
`
|
||||
})
|
||||
export class QueryCompWithChanges {
|
||||
@ViewChildren('foo') foos !: QueryList<any>;
|
||||
|
||||
showing = false;
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ describe('Query API', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
modifiedInIvy('Static ViewChild and ContentChild queries are resolved in update mode')
|
||||
modifiedInIvy('Static queries in Ivy require an explicit {static: true} arg')
|
||||
.it('should set static view and content children already after the constructor call', () => {
|
||||
const template =
|
||||
'<needs-static-content-view-child #q><div text="contentFoo"></div></needs-static-content-view-child>';
|
||||
|
|
|
@ -1026,7 +1026,7 @@ describe('content projection', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
/** @ViewChild(TemplateRef) template: TemplateRef<any> */
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(TemplateRef as any, true);
|
||||
viewQuery(TemplateRef as any, true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
|
|
@ -1011,7 +1011,7 @@ describe('host bindings', () => {
|
|||
},
|
||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo']);
|
||||
contentQuery(dirIndex, ['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
|
|
@ -382,7 +382,7 @@ describe('InheritDefinitionFeature', () => {
|
|||
selectors: [['super-comp']],
|
||||
viewQuery: <T>(rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['super'], false);
|
||||
viewQuery(['super'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -418,7 +418,7 @@ describe('InheritDefinitionFeature', () => {
|
|||
selectors: [['sub-comp']],
|
||||
viewQuery: (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['sub'], false);
|
||||
viewQuery(['sub'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -561,7 +561,7 @@ describe('InheritDefinitionFeature', () => {
|
|||
factory: () => new SuperDirective(),
|
||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], true);
|
||||
contentQuery(dirIndex, ['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -581,7 +581,7 @@ describe('InheritDefinitionFeature', () => {
|
|||
factory: () => dirInstance = new SubDirective(),
|
||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['bar'], true);
|
||||
contentQuery(dirIndex, ['bar'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
|
|
@ -56,7 +56,8 @@ describe('jit directive helper functions', () => {
|
|||
predicate: ['localRef'],
|
||||
descendants: false,
|
||||
first: false,
|
||||
read: null
|
||||
read: null,
|
||||
static: false
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -72,7 +73,8 @@ describe('jit directive helper functions', () => {
|
|||
predicate: ['foo', 'bar', 'baz'],
|
||||
descendants: true,
|
||||
first: true,
|
||||
read: null
|
||||
read: null,
|
||||
static: false
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -85,7 +87,8 @@ describe('jit directive helper functions', () => {
|
|||
descendants: true,
|
||||
first: true,
|
||||
isViewQuery: true,
|
||||
read: Directive
|
||||
read: Directive,
|
||||
static: false
|
||||
});
|
||||
|
||||
expect(converted.predicate).toEqual(Directive);
|
||||
|
|
|
@ -15,7 +15,7 @@ import {getNativeByIndex} from '../../src/render3/util';
|
|||
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, reference, template, text} from '../../src/render3/instructions';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
import {queryRefresh, viewQuery, loadViewQuery, contentQuery, loadContentQuery} from '../../src/render3/query';
|
||||
import {queryRefresh, viewQuery, loadViewQuery, contentQuery, loadContentQuery, query} from '../../src/render3/query';
|
||||
import {getLView} from '../../src/render3/state';
|
||||
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
|
||||
|
||||
|
@ -83,8 +83,8 @@ describe('query', () => {
|
|||
2, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(Child, false);
|
||||
viewQuery(Child, true);
|
||||
viewQuery(Child, false, null);
|
||||
viewQuery(Child, true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -261,9 +261,9 @@ describe('query', () => {
|
|||
},
|
||||
viewQuery: function(rf: RenderFlags, ctx: App) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(MyDirective, false);
|
||||
viewQuery(Service, false);
|
||||
viewQuery(Alias, false);
|
||||
viewQuery(MyDirective, false, null);
|
||||
viewQuery(Service, false, null);
|
||||
viewQuery(Alias, false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -347,7 +347,7 @@ describe('query', () => {
|
|||
3, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], false);
|
||||
viewQuery(['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -385,8 +385,8 @@ describe('query', () => {
|
|||
4, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], false);
|
||||
viewQuery(['bar'], false);
|
||||
viewQuery(['foo'], false, null);
|
||||
viewQuery(['bar'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -434,7 +434,7 @@ describe('query', () => {
|
|||
5, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo', 'bar'], undefined);
|
||||
viewQuery(['foo', 'bar'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -472,7 +472,7 @@ describe('query', () => {
|
|||
3, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], false);
|
||||
viewQuery(['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -545,7 +545,7 @@ describe('query', () => {
|
|||
2, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -746,7 +746,7 @@ describe('query', () => {
|
|||
2, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], undefined);
|
||||
viewQuery(['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -817,7 +817,7 @@ describe('query', () => {
|
|||
2, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -863,7 +863,7 @@ describe('query', () => {
|
|||
2, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -902,7 +902,7 @@ describe('query', () => {
|
|||
2, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -942,7 +942,7 @@ describe('query', () => {
|
|||
3, 0, [Child1, Child2], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo', 'bar'], true);
|
||||
viewQuery(['foo', 'bar'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -982,8 +982,8 @@ describe('query', () => {
|
|||
3, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['bar'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
viewQuery(['bar'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1026,7 +1026,7 @@ describe('query', () => {
|
|||
2, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], undefined, ElementRef);
|
||||
viewQuery(['foo'], false, ElementRef);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1065,7 +1065,7 @@ describe('query', () => {
|
|||
3, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo', 'bar'], undefined);
|
||||
viewQuery(['foo', 'bar'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1266,7 +1266,7 @@ describe('query', () => {
|
|||
1, 0, [Child], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(TemplateRef as any, false);
|
||||
viewQuery(TemplateRef as any, false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1315,7 +1315,7 @@ describe('query', () => {
|
|||
6, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(TemplateRef as any, false);
|
||||
viewQuery(TemplateRef as any, false, null);
|
||||
viewQuery(TemplateRef as any, false, ElementRef);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
|
@ -1401,7 +1401,7 @@ describe('query', () => {
|
|||
2, 1, [NgIf], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1463,7 +1463,7 @@ describe('query', () => {
|
|||
viewQuery: function(rf: RenderFlags, ctx: Cmpt) {
|
||||
let tmp: any;
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
queryRefresh(tmp = loadViewQuery<QueryList<any>>()) &&
|
||||
|
@ -1552,7 +1552,7 @@ describe('query', () => {
|
|||
8, 0, [ViewContainerManipulatorDirective], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1649,7 +1649,7 @@ describe('query', () => {
|
|||
viewQuery: (rf: RenderFlags, cmpt: Cmpt) => {
|
||||
let tmp: any;
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
queryRefresh(tmp = loadViewQuery<QueryList<any>>()) &&
|
||||
|
@ -1722,7 +1722,7 @@ describe('query', () => {
|
|||
viewQuery: (rf: RenderFlags, myApp: MyApp) => {
|
||||
let tmp: any;
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
queryRefresh(tmp = loadViewQuery<QueryList<any>>()) &&
|
||||
|
@ -1787,7 +1787,7 @@ describe('query', () => {
|
|||
1, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1853,7 +1853,7 @@ describe('query', () => {
|
|||
5, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -1930,7 +1930,7 @@ describe('query', () => {
|
|||
1, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2011,7 +2011,7 @@ describe('query', () => {
|
|||
1, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2081,8 +2081,8 @@ describe('query', () => {
|
|||
3, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], false);
|
||||
viewQuery(['foo'], true, null);
|
||||
viewQuery(['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2119,36 +2119,6 @@ describe('query', () => {
|
|||
|
||||
});
|
||||
|
||||
describe('observable interface', () => {
|
||||
|
||||
it('should allow observing changes to query list', () => {
|
||||
const queryList = new QueryList();
|
||||
let changes = 0;
|
||||
|
||||
queryList.changes.subscribe({
|
||||
next: (arg) => {
|
||||
changes += 1;
|
||||
expect(arg).toBe(queryList);
|
||||
}
|
||||
});
|
||||
|
||||
// initial refresh, the query should be dirty
|
||||
queryRefresh(queryList);
|
||||
expect(changes).toBe(1);
|
||||
|
||||
|
||||
// refresh without setting dirty - no emit
|
||||
queryRefresh(queryList);
|
||||
expect(changes).toBe(1);
|
||||
|
||||
// refresh with setting dirty - emit
|
||||
queryList.setDirty();
|
||||
queryRefresh(queryList);
|
||||
expect(changes).toBe(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('queryList', () => {
|
||||
it('should be destroyed when the containing view is destroyed', () => {
|
||||
let queryInstance: QueryList<any>;
|
||||
|
@ -2163,7 +2133,7 @@ describe('query', () => {
|
|||
2, 0, [], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], false);
|
||||
viewQuery(['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2244,7 +2214,7 @@ describe('query', () => {
|
|||
3, 0, [SomeDir], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2284,7 +2254,7 @@ describe('query', () => {
|
|||
factory: () => withContentInstance = new WithContentDirective(),
|
||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], true);
|
||||
contentQuery(dirIndex, ['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2307,7 +2277,7 @@ describe('query', () => {
|
|||
vars: 0,
|
||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], false);
|
||||
contentQuery(dirIndex, ['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2468,7 +2438,7 @@ describe('query', () => {
|
|||
5, 0, [WithContentDirective], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo', 'bar'], true);
|
||||
viewQuery(['foo', 'bar'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2509,7 +2479,7 @@ describe('query', () => {
|
|||
5, 0, [WithContentDirective], [],
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['bar'], true);
|
||||
viewQuery(['bar'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2535,7 +2505,7 @@ describe('query', () => {
|
|||
// @ContentChildren('foo, bar, baz', {descendants: true})
|
||||
// fooBars: QueryList<ElementRef>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo', 'bar', 'baz'], true);
|
||||
contentQuery(dirIndex, ['foo', 'bar', 'baz'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2599,7 +2569,7 @@ describe('query', () => {
|
|||
// @ContentChildren('foo', {descendants: true})
|
||||
// fooBars: QueryList<ElementRef>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], false);
|
||||
contentQuery(dirIndex, ['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2655,7 +2625,7 @@ describe('query', () => {
|
|||
// @ContentChildren('foo', {descendants: true})
|
||||
// fooBars: QueryList<ElementRef>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], false);
|
||||
contentQuery(dirIndex, ['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2715,7 +2685,7 @@ describe('query', () => {
|
|||
// @ContentChildren('foo', {descendants: false})
|
||||
// foos: QueryList<ElementRef>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], false);
|
||||
contentQuery(dirIndex, ['foo'], false, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2736,7 +2706,7 @@ describe('query', () => {
|
|||
// @ContentChildren('foo', {descendants: true})
|
||||
// foos: QueryList<ElementRef>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, ['foo'], true);
|
||||
contentQuery(dirIndex, ['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2812,7 +2782,7 @@ describe('query', () => {
|
|||
// @ContentChildren(TextDirective, {descendants: true})
|
||||
// texts: QueryList<TextDirective>;
|
||||
if (rf & RenderFlags.Create) {
|
||||
contentQuery(dirIndex, TextDirective, true);
|
||||
contentQuery(dirIndex, TextDirective, true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
@ -2892,7 +2862,7 @@ describe('query', () => {
|
|||
viewQuery: function(rf: RenderFlags, ctx: ViewQueryComponent) {
|
||||
let tmp: any;
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(TextDirective, true);
|
||||
viewQuery(TextDirective, true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
queryRefresh(tmp = loadViewQuery<QueryList<TextDirective>>()) &&
|
||||
|
|
|
@ -286,7 +286,7 @@ class SuperComp {
|
|||
},
|
||||
viewQuery: function(rf: RenderFlags, ctx: SuperComp) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['child'], true);
|
||||
viewQuery(['child'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
|
|
@ -2070,7 +2070,7 @@ describe('ViewContainerRef', () => {
|
|||
},
|
||||
viewQuery: function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
viewQuery(['foo'], true);
|
||||
viewQuery(['foo'], true, null);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
let tmp: any;
|
||||
|
|
Loading…
Reference in New Issue