Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/compiler/src/compile_metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export interface CompileQueryMetadata {
first: boolean;
propertyName: string;
read: CompileTokenMetadata;
static?: boolean;
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/compiler/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface Query {
read: any;
isViewQuery: boolean;
selector: any;
static?: boolean;
}

export const createContentChildren = makeMetadataFactory<Query>(
Expand Down
3 changes: 2 additions & 1 deletion packages/compiler/src/metadata_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,8 @@ export class CompileMetadataResolver {
selectors,
first: q.first,
descendants: q.descendants, propertyName,
read: q.read ? this._getTokenMetadata(q.read) : null !
read: q.read ? this._getTokenMetadata(q.read) : null !,
static: q.static
};
}

Expand Down
20 changes: 15 additions & 5 deletions packages/compiler/src/view_compiler/view_compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {CompileDirectiveMetadata, CompilePipeSummary, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
import {CompileDirectiveMetadata, CompilePipeSummary, CompileQueryMetadata, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata';
import {CompileReflector} from '../compile_reflector';
import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core';
Expand Down Expand Up @@ -145,7 +145,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
const queryId = queryIndex + 1;
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
const flags =
NodeFlags.TypeViewQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
NodeFlags.TypeViewQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query);
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: flags,
Expand Down Expand Up @@ -493,7 +493,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
dirAst.directive.queries.forEach((query, queryIndex) => {
const queryId = dirAst.contentQueryStartId + queryIndex;
const flags =
NodeFlags.TypeContentQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
NodeFlags.TypeContentQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query);
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan,
Expand Down Expand Up @@ -1081,18 +1081,28 @@ function elementEventNameAndTarget(
}

function calcStaticDynamicQueryFlags(
queryIds: StaticAndDynamicQueryIds, queryId: number, isFirst: boolean) {
queryIds: StaticAndDynamicQueryIds, queryId: number, query: CompileQueryMetadata) {
let flags = NodeFlags.None;
// Note: We only make queries static that query for a single item.
// This is because of backwards compatibility with the old view compiler...
if (isFirst && (queryIds.staticQueryIds.has(queryId) || !queryIds.dynamicQueryIds.has(queryId))) {
if (query.first && shouldResolveAsStaticQuery(queryIds, queryId, query)) {
flags |= NodeFlags.StaticQuery;
} else {
flags |= NodeFlags.DynamicQuery;
}
return flags;
}

function shouldResolveAsStaticQuery(
queryIds: StaticAndDynamicQueryIds, queryId: number, query: CompileQueryMetadata): boolean {
// If query.static has been set by the user, use that value to determine whether
// the query is static. If none has been set, sort the query into static/dynamic
// based on query results (i.e. dynamic if CD needs to run to get all results).
return query.static ||
query.static == null &&
(queryIds.staticQueryIds.has(queryId) || !queryIds.dynamicQueryIds.has(queryId));
}

export function elementEventFullName(target: string | null, name: string): string {
return target ? `${target}:${name}` : name;
}
21 changes: 17 additions & 4 deletions packages/core/src/metadata/di.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export interface Query {
read: any;
isViewQuery: boolean;
selector: any;
static?: boolean;
}

/**
Expand Down Expand Up @@ -199,6 +200,12 @@ export interface ContentChildDecorator {
*
* * **selector** - the directive type or the name used for querying.
* * **read** - read a different token from the queried element.
* * **static** - whether or not to resolve query results before change detection runs (i.e.
* return static results only). If this option is not provided, the compiler will fall back
* to its default behavior, which is to use query results to determine the timing of query
* resolution. If any query results are inside a nested view (e.g. *ngIf), the query will be
* resolved after change detection runs. Otherwise, it will be resolved before change detection
* runs.
*
* @usageNotes
* ### Example
Expand All @@ -211,8 +218,8 @@ export interface ContentChildDecorator {
*
* @Annotation
*/
(selector: Type<any>|Function|string, opts?: {read?: any}): any;
new (selector: Type<any>|Function|string, opts?: {read?: any}): ContentChild;
(selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): any;
new (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ContentChild;
}

/**
Expand Down Expand Up @@ -311,6 +318,12 @@ export interface ViewChildDecorator {
*
* * **selector** - the directive type or the name used for querying.
* * **read** - read a different token from the queried elements.
* * **static** - whether or not to resolve query results before change detection runs (i.e.
* return static results only). If this option is not provided, the compiler will fall back
* to its default behavior, which is to use query results to determine the timing of query
* resolution. If any query results are inside a nested view (e.g. *ngIf), the query will be
* resolved after change detection runs. Otherwise, it will be resolved before change detection
* runs.
*
* Supported selectors include:
* * any class with the `@Component` or `@Directive` decorator
Expand All @@ -337,8 +350,8 @@ export interface ViewChildDecorator {
*
* @Annotation
*/
(selector: Type<any>|Function|string, opts?: {read?: any}): any;
new (selector: Type<any>|Function|string, opts?: {read?: any}): ViewChild;
(selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): any;
new (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ViewChild;
}

/**
Expand Down
Loading