From a4638d5a816bc1fd47fd22734e5b7c70fb1dcc07 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Mon, 18 Feb 2019 17:33:59 -0800 Subject: [PATCH] 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 --- integration/_payload-limits.json | 2 +- .../src/ngtsc/annotations/src/directive.ts | 20 ++- .../compliance/r3_compiler_compliance_spec.ts | 77 +++++++++- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 14 +- .../compiler/src/compiler_facade_interface.ts | 1 + packages/compiler/src/jit_compiler_facade.ts | 1 + .../compiler/src/render3/r3_identifiers.ts | 1 + packages/compiler/src/render3/view/api.ts | 15 ++ .../compiler/src/render3/view/compiler.ts | 9 +- .../src/compiler/compiler_facade_interface.ts | 1 + .../core/src/core_render3_private_export.ts | 1 + packages/core/src/render3/index.ts | 1 + packages/core/src/render3/instructions.ts | 14 +- packages/core/src/render3/interfaces/view.ts | 8 + packages/core/src/render3/jit/directive.ts | 3 +- packages/core/src/render3/jit/environment.ts | 1 + packages/core/src/render3/query.ts | 44 ++++-- packages/core/test/acceptance/query_spec.ts | 139 +++++++++++++----- .../test/linker/query_integration_spec.ts | 2 +- packages/core/test/render3/content_spec.ts | 2 +- .../core/test/render3/host_binding_spec.ts | 2 +- .../inherit_definition_feature_spec.ts | 8 +- .../core/test/render3/jit/directive_spec.ts | 9 +- packages/core/test/render3/query_spec.ts | 124 ++++++---------- .../core/test/render3/styling/players_spec.ts | 2 +- .../test/render3/view_container_ref_spec.ts | 2 +- 26 files changed, 340 insertions(+), 163 deletions(-) diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index b93f10069f..62088d7ca7 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 12885, + "main": 13019, "polyfills": 38390 } } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index 4889294ac1..c87c47c560 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -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, }; } diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts index 497d59d143..b28c67b354 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -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: \` +
+ \` + }) + 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$; diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 41f8515b79..29cd9329e4 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -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)); }); diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index ad281c618e..10315fc72c 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -150,6 +150,7 @@ export interface R3QueryMetadataFacade { predicate: any|string[]; descendants: boolean; read: any|null; + static: boolean; } export interface ParseSourceSpan { diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 9d36aa3098..eeff934a04 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -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 }; } diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 2b156e1354..40e7ee30c7 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -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}; diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index afe470a482..d82cc05540 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -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; } /** diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index a79cb4186a..25ec289b01 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -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)); diff --git a/packages/core/src/compiler/compiler_facade_interface.ts b/packages/core/src/compiler/compiler_facade_interface.ts index a5f1802c2e..a5a209845b 100644 --- a/packages/core/src/compiler/compiler_facade_interface.ts +++ b/packages/core/src/compiler/compiler_facade_interface.ts @@ -150,6 +150,7 @@ export interface R3QueryMetadataFacade { predicate: any|string[]; descendants: boolean; read: any|null; + static: boolean; } export interface ParseSourceSpan { diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index f13b2b91da..fd88d0ba06 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -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, diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 447538a3b3..e525473d46 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -124,6 +124,7 @@ export { export { queryRefresh, viewQuery, + staticViewQuery, loadViewQuery, contentQuery, loadContentQuery, diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 2cede59d00..1a350e7469 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -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(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(lView: LView, tView: TView, component: T): void { +function executeViewQueryFn(flags: RenderFlags, tView: TView, component: T): void { const viewQuery = tView.viewQuery; if (viewQuery) { setCurrentQueryIndex(tView.viewQueryStartIndex); - viewQuery(getRenderFlags(lView), component); + viewQuery(flags, component); } } diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 500984ab4d..51c35ee782 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -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. diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 81c785c328..d04debf859 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -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( diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 81b440d3c2..f48e1f779b 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -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, diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index 59e305e41c..e13cc22692 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -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( }; } -type QueryList_ = QueryList& {_valuesTree: any[]}; +type QueryList_ = QueryList& {_valuesTree: any[], _static: boolean}; /** * Creates and returns a QueryList. @@ -350,12 +350,13 @@ type QueryList_ = QueryList& {_valuesTree: any[]}; */ export function query( // TODO: "read" should be an AbstractType (FW-486) - predicate: Type| string[], descend?: boolean, read?: any): QueryList { + predicate: Type| string[], descend: boolean, read: any): QueryList { ngDevMode && assertPreviousIsParent(getIsParent()); const lView = getLView(); - const queryList = new QueryList(); + const queryList = new QueryList() as QueryList_; const queries = lView[QUERIES] || (lView[QUERIES] = new LQueries_(null, null, null)); - (queryList as QueryList_)._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( */ export function queryRefresh(queryList: QueryList): boolean { const queryListImpl = (queryList as any as QueryList_); - 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): 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( + // TODO(FW-486): "read" should be an AbstractType + predicate: Type| string[], descend: boolean, read: any): void { + const queryList = viewQuery(predicate, descend, read) as QueryList_; + 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): boolean { * @returns QueryList */ export function viewQuery( - // TODO: "read" should be an AbstractType (FW-486) - predicate: Type| string[], descend?: boolean, read?: any): QueryList { + // TODO(FW-486): "read" should be an AbstractType + predicate: Type| string[], descend: boolean, read: any): QueryList { const lView = getLView(); const tView = lView[TVIEW]; if (tView.firstTemplatePass) { @@ -419,9 +441,9 @@ export function loadViewQuery(): T { * @returns QueryList */ export function contentQuery( - directiveIndex: number, predicate: Type| string[], descend?: boolean, + directiveIndex: number, predicate: Type| string[], descend: boolean, // TODO: "read" should be an AbstractType (FW-486) - read?: any): QueryList { + read: any): QueryList { const lView = getLView(); const tView = lView[TVIEW]; const contentQuery: QueryList = query(predicate, descend, read); @@ -448,4 +470,4 @@ export function loadContentQuery(): QueryList { setCurrentQueryIndex(index + 1); return lView[CONTENT_QUERIES] ![index]; -} \ No newline at end of file +} diff --git a/packages/core/test/acceptance/query_spec.ts b/packages/core/test/acceptance/query_spec.ts index 162948c9ca..58633ed3ab 100644 --- a/packages/core/test/acceptance/query_spec.ts +++ b/packages/core/test/acceptance/query_spec.ts @@ -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 = ` + + + `; + 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, template: string) { @@ -406,3 +461,15 @@ class SubclassStaticContentQueryComp extends StaticContentQueryComp { @ContentChild('baz', {static: false}) baz !: ElementRef; } + +@Component({ + selector: 'query-with-changes', + template: ` +
+ ` +}) +export class QueryCompWithChanges { + @ViewChildren('foo') foos !: QueryList; + + showing = false; +} diff --git a/packages/core/test/linker/query_integration_spec.ts b/packages/core/test/linker/query_integration_spec.ts index e93faa1139..a4f11a21b7 100644 --- a/packages/core/test/linker/query_integration_spec.ts +++ b/packages/core/test/linker/query_integration_spec.ts @@ -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 = '
'; diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts index a4d82b307c..235a932d0e 100644 --- a/packages/core/test/render3/content_spec.ts +++ b/packages/core/test/render3/content_spec.ts @@ -1026,7 +1026,7 @@ describe('content projection', () => { function(rf: RenderFlags, ctx: any) { /** @ViewChild(TemplateRef) template: TemplateRef */ if (rf & RenderFlags.Create) { - viewQuery(TemplateRef as any, true); + viewQuery(TemplateRef as any, true, null); } if (rf & RenderFlags.Update) { let tmp: any; diff --git a/packages/core/test/render3/host_binding_spec.ts b/packages/core/test/render3/host_binding_spec.ts index 2185df3317..a1af92fe26 100644 --- a/packages/core/test/render3/host_binding_spec.ts +++ b/packages/core/test/render3/host_binding_spec.ts @@ -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; diff --git a/packages/core/test/render3/inherit_definition_feature_spec.ts b/packages/core/test/render3/inherit_definition_feature_spec.ts index 7fa9769039..1ec9214fbd 100644 --- a/packages/core/test/render3/inherit_definition_feature_spec.ts +++ b/packages/core/test/render3/inherit_definition_feature_spec.ts @@ -382,7 +382,7 @@ describe('InheritDefinitionFeature', () => { selectors: [['super-comp']], viewQuery: (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; diff --git a/packages/core/test/render3/jit/directive_spec.ts b/packages/core/test/render3/jit/directive_spec.ts index d0e4e9c6c5..46f13a1969 100644 --- a/packages/core/test/render3/jit/directive_spec.ts +++ b/packages/core/test/render3/jit/directive_spec.ts @@ -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); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index 8f769b4b3f..637ec8cf66 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -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>()) && @@ -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>()) && @@ -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>()) && @@ -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; @@ -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; 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; 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; 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; 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; 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; 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>()) && diff --git a/packages/core/test/render3/styling/players_spec.ts b/packages/core/test/render3/styling/players_spec.ts index 2f77e83943..15bb9cc68a 100644 --- a/packages/core/test/render3/styling/players_spec.ts +++ b/packages/core/test/render3/styling/players_spec.ts @@ -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; diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index c3ad8f260c..03b87d8f37 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -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;