fix(core): `QueryList` should not fire changes if the underlying list did not change. (#40091)
Previous implementation would fire changes `QueryList.changes.subscribe` whenever the `QueryList` was recomputed. This resulted in artificially high number of change notifications, as it is possible that recomputing `QueryList` results in the same list. When the `QueryList` gets recomputed is an implementation detail and it should not be the thing which determines how often change event should fire. This change introduces a new `emitDistinctChangesOnly` option for `ContentChildren` and `ViewChildren`. ``` export class QueryCompWithStrictChangeEmitParent { @ContentChildren('foo', { // This option will become the default in the future emitDistinctChangesOnly: true, }) foos!: QueryList<any>; } ``` PR Close #40091
This commit is contained in:
parent
cf02cf1e18
commit
e32b6256ce
|
@ -174,10 +174,12 @@ export declare type ContentChildren = Query;
|
||||||
export declare interface ContentChildrenDecorator {
|
export declare interface ContentChildrenDecorator {
|
||||||
(selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
(selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
||||||
descendants?: boolean;
|
descendants?: boolean;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
read?: any;
|
read?: any;
|
||||||
}): any;
|
}): any;
|
||||||
new (selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
new (selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
||||||
descendants?: boolean;
|
descendants?: boolean;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
read?: any;
|
read?: any;
|
||||||
}): Query;
|
}): Query;
|
||||||
}
|
}
|
||||||
|
@ -734,6 +736,7 @@ export declare type Provider = TypeProvider | ValueProvider | ClassProvider | Co
|
||||||
|
|
||||||
export declare interface Query {
|
export declare interface Query {
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
|
emitDistinctChangesOnly: boolean;
|
||||||
first: boolean;
|
first: boolean;
|
||||||
isViewQuery: boolean;
|
isViewQuery: boolean;
|
||||||
read: any;
|
read: any;
|
||||||
|
@ -746,12 +749,12 @@ export declare abstract class Query {
|
||||||
|
|
||||||
export declare class QueryList<T> implements Iterable<T> {
|
export declare class QueryList<T> implements Iterable<T> {
|
||||||
[Symbol.iterator]: () => Iterator<T>;
|
[Symbol.iterator]: () => Iterator<T>;
|
||||||
readonly changes: Observable<any>;
|
get changes(): Observable<any>;
|
||||||
readonly dirty = true;
|
readonly dirty = true;
|
||||||
readonly first: T;
|
readonly first: T;
|
||||||
readonly last: T;
|
readonly last: T;
|
||||||
readonly length: number;
|
readonly length: number;
|
||||||
constructor();
|
constructor(_emitDistinctChangesOnly?: boolean);
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
filter(fn: (item: T, index: number, array: T[]) => boolean): T[];
|
filter(fn: (item: T, index: number, array: T[]) => boolean): T[];
|
||||||
find(fn: (item: T, index: number, array: T[]) => boolean): T | undefined;
|
find(fn: (item: T, index: number, array: T[]) => boolean): T | undefined;
|
||||||
|
@ -760,7 +763,7 @@ export declare class QueryList<T> implements Iterable<T> {
|
||||||
map<U>(fn: (item: T, index: number, array: T[]) => U): U[];
|
map<U>(fn: (item: T, index: number, array: T[]) => U): U[];
|
||||||
notifyOnChanges(): void;
|
notifyOnChanges(): void;
|
||||||
reduce<U>(fn: (prevValue: U, curValue: T, curIndex: number, array: T[]) => U, init: U): U;
|
reduce<U>(fn: (prevValue: U, curValue: T, curIndex: number, array: T[]) => U, init: U): U;
|
||||||
reset(resultsTree: Array<T | any[]>): void;
|
reset(resultsTree: Array<T | any[]>, identityAccessor?: (value: T) => unknown): void;
|
||||||
setDirty(): void;
|
setDirty(): void;
|
||||||
some(fn: (value: T, index: number, array: T[]) => boolean): boolean;
|
some(fn: (value: T, index: number, array: T[]) => boolean): boolean;
|
||||||
toArray(): T[];
|
toArray(): T[];
|
||||||
|
@ -1010,9 +1013,11 @@ export declare type ViewChildren = Query;
|
||||||
export declare interface ViewChildrenDecorator {
|
export declare interface ViewChildrenDecorator {
|
||||||
(selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
(selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
||||||
read?: any;
|
read?: any;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
}): any;
|
}): any;
|
||||||
new (selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
new (selector: Type<any> | InjectionToken<unknown> | Function | string, opts?: {
|
||||||
read?: any;
|
read?: any;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
}): ViewChildren;
|
}): ViewChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3033,
|
"runtime-es2015": 3033,
|
||||||
"main-es2015": 447349,
|
"main-es2015": 448090,
|
||||||
"polyfills-es2015": 52493
|
"polyfills-es2015": 52493
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3153,
|
"runtime-es2015": 3153,
|
||||||
"main-es2015": 431137,
|
"main-es2015": 432078,
|
||||||
"polyfills-es2015": 52493
|
"polyfills-es2015": 52493
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 2285,
|
"runtime-es2015": 2285,
|
||||||
"main-es2015": 240909,
|
"main-es2015": 241738,
|
||||||
"polyfills-es2015": 36709,
|
"polyfills-es2015": 36709,
|
||||||
"5-es2015": 745
|
"5-es2015": 745
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,8 @@ function toQueryMetadata<TExpression>(obj: AstObject<R3DeclareQueryMetadata, TEx
|
||||||
first: obj.has('first') ? obj.getBoolean('first') : false,
|
first: obj.has('first') ? obj.getBoolean('first') : false,
|
||||||
predicate,
|
predicate,
|
||||||
descendants: obj.has('descendants') ? obj.getBoolean('descendants') : false,
|
descendants: obj.has('descendants') ? obj.getBoolean('descendants') : false,
|
||||||
|
emitDistinctChangesOnly:
|
||||||
|
obj.has('emitDistinctChangesOnly') ? obj.getBoolean('emitDistinctChangesOnly') : true,
|
||||||
read: obj.has('read') ? obj.getOpaque('read') : null,
|
read: obj.has('read') ? obj.getOpaque('read') : null,
|
||||||
static: obj.has('static') ? obj.getBoolean('static') : false,
|
static: obj.has('static') ? obj.getBoolean('static') : false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {compileDeclareDirectiveFromMetadata, compileDirectiveFromMetadata, ConstantPool, Expression, ExternalExpr, getSafePropertyAccessString, Identifiers, makeBindingParser, ParsedHostBindings, ParseError, parseHostBindings, R3DependencyMetadata, R3DirectiveDef, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, R3ResolvedDependencyType, Statement, verifyHostBindings, WrappedNodeExpr} from '@angular/compiler';
|
import {compileDeclareDirectiveFromMetadata, compileDirectiveFromMetadata, ConstantPool, Expression, ExternalExpr, getSafePropertyAccessString, Identifiers, makeBindingParser, ParsedHostBindings, ParseError, parseHostBindings, R3DependencyMetadata, R3DirectiveDef, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, R3ResolvedDependencyType, Statement, verifyHostBindings, WrappedNodeExpr} from '@angular/compiler';
|
||||||
|
import {emitDistinctChangesOnlyDefaultValue} from '@angular/compiler/src/core';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
|
@ -436,6 +437,7 @@ export function extractQueryMetadata(
|
||||||
let read: Expression|null = null;
|
let read: Expression|null = null;
|
||||||
// The default value for descendants is true for every decorator except @ContentChildren.
|
// The default value for descendants is true for every decorator except @ContentChildren.
|
||||||
let descendants: boolean = name !== 'ContentChildren';
|
let descendants: boolean = name !== 'ContentChildren';
|
||||||
|
let emitDistinctChangesOnly: boolean = emitDistinctChangesOnlyDefaultValue;
|
||||||
if (args.length === 2) {
|
if (args.length === 2) {
|
||||||
const optionsExpr = unwrapExpression(args[1]);
|
const optionsExpr = unwrapExpression(args[1]);
|
||||||
if (!ts.isObjectLiteralExpression(optionsExpr)) {
|
if (!ts.isObjectLiteralExpression(optionsExpr)) {
|
||||||
|
@ -458,6 +460,17 @@ export function extractQueryMetadata(
|
||||||
descendants = descendantsValue;
|
descendants = descendantsValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.has('emitDistinctChangesOnly')) {
|
||||||
|
const emitDistinctChangesOnlyExpr = options.get('emitDistinctChangesOnly')!;
|
||||||
|
const emitDistinctChangesOnlyValue = evaluator.evaluate(emitDistinctChangesOnlyExpr);
|
||||||
|
if (typeof emitDistinctChangesOnlyValue !== 'boolean') {
|
||||||
|
throw createValueHasWrongTypeError(
|
||||||
|
emitDistinctChangesOnlyExpr, emitDistinctChangesOnlyValue,
|
||||||
|
`@${name} options.emitDistinctChangesOnlys must be a boolean`);
|
||||||
|
}
|
||||||
|
emitDistinctChangesOnly = emitDistinctChangesOnlyValue;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.has('static')) {
|
if (options.has('static')) {
|
||||||
const staticValue = evaluator.evaluate(options.get('static')!);
|
const staticValue = evaluator.evaluate(options.get('static')!);
|
||||||
if (typeof staticValue !== 'boolean') {
|
if (typeof staticValue !== 'boolean') {
|
||||||
|
@ -480,6 +493,7 @@ export function extractQueryMetadata(
|
||||||
descendants,
|
descendants,
|
||||||
read,
|
read,
|
||||||
static: isStatic,
|
static: isStatic,
|
||||||
|
emitDistinctChangesOnly,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
}
|
}
|
||||||
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
||||||
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true }, { propertyName: "someDirs", predicate: SomeDirective, descendants: true }], ngImport: i0, template: `
|
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
|
||||||
<div someDir></div>
|
<div someDir></div>
|
||||||
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
|
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
|
||||||
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
|
||||||
|
@ -86,7 +86,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
}
|
}
|
||||||
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
||||||
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], descendants: true }], ngImport: i0, template: `
|
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
`, isInline: true });
|
`, isInline: true });
|
||||||
|
@ -166,7 +166,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
}
|
}
|
||||||
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
||||||
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], descendants: true }], ngImport: i0, template: `
|
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
|
||||||
<div someDir></div>
|
<div someDir></div>
|
||||||
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
|
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
|
||||||
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
|
||||||
|
@ -246,7 +246,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ViewQueryComponent {
|
export class ViewQueryComponent {
|
||||||
}
|
}
|
||||||
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
|
||||||
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], descendants: true, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, descendants: true, read: TemplateRef }], ngImport: i0, template: `
|
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }], ngImport: i0, template: `
|
||||||
<div someDir></div>
|
<div someDir></div>
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
|
@ -336,7 +336,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
}
|
}
|
||||||
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
||||||
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true }, { propertyName: "someDirList", predicate: SomeDirective }], ngImport: i0, template: `
|
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }, { propertyName: "someDirList", predicate: SomeDirective, emitDistinctChangesOnly: false }], ngImport: i0, template: `
|
||||||
<div><ng-content></ng-content></div>
|
<div><ng-content></ng-content></div>
|
||||||
`, isInline: true });
|
`, isInline: true });
|
||||||
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
|
||||||
|
@ -413,7 +413,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
}
|
}
|
||||||
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
||||||
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"] }], ngImport: i0, template: `
|
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false }], ngImport: i0, template: `
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
`, isInline: true });
|
`, isInline: true });
|
||||||
|
@ -493,7 +493,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
}
|
}
|
||||||
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
||||||
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], descendants: true }], ngImport: i0, template: `
|
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
|
||||||
<div><ng-content></ng-content></div>
|
<div><ng-content></ng-content></div>
|
||||||
`, isInline: true });
|
`, isInline: true });
|
||||||
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
|
||||||
|
@ -596,7 +596,7 @@ import * as i0 from "@angular/core";
|
||||||
export class ContentQueryComponent {
|
export class ContentQueryComponent {
|
||||||
}
|
}
|
||||||
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
||||||
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, read: TemplateRef }], ngImport: i0, template: `
|
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, read: TemplateRef }], ngImport: i0, template: `
|
||||||
<div someDir></div>
|
<div someDir></div>
|
||||||
<div #myRef></div>
|
<div #myRef></div>
|
||||||
<div #myRef1></div>
|
<div #myRef1></div>
|
||||||
|
@ -652,3 +652,91 @@ export declare class MyModule {
|
||||||
static ɵinj: i0.ɵɵInjectorDef<MyModule>;
|
static ɵinj: i0.ɵɵInjectorDef<MyModule>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************************
|
||||||
|
* PARTIAL FILE: some.directive.js
|
||||||
|
****************************************************************************************************/
|
||||||
|
import { Directive } from '@angular/core';
|
||||||
|
import * as i0 from "@angular/core";
|
||||||
|
export class SomeDirective {
|
||||||
|
}
|
||||||
|
SomeDirective.ɵfac = function SomeDirective_Factory(t) { return new (t || SomeDirective)(); };
|
||||||
|
SomeDirective.ɵdir = i0.ɵɵngDeclareDirective({ version: "0.0.0-PLACEHOLDER", type: SomeDirective, selector: "[someDir]", ngImport: i0 });
|
||||||
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SomeDirective, [{
|
||||||
|
type: Directive,
|
||||||
|
args: [{
|
||||||
|
selector: '[someDir]',
|
||||||
|
}]
|
||||||
|
}], null, null); })();
|
||||||
|
|
||||||
|
/****************************************************************************************************
|
||||||
|
* PARTIAL FILE: some.directive.d.ts
|
||||||
|
****************************************************************************************************/
|
||||||
|
import * as i0 from "@angular/core";
|
||||||
|
export declare class SomeDirective {
|
||||||
|
static ɵfac: i0.ɵɵFactoryDef<SomeDirective, never>;
|
||||||
|
static ɵdir: i0.ɵɵDirectiveDefWithMeta<SomeDirective, "[someDir]", never, {}, {}, never>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************************
|
||||||
|
* PARTIAL FILE: query_with_emit_distinct_changes_only.js
|
||||||
|
****************************************************************************************************/
|
||||||
|
import { Component, ContentChildren, NgModule, ViewChildren } from '@angular/core';
|
||||||
|
import { SomeDirective } from './some.directive';
|
||||||
|
import * as i0 from "@angular/core";
|
||||||
|
export class ContentQueryComponent {
|
||||||
|
}
|
||||||
|
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
|
||||||
|
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRefs", predicate: ["myRef"] }, { propertyName: "oldMyRefs", predicate: ["myRef"], emitDistinctChangesOnly: false }], viewQueries: [{ propertyName: "someDirs", predicate: SomeDirective, descendants: true }, { propertyName: "oldSomeDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
|
||||||
|
<div someDir></div>
|
||||||
|
<div #myRef></div>
|
||||||
|
`, isInline: true });
|
||||||
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
|
||||||
|
type: Component,
|
||||||
|
args: [{
|
||||||
|
selector: 'content-query-component',
|
||||||
|
template: `
|
||||||
|
<div someDir></div>
|
||||||
|
<div #myRef></div>
|
||||||
|
`
|
||||||
|
}]
|
||||||
|
}], null, { myRefs: [{
|
||||||
|
type: ContentChildren,
|
||||||
|
args: ['myRef', { emitDistinctChangesOnly: true }]
|
||||||
|
}], oldMyRefs: [{
|
||||||
|
type: ContentChildren,
|
||||||
|
args: ['myRef', { emitDistinctChangesOnly: false }]
|
||||||
|
}], someDirs: [{
|
||||||
|
type: ViewChildren,
|
||||||
|
args: [SomeDirective, { emitDistinctChangesOnly: true }]
|
||||||
|
}], oldSomeDirs: [{
|
||||||
|
type: ViewChildren,
|
||||||
|
args: [SomeDirective, { emitDistinctChangesOnly: false }]
|
||||||
|
}] }); })();
|
||||||
|
export class MyModule {
|
||||||
|
}
|
||||||
|
MyModule.ɵmod = i0.ɵɵdefineNgModule({ type: MyModule });
|
||||||
|
MyModule.ɵinj = i0.ɵɵdefineInjector({ factory: function MyModule_Factory(t) { return new (t || MyModule)(); } });
|
||||||
|
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MyModule, { declarations: [ContentQueryComponent] }); })();
|
||||||
|
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyModule, [{
|
||||||
|
type: NgModule,
|
||||||
|
args: [{ declarations: [ContentQueryComponent] }]
|
||||||
|
}], null, null); })();
|
||||||
|
|
||||||
|
/****************************************************************************************************
|
||||||
|
* PARTIAL FILE: query_with_emit_distinct_changes_only.d.ts
|
||||||
|
****************************************************************************************************/
|
||||||
|
import { ElementRef, QueryList } from '@angular/core';
|
||||||
|
import * as i0 from "@angular/core";
|
||||||
|
export declare class ContentQueryComponent {
|
||||||
|
myRefs: QueryList<ElementRef>;
|
||||||
|
oldMyRefs: QueryList<ElementRef>;
|
||||||
|
someDirs: QueryList<any>;
|
||||||
|
oldSomeDirs: QueryList<any>;
|
||||||
|
static ɵfac: i0.ɵɵFactoryDef<ContentQueryComponent, never>;
|
||||||
|
static ɵcmp: i0.ɵɵComponentDefWithMeta<ContentQueryComponent, "content-query-component", never, {}, {}, ["myRefs", "oldMyRefs"], never>;
|
||||||
|
}
|
||||||
|
export declare class MyModule {
|
||||||
|
static ɵmod: i0.ɵɵNgModuleDefWithMeta<MyModule, [typeof ContentQueryComponent], never, never>;
|
||||||
|
static ɵinj: i0.ɵɵInjectorDef<MyModule>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,21 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "should support query emitDistinctChangesOnly flag",
|
||||||
|
"inputFiles": [
|
||||||
|
"some.directive.ts",
|
||||||
|
"query_with_emit_distinct_changes_only.ts"
|
||||||
|
],
|
||||||
|
"expectations": [
|
||||||
|
{
|
||||||
|
"failureMessage": "Invalid ContentQuery declaration",
|
||||||
|
"files": [
|
||||||
|
"query_with_emit_distinct_changes_only.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ ContentQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
selectors: [["content-query-component"]],
|
selectors: [["content-query-component"]],
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, true);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -5,8 +5,8 @@ ContentQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
// ...
|
// ...
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true);
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, false);
|
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -5,10 +5,10 @@ ContentQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
// ...
|
// ...
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true, TemplateRef);
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1, TemplateRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, true, ElementRef);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1, ElementRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, false, ElementRef);
|
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0, ElementRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false, TemplateRef);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
const $e0_attrs$ = ["myRef"];
|
||||||
|
// ...
|
||||||
|
ContentQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
|
// ...
|
||||||
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, __QueryFlags.emitDistinctChangesOnly__);
|
||||||
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, __QueryFlags.none__);
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
let $tmp$;
|
||||||
|
$r3$.ɵɵqueryRefresh($tmp$ = $r3$.ɵɵloadQuery()) && (ctx.myRefs = $tmp$);
|
||||||
|
$r3$.ɵɵqueryRefresh($tmp$ = $r3$.ɵɵloadQuery()) && (ctx.oldMyRefs = $tmp$);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ...
|
||||||
|
viewQuery: function ContentQueryComponent_Query(rf, ctx) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵɵviewQuery(SomeDirective, __QueryFlags.emitDistinctChangesOnly__|__QueryFlags.descendants__);
|
||||||
|
$r3$.ɵɵviewQuery(SomeDirective, __QueryFlags.descendants__);
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
let $tmp$;
|
||||||
|
$r3$.ɵɵqueryRefresh($tmp$ = $r3$.ɵɵloadQuery()) && (ctx.someDirs = $tmp$);
|
||||||
|
$r3$.ɵɵqueryRefresh($tmp$ = $r3$.ɵɵloadQuery()) && (ctx.oldSomeDirs = $tmp$);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//...
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {Component, ContentChildren, ElementRef, NgModule, QueryList, TemplateRef, ViewChildren} from '@angular/core';
|
||||||
|
|
||||||
|
import {SomeDirective} from './some.directive';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'content-query-component',
|
||||||
|
template: `
|
||||||
|
<div someDir></div>
|
||||||
|
<div #myRef></div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class ContentQueryComponent {
|
||||||
|
@ContentChildren('myRef', {emitDistinctChangesOnly: true}) myRefs!: QueryList<ElementRef>;
|
||||||
|
@ContentChildren('myRef', {emitDistinctChangesOnly: false}) oldMyRefs!: QueryList<ElementRef>;
|
||||||
|
|
||||||
|
@ViewChildren(SomeDirective, {emitDistinctChangesOnly: true}) someDirs!: QueryList<any>;
|
||||||
|
@ViewChildren(SomeDirective, {emitDistinctChangesOnly: false}) oldSomeDirs!: QueryList<any>;
|
||||||
|
}
|
||||||
|
@NgModule({declarations: [ContentQueryComponent]})
|
||||||
|
export class MyModule {
|
||||||
|
}
|
|
@ -3,8 +3,8 @@ ContentQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
selectors: [["content-query-component"]],
|
selectors: [["content-query-component"]],
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵstaticContentQuery(dirIndex, SomeDirective, true);
|
$r3$.ɵɵstaticContentQuery(dirIndex, SomeDirective, 3);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, true);
|
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -5,8 +5,8 @@ ViewQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
selectors: [["view-query-component"]],
|
selectors: [["view-query-component"]],
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵstaticViewQuery(SomeDirective, true);
|
$r3$.ɵɵstaticViewQuery(SomeDirective, 3);
|
||||||
$r3$.ɵɵviewQuery($refs$, true);
|
$r3$.ɵɵviewQuery($refs$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -3,8 +3,8 @@ ViewQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
selectors: [["view-query-component"]],
|
selectors: [["view-query-component"]],
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true);
|
$r3$.ɵɵviewQuery(SomeDirective, 1);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true);
|
$r3$.ɵɵviewQuery(SomeDirective, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -5,8 +5,8 @@ ViewQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
// ...
|
// ...
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery($e0_attrs$, true);
|
$r3$.ɵɵviewQuery($e0_attrs$, 1);
|
||||||
$r3$.ɵɵviewQuery($e1_attrs$, true);
|
$r3$.ɵɵviewQuery($e1_attrs$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -5,10 +5,10 @@ ViewQueryComponent.ɵcmp = $r3$.ɵɵdefineComponent({
|
||||||
// ...
|
// ...
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery($e0_attrs$, true, TemplateRef);
|
$r3$.ɵɵviewQuery($e0_attrs$, 1, TemplateRef);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true, ElementRef);
|
$r3$.ɵɵviewQuery(SomeDirective, 1, ElementRef);
|
||||||
$r3$.ɵɵviewQuery($e1_attrs$, true, ElementRef);
|
$r3$.ɵɵviewQuery($e1_attrs$, 1, ElementRef);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true, TemplateRef);
|
$r3$.ɵɵviewQuery(SomeDirective, 1, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -1636,8 +1636,8 @@ describe('compiler compliance', () => {
|
||||||
selectors: [["view-query-component"]],
|
selectors: [["view-query-component"]],
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true);
|
$r3$.ɵɵviewQuery(SomeDirective, 1);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true);
|
$r3$.ɵɵviewQuery(SomeDirective, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1695,8 +1695,8 @@ describe('compiler compliance', () => {
|
||||||
…
|
…
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery($e0_attrs$, true);
|
$r3$.ɵɵviewQuery($e0_attrs$, 1);
|
||||||
$r3$.ɵɵviewQuery($e1_attrs$, true);
|
$r3$.ɵɵviewQuery($e1_attrs$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1746,8 +1746,8 @@ describe('compiler compliance', () => {
|
||||||
selectors: [["view-query-component"]],
|
selectors: [["view-query-component"]],
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵstaticViewQuery(SomeDirective, true);
|
$r3$.ɵɵstaticViewQuery(SomeDirective, 3);
|
||||||
$r3$.ɵɵviewQuery($refs$, true);
|
$r3$.ɵɵviewQuery($refs$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1810,10 +1810,10 @@ describe('compiler compliance', () => {
|
||||||
…
|
…
|
||||||
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵviewQuery($e0_attrs$, true, TemplateRef);
|
$r3$.ɵɵviewQuery($e0_attrs$, 1, TemplateRef);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true, ElementRef);
|
$r3$.ɵɵviewQuery(SomeDirective, 1, ElementRef);
|
||||||
$r3$.ɵɵviewQuery($e1_attrs$, true, ElementRef);
|
$r3$.ɵɵviewQuery($e1_attrs$, 1, ElementRef);
|
||||||
$r3$.ɵɵviewQuery(SomeDirective, true, TemplateRef);
|
$r3$.ɵɵviewQuery(SomeDirective, 1, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1873,8 +1873,8 @@ describe('compiler compliance', () => {
|
||||||
selectors: [["content-query-component"]],
|
selectors: [["content-query-component"]],
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, true);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1933,8 +1933,8 @@ describe('compiler compliance', () => {
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true);
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, false);
|
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -1992,8 +1992,8 @@ describe('compiler compliance', () => {
|
||||||
selectors: [["content-query-component"]],
|
selectors: [["content-query-component"]],
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵstaticContentQuery(dirIndex, SomeDirective, true);
|
$r3$.ɵɵstaticContentQuery(dirIndex, SomeDirective, 3);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, true);
|
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, 1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
@ -2057,10 +2057,10 @@ describe('compiler compliance', () => {
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, true, TemplateRef);
|
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1, TemplateRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, true, ElementRef);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1, ElementRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, false, ElementRef);
|
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0, ElementRef);
|
||||||
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, false, TemplateRef);
|
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
let $tmp$;
|
let $tmp$;
|
||||||
|
|
|
@ -22,14 +22,14 @@ const trim = (input: string): string => input.replace(/\s+/g, ' ').trim();
|
||||||
|
|
||||||
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
||||||
|
|
||||||
const viewQueryRegExp = (predicate: string, descend: boolean, ref?: string): RegExp => {
|
const viewQueryRegExp = (predicate: string, flags: number, ref?: string): RegExp => {
|
||||||
const maybeRef = ref ? `, ${ref}` : ``;
|
const maybeRef = ref ? `, ${ref}` : ``;
|
||||||
return new RegExp(`i0\\.ɵɵviewQuery\\(${predicate}, ${descend}${maybeRef}\\)`);
|
return new RegExp(`i0\\.ɵɵviewQuery\\(${predicate}, ${flags}${maybeRef}\\)`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const contentQueryRegExp = (predicate: string, descend: boolean, ref?: string): RegExp => {
|
const contentQueryRegExp = (predicate: string, flags: number, ref?: string): RegExp => {
|
||||||
const maybeRef = ref ? `, ${ref}` : ``;
|
const maybeRef = ref ? `, ${ref}` : ``;
|
||||||
return new RegExp(`i0\\.ɵɵcontentQuery\\(dirIndex, ${predicate}, ${descend}${maybeRef}\\)`);
|
return new RegExp(`i0\\.ɵɵcontentQuery\\(dirIndex, ${predicate}, ${flags}${maybeRef}\\)`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setClassMetadataRegExp = (expectedType: string): RegExp =>
|
const setClassMetadataRegExp = (expectedType: string): RegExp =>
|
||||||
|
@ -3093,10 +3093,10 @@ runInEachFileSystem(os => {
|
||||||
expect(jsContents).toMatch(varRegExp('test1'));
|
expect(jsContents).toMatch(varRegExp('test1'));
|
||||||
expect(jsContents).toMatch(varRegExp('test2'));
|
expect(jsContents).toMatch(varRegExp('test2'));
|
||||||
expect(jsContents).toMatch(varRegExp('accessor'));
|
expect(jsContents).toMatch(varRegExp('accessor'));
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, _c1, true, TemplateRef)`
|
// match `i0.ɵɵcontentQuery(dirIndex, _c1, 1, TemplateRef)`
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('\\w+', true, 'TemplateRef'));
|
expect(jsContents).toMatch(contentQueryRegExp('\\w+', 1, 'TemplateRef'));
|
||||||
// match `i0.ɵɵviewQuery(_c2, true, null)`
|
// match `i0.ɵɵviewQuery(_c2, 1, null)`
|
||||||
expect(jsContents).toMatch(viewQueryRegExp('\\w+', true));
|
expect(jsContents).toMatch(viewQueryRegExp('\\w+', 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate queries for directives', () => {
|
it('should generate queries for directives', () => {
|
||||||
|
@ -3125,14 +3125,14 @@ runInEachFileSystem(os => {
|
||||||
expect(jsContents).toMatch(varRegExp('test1'));
|
expect(jsContents).toMatch(varRegExp('test1'));
|
||||||
expect(jsContents).toMatch(varRegExp('test2'));
|
expect(jsContents).toMatch(varRegExp('test2'));
|
||||||
expect(jsContents).toMatch(varRegExp('accessor'));
|
expect(jsContents).toMatch(varRegExp('accessor'));
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, _c1, true, TemplateRef)`
|
// match `i0.ɵɵcontentQuery(dirIndex, _c1, 1, TemplateRef)`
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('\\w+', true, 'TemplateRef'));
|
expect(jsContents).toMatch(contentQueryRegExp('\\w+', 1, 'TemplateRef'));
|
||||||
|
|
||||||
// match `i0.ɵɵviewQuery(_c2, true)`
|
// match `i0.ɵɵviewQuery(_c2, 1)`
|
||||||
// Note that while ViewQuery doesn't necessarily make sense on a directive,
|
// Note that while ViewQuery doesn't necessarily make sense on a directive,
|
||||||
// because it doesn't have a view, we still need to handle it because a component
|
// because it doesn't have a view, we still need to handle it because a component
|
||||||
// could extend the directive.
|
// could extend the directive.
|
||||||
expect(jsContents).toMatch(viewQueryRegExp('\\w+', true));
|
expect(jsContents).toMatch(viewQueryRegExp('\\w+', 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle queries that use forwardRef', () => {
|
it('should handle queries that use forwardRef', () => {
|
||||||
|
@ -3154,13 +3154,13 @@ runInEachFileSystem(os => {
|
||||||
|
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, TemplateRef, true, null)`
|
// match `i0.ɵɵcontentQuery(dirIndex, TemplateRef, 1, null)`
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('TemplateRef', true));
|
expect(jsContents).toMatch(contentQueryRegExp('TemplateRef', 1));
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, ViewContainerRef, true, null)`
|
// match `i0.ɵɵcontentQuery(dirIndex, ViewContainerRef, 1, null)`
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('ViewContainerRef', true));
|
expect(jsContents).toMatch(contentQueryRegExp('ViewContainerRef', 1));
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, _c0, true, null)`
|
// match `i0.ɵɵcontentQuery(dirIndex, _c0, 1, null)`
|
||||||
expect(jsContents).toContain('_c0 = ["parens"];');
|
expect(jsContents).toContain('_c0 = ["parens"];');
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('_c0', true));
|
expect(jsContents).toMatch(contentQueryRegExp('_c0', 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle queries that use an InjectionToken', () => {
|
it('should handle queries that use an InjectionToken', () => {
|
||||||
|
@ -3181,10 +3181,10 @@ runInEachFileSystem(os => {
|
||||||
|
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
// match `i0.ɵɵviewQuery(TOKEN, true, null)`
|
// match `i0.ɵɵviewQuery(TOKEN, 1, null)`
|
||||||
expect(jsContents).toMatch(viewQueryRegExp('TOKEN', true));
|
expect(jsContents).toMatch(viewQueryRegExp('TOKEN', 1));
|
||||||
// match `i0.ɵɵcontentQuery(dirIndex, TOKEN, true, null)`
|
// match `i0.ɵɵcontentQuery(dirIndex, TOKEN, 1, null)`
|
||||||
expect(jsContents).toMatch(contentQueryRegExp('TOKEN', true));
|
expect(jsContents).toMatch(contentQueryRegExp('TOKEN', 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compile expressions that write keys', () => {
|
it('should compile expressions that write keys', () => {
|
||||||
|
|
|
@ -169,6 +169,7 @@ export interface CompileQueryMetadata {
|
||||||
propertyName: string;
|
propertyName: string;
|
||||||
read: CompileTokenMetadata;
|
read: CompileTokenMetadata;
|
||||||
static?: boolean;
|
static?: boolean;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -240,6 +240,7 @@ export interface R3QueryMetadataFacade {
|
||||||
first: boolean;
|
first: boolean;
|
||||||
predicate: any|string[];
|
predicate: any|string[];
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
|
emitDistinctChangesOnly: boolean;
|
||||||
read: any|null;
|
read: any|null;
|
||||||
static: boolean;
|
static: boolean;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +252,7 @@ export interface R3DeclareQueryMetadataFacade {
|
||||||
descendants?: boolean;
|
descendants?: boolean;
|
||||||
read?: OpaqueValue;
|
read?: OpaqueValue;
|
||||||
static?: boolean;
|
static?: boolean;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseSourceSpan {
|
export interface ParseSourceSpan {
|
||||||
|
|
|
@ -27,6 +27,12 @@ export interface Attribute {
|
||||||
export const createAttribute =
|
export const createAttribute =
|
||||||
makeMetadataFactory<Attribute>('Attribute', (attributeName: string) => ({attributeName}));
|
makeMetadataFactory<Attribute>('Attribute', (attributeName: string) => ({attributeName}));
|
||||||
|
|
||||||
|
// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
|
||||||
|
// explicitly set. This value will be changed to `true` in v12.
|
||||||
|
// TODO(misko): switch the default in v12 to `true`. See: packages/core/src/metadata/di.ts
|
||||||
|
export const emitDistinctChangesOnlyDefaultValue = false;
|
||||||
|
|
||||||
|
|
||||||
export interface Query {
|
export interface Query {
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
first: boolean;
|
first: boolean;
|
||||||
|
@ -37,17 +43,27 @@ export interface Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createContentChildren = makeMetadataFactory<Query>(
|
export const createContentChildren = makeMetadataFactory<Query>(
|
||||||
'ContentChildren',
|
'ContentChildren', (selector?: any, data: any = {}) => ({
|
||||||
(selector?: any, data: any = {}) =>
|
selector,
|
||||||
({selector, first: false, isViewQuery: false, descendants: false, ...data}));
|
first: false,
|
||||||
|
isViewQuery: false,
|
||||||
|
descendants: false,
|
||||||
|
emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
|
||||||
|
...data
|
||||||
|
}));
|
||||||
export const createContentChild = makeMetadataFactory<Query>(
|
export const createContentChild = makeMetadataFactory<Query>(
|
||||||
'ContentChild',
|
'ContentChild',
|
||||||
(selector?: any, data: any = {}) =>
|
(selector?: any, data: any = {}) =>
|
||||||
({selector, first: true, isViewQuery: false, descendants: true, ...data}));
|
({selector, first: true, isViewQuery: false, descendants: true, ...data}));
|
||||||
export const createViewChildren = makeMetadataFactory<Query>(
|
export const createViewChildren = makeMetadataFactory<Query>(
|
||||||
'ViewChildren',
|
'ViewChildren', (selector?: any, data: any = {}) => ({
|
||||||
(selector?: any, data: any = {}) =>
|
selector,
|
||||||
({selector, first: false, isViewQuery: true, descendants: true, ...data}));
|
first: false,
|
||||||
|
isViewQuery: true,
|
||||||
|
descendants: true,
|
||||||
|
emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
|
||||||
|
...data
|
||||||
|
}));
|
||||||
export const createViewChild = makeMetadataFactory<Query>(
|
export const createViewChild = makeMetadataFactory<Query>(
|
||||||
'ViewChild',
|
'ViewChild',
|
||||||
(selector: any, data: any) =>
|
(selector: any, data: any) =>
|
||||||
|
@ -224,6 +240,7 @@ export const enum NodeFlags {
|
||||||
StaticQuery = 1 << 28,
|
StaticQuery = 1 << 28,
|
||||||
DynamicQuery = 1 << 29,
|
DynamicQuery = 1 << 29,
|
||||||
TypeModuleProvider = 1 << 30,
|
TypeModuleProvider = 1 << 30,
|
||||||
|
EmitDistinctChangesOnly = 1 << 31,
|
||||||
CatQuery = TypeContentQuery | TypeViewQuery,
|
CatQuery = TypeContentQuery | TypeViewQuery,
|
||||||
|
|
||||||
// mutually exclusive values...
|
// mutually exclusive values...
|
||||||
|
|
|
@ -243,7 +243,8 @@ function convertToR3QueryMetadata(facade: R3QueryMetadataFacade): R3QueryMetadat
|
||||||
predicate: Array.isArray(facade.predicate) ? facade.predicate :
|
predicate: Array.isArray(facade.predicate) ? facade.predicate :
|
||||||
new WrappedNodeExpr(facade.predicate),
|
new WrappedNodeExpr(facade.predicate),
|
||||||
read: facade.read ? new WrappedNodeExpr(facade.read) : null,
|
read: facade.read ? new WrappedNodeExpr(facade.read) : null,
|
||||||
static: facade.static
|
static: facade.static,
|
||||||
|
emitDistinctChangesOnly: facade.emitDistinctChangesOnly,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +258,7 @@ function convertQueryDeclarationToMetadata(declaration: R3DeclareQueryMetadataFa
|
||||||
descendants: declaration.descendants ?? false,
|
descendants: declaration.descendants ?? false,
|
||||||
read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
|
read: declaration.read ? new WrappedNodeExpr(declaration.read) : null,
|
||||||
static: declaration.static ?? false,
|
static: declaration.static ?? false,
|
||||||
|
emitDistinctChangesOnly: declaration.emitDistinctChangesOnly ?? true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1196,6 +1196,7 @@ export class CompileMetadataResolver {
|
||||||
selectors,
|
selectors,
|
||||||
first: q.first,
|
first: q.first,
|
||||||
descendants: q.descendants,
|
descendants: q.descendants,
|
||||||
|
emitDistinctChangesOnly: q.emitDistinctChangesOnly,
|
||||||
propertyName,
|
propertyName,
|
||||||
read: q.read ? this._getTokenMetadata(q.read) : null!,
|
read: q.read ? this._getTokenMetadata(q.read) : null!,
|
||||||
static: q.static
|
static: q.static
|
||||||
|
|
|
@ -232,6 +232,14 @@ export interface R3DeclareQueryMetadata {
|
||||||
*/
|
*/
|
||||||
descendants?: boolean;
|
descendants?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True to only fire changes if there are underlying changes to the query.
|
||||||
|
*/
|
||||||
|
// TODO(misko): This will become `true` be default in v12. `QueryList.changes` would fire even if
|
||||||
|
// no changes to the query list were detected. This is not ideal, as changes should only fire if
|
||||||
|
// the `QueryList` actually materially changed.
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression representing a type to read from each matched node, or null if the default value
|
* An expression representing a type to read from each matched node, or null if the default value
|
||||||
* for a given node is to be returned.
|
* for a given node is to be returned.
|
||||||
|
|
|
@ -86,6 +86,11 @@ function compileQuery(query: R3QueryMetadata): o.LiteralMapExpr {
|
||||||
}
|
}
|
||||||
meta.set(
|
meta.set(
|
||||||
'predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : query.predicate);
|
'predicate', Array.isArray(query.predicate) ? asLiteral(query.predicate) : query.predicate);
|
||||||
|
if (!query.emitDistinctChangesOnly) {
|
||||||
|
// `emitDistinctChangesOnly` is special because in future we expect it to be `true`. For this
|
||||||
|
// reason the absence should be interpreted as `true`.
|
||||||
|
meta.set('emitDistinctChangesOnly', o.literal(false));
|
||||||
|
}
|
||||||
if (query.descendants) {
|
if (query.descendants) {
|
||||||
meta.set('descendants', o.literal(true));
|
meta.set('descendants', o.literal(true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,6 +304,13 @@ export interface R3QueryMetadata {
|
||||||
*/
|
*/
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the `QueryList` should fire change event only if actual change to query was computed (vs old
|
||||||
|
* behavior where the change was fired whenever the query was recomputed, even if the recomputed
|
||||||
|
* query resulted in the same list.)
|
||||||
|
*/
|
||||||
|
emitDistinctChangesOnly: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression representing a type to read from each matched node, or null if the default value
|
* An expression representing a type to read from each matched node, or null if the default value
|
||||||
* for a given node is to be returned.
|
* for a given node is to be returned.
|
||||||
|
|
|
@ -404,6 +404,7 @@ function queriesFromGlobalMetadata(
|
||||||
predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
|
predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx),
|
||||||
descendants: query.descendants,
|
descendants: query.descendants,
|
||||||
read,
|
read,
|
||||||
|
emitDistinctChangesOnly: !!query.emitDistinctChangesOnly,
|
||||||
static: !!query.static
|
static: !!query.static
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -435,13 +436,55 @@ function selectorsFromGlobalMetadata(
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool): o.Expression[] {
|
function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool): o.Expression[] {
|
||||||
const parameters = [getQueryPredicate(query, constantPool), o.literal(query.descendants)];
|
const parameters = [getQueryPredicate(query, constantPool), o.literal(toQueryFlags(query))];
|
||||||
if (query.read) {
|
if (query.read) {
|
||||||
parameters.push(query.read);
|
parameters.push(query.read);
|
||||||
}
|
}
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of flags to be used with Queries.
|
||||||
|
*
|
||||||
|
* NOTE: Ensure changes here are in sync with `packages/core/src/render3/interfaces/query.ts`
|
||||||
|
*/
|
||||||
|
export const enum QueryFlags {
|
||||||
|
/**
|
||||||
|
* No flags
|
||||||
|
*/
|
||||||
|
none = 0b0000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the query should descend into children.
|
||||||
|
*/
|
||||||
|
descendants = 0b0001,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query can be computed statically and hence can be assigned eagerly.
|
||||||
|
*
|
||||||
|
* NOTE: Backwards compatibility with ViewEngine.
|
||||||
|
*/
|
||||||
|
isStatic = 0b0010,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the `QueryList` should fire change event only if actual change to query was computed (vs old
|
||||||
|
* behavior where the change was fired whenever the query was recomputed, even if the recomputed
|
||||||
|
* query resulted in the same list.)
|
||||||
|
*/
|
||||||
|
emitDistinctChangesOnly = 0b0100,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates query flags into `TQueryFlags` type in packages/core/src/render3/interfaces/query.ts
|
||||||
|
* @param query
|
||||||
|
*/
|
||||||
|
function toQueryFlags(query: R3QueryMetadata): number {
|
||||||
|
// NOTE: Verify that changes here match
|
||||||
|
return (query.descendants ? 1 /* TQueryFlags.descendants */ : 0) |
|
||||||
|
(query.static ? 2 /* TQueryFlags.isStatic */ : 0) |
|
||||||
|
(query.emitDistinctChangesOnly ? 4 /* TQueryFlags.emitDistinctChangesOnly */ : 0);
|
||||||
|
}
|
||||||
|
|
||||||
function convertAttributesToExpressions(attributes: {[name: string]: o.Expression}):
|
function convertAttributesToExpressions(attributes: {[name: string]: o.Expression}):
|
||||||
o.Expression[] {
|
o.Expression[] {
|
||||||
const values: o.Expression[] = [];
|
const values: o.Expression[] = [];
|
||||||
|
|
|
@ -143,7 +143,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||||
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
// Note: queries start with id 1 so we can use the number in a Bloom filter!
|
||||||
const queryId = queryIndex + 1;
|
const queryId = queryIndex + 1;
|
||||||
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
|
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
|
||||||
const flags = NodeFlags.TypeViewQuery | calcStaticDynamicQueryFlags(query);
|
const flags = NodeFlags.TypeViewQuery | calcQueryFlags(query);
|
||||||
this.nodes.push(() => ({
|
this.nodes.push(() => ({
|
||||||
sourceSpan: null,
|
sourceSpan: null,
|
||||||
nodeFlags: flags,
|
nodeFlags: flags,
|
||||||
|
@ -485,7 +485,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||||
|
|
||||||
dirAst.directive.queries.forEach((query, queryIndex) => {
|
dirAst.directive.queries.forEach((query, queryIndex) => {
|
||||||
const queryId = dirAst.contentQueryStartId + queryIndex;
|
const queryId = dirAst.contentQueryStartId + queryIndex;
|
||||||
const flags = NodeFlags.TypeContentQuery | calcStaticDynamicQueryFlags(query);
|
const flags = NodeFlags.TypeContentQuery | calcQueryFlags(query);
|
||||||
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
|
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
|
||||||
this.nodes.push(() => ({
|
this.nodes.push(() => ({
|
||||||
sourceSpan: dirAst.sourceSpan,
|
sourceSpan: dirAst.sourceSpan,
|
||||||
|
@ -1028,7 +1028,7 @@ function elementEventNameAndTarget(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcStaticDynamicQueryFlags(query: CompileQueryMetadata) {
|
function calcQueryFlags(query: CompileQueryMetadata) {
|
||||||
let flags = NodeFlags.None;
|
let flags = NodeFlags.None;
|
||||||
// Note: We only make queries static that query for a single item and the user specifically
|
// Note: We only make queries static that query for a single item and the user specifically
|
||||||
// set the to be static. This is because of backwards compatibility with the old view compiler...
|
// set the to be static. This is because of backwards compatibility with the old view compiler...
|
||||||
|
@ -1037,6 +1037,9 @@ function calcStaticDynamicQueryFlags(query: CompileQueryMetadata) {
|
||||||
} else {
|
} else {
|
||||||
flags |= NodeFlags.DynamicQuery;
|
flags |= NodeFlags.DynamicQuery;
|
||||||
}
|
}
|
||||||
|
if (query.emitDistinctChangesOnly) {
|
||||||
|
flags |= NodeFlags.EmitDistinctChangesOnly;
|
||||||
|
}
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,7 @@ export interface R3QueryMetadataFacade {
|
||||||
first: boolean;
|
first: boolean;
|
||||||
predicate: any|string[];
|
predicate: any|string[];
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
|
emitDistinctChangesOnly: boolean;
|
||||||
read: any|null;
|
read: any|null;
|
||||||
static: boolean;
|
static: boolean;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +252,7 @@ export interface R3DeclareQueryMetadataFacade {
|
||||||
descendants?: boolean;
|
descendants?: boolean;
|
||||||
read?: OpaqueValue;
|
read?: OpaqueValue;
|
||||||
static?: boolean;
|
static?: boolean;
|
||||||
|
emitDistinctChangesOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseSourceSpan {
|
export interface ParseSourceSpan {
|
||||||
|
|
|
@ -86,3 +86,14 @@ export class ElementRef<T = any> {
|
||||||
*/
|
*/
|
||||||
static __NG_ELEMENT_ID__: () => ElementRef = SWITCH_ELEMENT_REF_FACTORY;
|
static __NG_ELEMENT_ID__: () => ElementRef = SWITCH_ELEMENT_REF_FACTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwraps `ElementRef` and return the `nativeElement`.
|
||||||
|
*
|
||||||
|
* Conditionally unwrap the `ElementRef`.
|
||||||
|
* @param value value to unwrap
|
||||||
|
* @returns `nativeElement` if `ElementRef` otherwise returns value as is.
|
||||||
|
*/
|
||||||
|
export function unwrapElementRef<T, R>(value: T|ElementRef<R>): T|R {
|
||||||
|
return value instanceof ElementRef ? value.nativeElement : value;
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
import {EventEmitter} from '../event_emitter';
|
import {EventEmitter} from '../event_emitter';
|
||||||
import {flatten} from '../util/array_utils';
|
import {arrayEquals, flatten} from '../util/array_utils';
|
||||||
import {getSymbolIterator} from '../util/symbol';
|
import {getSymbolIterator} from '../util/symbol';
|
||||||
|
|
||||||
function symbolIterator<T>(this: QueryList<T>): Iterator<T> {
|
function symbolIterator<T>(this: QueryList<T>): Iterator<T> {
|
||||||
|
@ -45,15 +45,31 @@ function symbolIterator<T>(this: QueryList<T>): Iterator<T> {
|
||||||
export class QueryList<T> implements Iterable<T> {
|
export class QueryList<T> implements Iterable<T> {
|
||||||
public readonly dirty = true;
|
public readonly dirty = true;
|
||||||
private _results: Array<T> = [];
|
private _results: Array<T> = [];
|
||||||
public readonly changes: Observable<any> = new EventEmitter();
|
private _changesDetected: boolean = false;
|
||||||
|
private _changes: EventEmitter<QueryList<T>>|null = null;
|
||||||
|
|
||||||
readonly length: number = 0;
|
readonly length: number = 0;
|
||||||
// TODO(issue/24571): remove '!'.
|
readonly first: T = undefined!;
|
||||||
readonly first!: T;
|
readonly last: T = undefined!;
|
||||||
// TODO(issue/24571): remove '!'.
|
|
||||||
readonly last!: T;
|
|
||||||
|
|
||||||
constructor() {
|
/**
|
||||||
|
* Returns `Observable` of `QueryList` notifying the subscriber of changes.
|
||||||
|
*
|
||||||
|
* NOTE: This currently points to `changesDeprecated` which incorrectly notifies of changes even
|
||||||
|
* if no changes to `QueryList` have occurred. (It fires more often than it needs to.)
|
||||||
|
* The implementation will change to point `changesStrict` starting with v12.
|
||||||
|
*/
|
||||||
|
get changes(): Observable<any> {
|
||||||
|
return this._changes || (this._changes = new EventEmitter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
|
||||||
|
* has occurred. Or if it should fire when query is recomputed. (recomputing could resolve in
|
||||||
|
* the same result) This is set to `false` for backwards compatibility but will be changed to
|
||||||
|
* true in v12.
|
||||||
|
*/
|
||||||
|
constructor(private _emitDistinctChangesOnly: boolean = false) {
|
||||||
// This function should be declared on the prototype, but doing so there will cause the class
|
// This function should be declared on the prototype, but doing so there will cause the class
|
||||||
// declaration to have side-effects and become not tree-shakable. For this reason we do it in
|
// declaration to have side-effects and become not tree-shakable. For this reason we do it in
|
||||||
// the constructor.
|
// the constructor.
|
||||||
|
@ -135,20 +151,27 @@ export class QueryList<T> implements Iterable<T> {
|
||||||
* occurs.
|
* occurs.
|
||||||
*
|
*
|
||||||
* @param resultsTree The query results to store
|
* @param resultsTree The query results to store
|
||||||
|
* @param identityAccessor Optional functions for extracting stable object identity from a value
|
||||||
|
* in the array.
|
||||||
*/
|
*/
|
||||||
reset(resultsTree: Array<T|any[]>): void {
|
reset(resultsTree: Array<T|any[]>, identityAccessor?: (value: T) => unknown): void {
|
||||||
this._results = flatten(resultsTree);
|
const self = this as QueryListInternal<T>;
|
||||||
(this as {dirty: boolean}).dirty = false;
|
(self as {dirty: boolean}).dirty = false;
|
||||||
(this as {length: number}).length = this._results.length;
|
const newResultFlat = flatten(resultsTree);
|
||||||
(this as {last: T}).last = this._results[this.length - 1];
|
if (this._changesDetected = !arrayEquals(self._results, newResultFlat, identityAccessor)) {
|
||||||
(this as {first: T}).first = this._results[0];
|
self._results = newResultFlat;
|
||||||
|
self.length = newResultFlat.length;
|
||||||
|
self.last = newResultFlat[this.length - 1];
|
||||||
|
self.first = newResultFlat[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers a change event by emitting on the `changes` {@link EventEmitter}.
|
* Triggers a change event by emitting on the `changes` {@link EventEmitter}.
|
||||||
*/
|
*/
|
||||||
notifyOnChanges(): void {
|
notifyOnChanges(): void {
|
||||||
(this.changes as EventEmitter<any>).emit(this);
|
if (this._changes && (this._emitDistinctChangesOnly ? this._changesDetected : true))
|
||||||
|
this._changes.emit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** internal */
|
/** internal */
|
||||||
|
@ -169,3 +192,14 @@ export class QueryList<T> implements Iterable<T> {
|
||||||
// over QueryLists to work correctly, since QueryList must be assignable to NgIterable.
|
// over QueryLists to work correctly, since QueryList must be assignable to NgIterable.
|
||||||
[Symbol.iterator]!: () => Iterator<T>;
|
[Symbol.iterator]!: () => Iterator<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal set of APIs used by the framework. (not to be made public)
|
||||||
|
*/
|
||||||
|
export interface QueryListInternal<T> extends QueryList<T> {
|
||||||
|
reset(a: any[]): void;
|
||||||
|
notifyOnChanges(): void;
|
||||||
|
length: number;
|
||||||
|
last: T;
|
||||||
|
first: T;
|
||||||
|
}
|
|
@ -98,6 +98,7 @@ export interface Attribute {
|
||||||
*/
|
*/
|
||||||
export interface Query {
|
export interface Query {
|
||||||
descendants: boolean;
|
descendants: boolean;
|
||||||
|
emitDistinctChangesOnly: boolean;
|
||||||
first: boolean;
|
first: boolean;
|
||||||
read: any;
|
read: any;
|
||||||
isViewQuery: boolean;
|
isViewQuery: boolean;
|
||||||
|
@ -105,6 +106,12 @@ export interface Query {
|
||||||
static?: boolean;
|
static?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stores the default value of `emitDistinctChangesOnly` when the `emitDistinctChangesOnly` is not
|
||||||
|
// explicitly set. This value will be changed to `true` in v12.
|
||||||
|
// TODO(misko): switch the default in v12 to `true`. See: packages/compiler/src/core.ts
|
||||||
|
export const emitDistinctChangesOnlyDefaultValue = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for query metadata.
|
* Base class for query metadata.
|
||||||
*
|
*
|
||||||
|
@ -140,6 +147,9 @@ export interface ContentChildrenDecorator {
|
||||||
*
|
*
|
||||||
* * **selector** - The directive type or the name used for querying.
|
* * **selector** - The directive type or the name used for querying.
|
||||||
* * **descendants** - True to include all descendants, otherwise include only direct children.
|
* * **descendants** - True to include all descendants, otherwise include only direct children.
|
||||||
|
* * **emitDistinctChangesOnly** - The ` QueryList#changes` observable will emit new values only
|
||||||
|
* if the QueryList result has changed. The default value will change from `false` to `true` in
|
||||||
|
* v12. When `false` the `changes` observable might emit even if the QueryList has not changed.
|
||||||
* * **read** - Used to read a different token from the queried elements.
|
* * **read** - Used to read a different token from the queried elements.
|
||||||
*
|
*
|
||||||
* @usageNotes
|
* @usageNotes
|
||||||
|
@ -157,10 +167,13 @@ export interface ContentChildrenDecorator {
|
||||||
*
|
*
|
||||||
* @Annotation
|
* @Annotation
|
||||||
*/
|
*/
|
||||||
(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
(selector: Type<any>|InjectionToken<unknown>|Function|string, opts?: {
|
||||||
opts?: {descendants?: boolean, read?: any}): any;
|
descendants?: boolean,
|
||||||
|
emitDistinctChangesOnly?: boolean,
|
||||||
|
read?: any,
|
||||||
|
}): any;
|
||||||
new(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
new(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
||||||
opts?: {descendants?: boolean, read?: any}): Query;
|
opts?: {descendants?: boolean, emitDistinctChangesOnly?: boolean, read?: any}): Query;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,9 +193,14 @@ export type ContentChildren = Query;
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export const ContentChildren: ContentChildrenDecorator = makePropDecorator(
|
export const ContentChildren: ContentChildrenDecorator = makePropDecorator(
|
||||||
'ContentChildren',
|
'ContentChildren', (selector?: any, data: any = {}) => ({
|
||||||
(selector?: any, data: any = {}) =>
|
selector,
|
||||||
({selector, first: false, isViewQuery: false, descendants: false, ...data}),
|
first: false,
|
||||||
|
isViewQuery: false,
|
||||||
|
descendants: false,
|
||||||
|
emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
|
||||||
|
...data
|
||||||
|
}),
|
||||||
Query);
|
Query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -268,6 +286,9 @@ export interface ViewChildrenDecorator {
|
||||||
*
|
*
|
||||||
* * **selector** - The directive type or the name used for querying.
|
* * **selector** - The directive type or the name used for querying.
|
||||||
* * **read** - Used to read a different token from the queried elements.
|
* * **read** - Used to read a different token from the queried elements.
|
||||||
|
* * **emitDistinctChangesOnly** - The ` QueryList#changes` observable will emit new values only
|
||||||
|
* if the QueryList result has changed. The default value will change from `false` to `true` in
|
||||||
|
* v12. When `false` the `changes` observable might emit even if the QueryList has not changed.
|
||||||
*
|
*
|
||||||
* @usageNotes
|
* @usageNotes
|
||||||
*
|
*
|
||||||
|
@ -279,9 +300,10 @@ export interface ViewChildrenDecorator {
|
||||||
*
|
*
|
||||||
* @Annotation
|
* @Annotation
|
||||||
*/
|
*/
|
||||||
(selector: Type<any>|InjectionToken<unknown>|Function|string, opts?: {read?: any}): any;
|
(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
||||||
|
opts?: {read?: any, emitDistinctChangesOnly?: boolean}): any;
|
||||||
new(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
new(selector: Type<any>|InjectionToken<unknown>|Function|string,
|
||||||
opts?: {read?: any}): ViewChildren;
|
opts?: {read?: any, emitDistinctChangesOnly?: boolean}): ViewChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,9 +320,14 @@ export type ViewChildren = Query;
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export const ViewChildren: ViewChildrenDecorator = makePropDecorator(
|
export const ViewChildren: ViewChildrenDecorator = makePropDecorator(
|
||||||
'ViewChildren',
|
'ViewChildren', (selector?: any, data: any = {}) => ({
|
||||||
(selector?: any, data: any = {}) =>
|
selector,
|
||||||
({selector, first: false, isViewQuery: true, descendants: true, ...data}),
|
first: false,
|
||||||
|
isViewQuery: true,
|
||||||
|
descendants: true,
|
||||||
|
emitDistinctChangesOnly: emitDistinctChangesOnlyDefaultValue,
|
||||||
|
...data
|
||||||
|
}),
|
||||||
Query);
|
Query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,9 +18,39 @@ import {TView} from './view';
|
||||||
*/
|
*/
|
||||||
export interface TQueryMetadata {
|
export interface TQueryMetadata {
|
||||||
predicate: Type<any>|InjectionToken<unknown>|string[];
|
predicate: Type<any>|InjectionToken<unknown>|string[];
|
||||||
descendants: boolean;
|
|
||||||
read: any;
|
read: any;
|
||||||
isStatic: boolean;
|
flags: QueryFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of flags to be used with Queries.
|
||||||
|
*
|
||||||
|
* NOTE: Ensure changes here are reflected in `packages/compiler/src/render3/view/compiler.ts`
|
||||||
|
*/
|
||||||
|
export const enum QueryFlags {
|
||||||
|
/**
|
||||||
|
* No flags
|
||||||
|
*/
|
||||||
|
none = 0b0000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the query should descend into children.
|
||||||
|
*/
|
||||||
|
descendants = 0b0001,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query can be computed statically and hence can be assigned eagerly.
|
||||||
|
*
|
||||||
|
* NOTE: Backwards compatibility with ViewEngine.
|
||||||
|
*/
|
||||||
|
isStatic = 0b0010,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the `QueryList` should fire change event only if actual change to query was computed (vs old
|
||||||
|
* behavior where the change was fired whenever the query was recomputed, even if the recomputed
|
||||||
|
* query resulted in the same list.)
|
||||||
|
*/
|
||||||
|
emitDistinctChangesOnly = 0b0100,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -286,7 +286,8 @@ export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3Qu
|
||||||
descendants: ann.descendants,
|
descendants: ann.descendants,
|
||||||
first: ann.first,
|
first: ann.first,
|
||||||
read: ann.read ? ann.read : null,
|
read: ann.read ? ann.read : null,
|
||||||
static: !!ann.static
|
static: !!ann.static,
|
||||||
|
emitDistinctChangesOnly: !!ann.emitDistinctChangesOnly,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function extractQueriesMetadata(
|
function extractQueriesMetadata(
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
|
|
||||||
import {InjectionToken} from '../di/injection_token';
|
import {InjectionToken} from '../di/injection_token';
|
||||||
import {Type} from '../interface/type';
|
import {Type} from '../interface/type';
|
||||||
import {createElementRef, ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
import {createElementRef, ElementRef as ViewEngine_ElementRef, unwrapElementRef} from '../linker/element_ref';
|
||||||
import {QueryList} from '../linker/query_list';
|
import {QueryList} from '../linker/query_list';
|
||||||
import {createTemplateRef, TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
import {createTemplateRef, TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
||||||
import {createContainerRef, ViewContainerRef} from '../linker/view_container_ref';
|
import {createContainerRef, ViewContainerRef} from '../linker/view_container_ref';
|
||||||
import {assertDefined, assertIndexInRange, throwError} from '../util/assert';
|
import {assertDefined, assertIndexInRange, assertNumber, throwError} from '../util/assert';
|
||||||
import {stringify} from '../util/stringify';
|
import {stringify} from '../util/stringify';
|
||||||
import {assertFirstCreatePass, assertLContainer} from './assert';
|
import {assertFirstCreatePass, assertLContainer} from './assert';
|
||||||
import {getNodeInjectable, locateDirectiveOrProvider} from './di';
|
import {getNodeInjectable, locateDirectiveOrProvider} from './di';
|
||||||
|
@ -24,7 +24,7 @@ import {CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS} from './interfaces/con
|
||||||
import {unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
import {unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
||||||
import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
||||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
||||||
import {LQueries, LQuery, TQueries, TQuery, TQueryMetadata, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
import {LQueries, LQuery, QueryFlags, TQueries, TQuery, TQueryMetadata, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
||||||
import {DECLARATION_LCONTAINER, LView, PARENT, QUERIES, TVIEW, TView} from './interfaces/view';
|
import {DECLARATION_LCONTAINER, LView, PARENT, QUERIES, TVIEW, TView} from './interfaces/view';
|
||||||
import {assertTNodeType} from './node_assert';
|
import {assertTNodeType} from './node_assert';
|
||||||
import {getCurrentQueryIndex, getCurrentTNode, getLView, getTView, setCurrentQueryIndex} from './state';
|
import {getCurrentQueryIndex, getCurrentTNode, getLView, getTView, setCurrentQueryIndex} from './state';
|
||||||
|
@ -88,8 +88,8 @@ class LQueries_ implements LQueries {
|
||||||
|
|
||||||
class TQueryMetadata_ implements TQueryMetadata {
|
class TQueryMetadata_ implements TQueryMetadata {
|
||||||
constructor(
|
constructor(
|
||||||
public predicate: Type<any>|InjectionToken<unknown>|string[], public descendants: boolean,
|
public predicate: Type<any>|InjectionToken<unknown>|string[], public flags: QueryFlags,
|
||||||
public isStatic: boolean, public read: any = null) {}
|
public read: any = null) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TQueries_ implements TQueries {
|
class TQueries_ implements TQueries {
|
||||||
|
@ -202,7 +202,8 @@ class TQuery_ implements TQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
private isApplyingToNode(tNode: TNode): boolean {
|
private isApplyingToNode(tNode: TNode): boolean {
|
||||||
if (this._appliesToNextNode && this.metadata.descendants === false) {
|
const isDescend = (this.metadata.flags & QueryFlags.descendants) === QueryFlags.descendants;
|
||||||
|
if (this._appliesToNextNode && !isDescend) {
|
||||||
const declarationNodeIdx = this._declarationNodeIndex;
|
const declarationNodeIdx = this._declarationNodeIndex;
|
||||||
let parent = tNode.parent;
|
let parent = tNode.parent;
|
||||||
// Determine if a given TNode is a "direct" child of a node on which a content query was
|
// Determine if a given TNode is a "direct" child of a node on which a content query was
|
||||||
|
@ -427,14 +428,15 @@ export function ɵɵqueryRefresh(queryList: QueryList<any>): boolean {
|
||||||
setCurrentQueryIndex(queryIndex + 1);
|
setCurrentQueryIndex(queryIndex + 1);
|
||||||
|
|
||||||
const tQuery = getTQuery(tView, queryIndex);
|
const tQuery = getTQuery(tView, queryIndex);
|
||||||
if (queryList.dirty && (isCreationMode(lView) === tQuery.metadata.isStatic)) {
|
const isStatic = (tQuery.metadata.flags & QueryFlags.isStatic) === QueryFlags.isStatic;
|
||||||
|
if (queryList.dirty && (isCreationMode(lView) === isStatic)) {
|
||||||
if (tQuery.matches === null) {
|
if (tQuery.matches === null) {
|
||||||
queryList.reset([]);
|
queryList.reset([]);
|
||||||
} else {
|
} else {
|
||||||
const result = tQuery.crossesNgTemplate ?
|
const result = tQuery.crossesNgTemplate ?
|
||||||
collectQueryResults(tView, lView, queryIndex, []) :
|
collectQueryResults(tView, lView, queryIndex, []) :
|
||||||
materializeViewResults(tView, lView, tQuery, queryIndex);
|
materializeViewResults(tView, lView, tQuery, queryIndex);
|
||||||
queryList.reset(result);
|
queryList.reset(result, unwrapElementRef);
|
||||||
queryList.notifyOnChanges();
|
queryList.notifyOnChanges();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -447,40 +449,42 @@ export function ɵɵqueryRefresh(queryList: QueryList<any>): boolean {
|
||||||
* Creates new QueryList for a static view query.
|
* Creates new QueryList for a static view query.
|
||||||
*
|
*
|
||||||
* @param predicate The type for which the query will search
|
* @param predicate The type for which the query will search
|
||||||
* @param descend Whether or not to descend into children
|
* @param flags Flags associated with the query
|
||||||
* @param read What to save in the query
|
* @param read What to save in the query
|
||||||
*
|
*
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵstaticViewQuery<T>(
|
export function ɵɵstaticViewQuery<T>(
|
||||||
predicate: Type<any>|InjectionToken<unknown>|string[], descend: boolean, read?: any): void {
|
predicate: Type<any>|InjectionToken<unknown>|string[], flags: QueryFlags, read?: any): void {
|
||||||
viewQueryInternal(getTView(), getLView(), predicate, descend, read, true);
|
ngDevMode && assertNumber(flags, 'Expecting flags');
|
||||||
|
viewQueryInternal(getTView(), getLView(), predicate, flags | QueryFlags.isStatic, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new QueryList, stores the reference in LView and returns QueryList.
|
* Creates new QueryList, stores the reference in LView and returns QueryList.
|
||||||
*
|
*
|
||||||
* @param predicate The type for which the query will search
|
* @param predicate The type for which the query will search
|
||||||
* @param descend Whether or not to descend into children
|
* @param flags Flags associated with the query
|
||||||
* @param read What to save in the query
|
* @param read What to save in the query
|
||||||
*
|
*
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵviewQuery<T>(
|
export function ɵɵviewQuery<T>(
|
||||||
predicate: Type<any>|InjectionToken<unknown>|string[], descend: boolean, read?: any): void {
|
predicate: Type<any>|InjectionToken<unknown>|string[], flags: QueryFlags, read?: any): void {
|
||||||
viewQueryInternal(getTView(), getLView(), predicate, descend, read, false);
|
ngDevMode && assertNumber(flags, 'Expecting flags');
|
||||||
|
viewQueryInternal(getTView(), getLView(), predicate, flags, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
function viewQueryInternal<T>(
|
function viewQueryInternal<T>(
|
||||||
tView: TView, lView: LView, predicate: Type<any>|InjectionToken<unknown>|string[],
|
tView: TView, lView: LView, predicate: Type<any>|InjectionToken<unknown>|string[],
|
||||||
descend: boolean, read: any, isStatic: boolean): void {
|
flags: QueryFlags, read: any): void {
|
||||||
if (tView.firstCreatePass) {
|
if (tView.firstCreatePass) {
|
||||||
createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), -1);
|
createTQuery(tView, new TQueryMetadata_(predicate, flags, read), -1);
|
||||||
if (isStatic) {
|
if (flags & QueryFlags.isStatic) {
|
||||||
tView.staticViewQueries = true;
|
tView.staticViewQueries = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createLQuery<T>(tView, lView);
|
createLQuery<T>(tView, lView, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,17 +493,18 @@ function viewQueryInternal<T>(
|
||||||
*
|
*
|
||||||
* @param directiveIndex Current directive index
|
* @param directiveIndex Current directive index
|
||||||
* @param predicate The type for which the query will search
|
* @param predicate The type for which the query will search
|
||||||
* @param descend Whether or not to descend into children
|
* @param flags Flags associated with the query
|
||||||
* @param read What to save in the query
|
* @param read What to save in the query
|
||||||
* @returns QueryList<T>
|
* @returns QueryList<T>
|
||||||
*
|
*
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵcontentQuery<T>(
|
export function ɵɵcontentQuery<T>(
|
||||||
directiveIndex: number, predicate: Type<any>|InjectionToken<unknown>|string[], descend: boolean,
|
directiveIndex: number, predicate: Type<any>|InjectionToken<unknown>|string[],
|
||||||
read?: any): void {
|
flags: QueryFlags, read?: any): void {
|
||||||
|
ngDevMode && assertNumber(flags, 'Expecting flags');
|
||||||
contentQueryInternal(
|
contentQueryInternal(
|
||||||
getTView(), getLView(), predicate, descend, read, false, getCurrentTNode()!, directiveIndex);
|
getTView(), getLView(), predicate, flags, read, false, getCurrentTNode()!, directiveIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -508,31 +513,32 @@ export function ɵɵcontentQuery<T>(
|
||||||
*
|
*
|
||||||
* @param directiveIndex Current directive index
|
* @param directiveIndex Current directive index
|
||||||
* @param predicate The type for which the query will search
|
* @param predicate The type for which the query will search
|
||||||
* @param descend Whether or not to descend into children
|
* @param flags Flags associated with the query
|
||||||
* @param read What to save in the query
|
* @param read What to save in the query
|
||||||
* @returns QueryList<T>
|
* @returns QueryList<T>
|
||||||
*
|
*
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵstaticContentQuery<T>(
|
export function ɵɵstaticContentQuery<T>(
|
||||||
directiveIndex: number, predicate: Type<any>|InjectionToken<unknown>|string[], descend: boolean,
|
directiveIndex: number, predicate: Type<any>|InjectionToken<unknown>|string[],
|
||||||
read?: any): void {
|
flags: QueryFlags, read?: any): void {
|
||||||
|
ngDevMode && assertNumber(flags, 'Expecting flags');
|
||||||
contentQueryInternal(
|
contentQueryInternal(
|
||||||
getTView(), getLView(), predicate, descend, read, true, getCurrentTNode()!, directiveIndex);
|
getTView(), getLView(), predicate, flags, read, true, getCurrentTNode()!, directiveIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function contentQueryInternal<T>(
|
function contentQueryInternal<T>(
|
||||||
tView: TView, lView: LView, predicate: Type<any>|InjectionToken<unknown>|string[],
|
tView: TView, lView: LView, predicate: Type<any>|InjectionToken<unknown>|string[],
|
||||||
descend: boolean, read: any, isStatic: boolean, tNode: TNode, directiveIndex: number): void {
|
flags: QueryFlags, read: any, isStatic: boolean, tNode: TNode, directiveIndex: number): void {
|
||||||
if (tView.firstCreatePass) {
|
if (tView.firstCreatePass) {
|
||||||
createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), tNode.index);
|
createTQuery(tView, new TQueryMetadata_(predicate, flags, read), tNode.index);
|
||||||
saveContentQueryAndDirectiveIndex(tView, directiveIndex);
|
saveContentQueryAndDirectiveIndex(tView, directiveIndex);
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
tView.staticContentQueries = true;
|
tView.staticContentQueries = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createLQuery<T>(tView, lView);
|
createLQuery<T>(tView, lView, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -551,8 +557,9 @@ function loadQueryInternal<T>(lView: LView, queryIndex: number): QueryList<T> {
|
||||||
return lView[QUERIES]!.queries[queryIndex].queryList;
|
return lView[QUERIES]!.queries[queryIndex].queryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLQuery<T>(tView: TView, lView: LView) {
|
function createLQuery<T>(tView: TView, lView: LView, flags: QueryFlags) {
|
||||||
const queryList = new QueryList<T>();
|
const queryList = new QueryList<T>(
|
||||||
|
(flags & QueryFlags.emitDistinctChangesOnly) === QueryFlags.emitDistinctChangesOnly);
|
||||||
storeCleanupWithContext(tView, lView, queryList, queryList.destroy);
|
storeCleanupWithContext(tView, lView, queryList, queryList.destroy);
|
||||||
|
|
||||||
if (lView[QUERIES] === null) lView[QUERIES] = new LQueries_();
|
if (lView[QUERIES] === null) lView[QUERIES] = new LQueries_();
|
||||||
|
|
|
@ -20,6 +20,31 @@ export function addAllToArray(items: any[], arr: any[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the contents of two arrays is identical
|
||||||
|
*
|
||||||
|
* @param a first array
|
||||||
|
* @param b second array
|
||||||
|
* @param identityAccessor Optional functions for extracting stable object identity from a value in
|
||||||
|
* the array.
|
||||||
|
*/
|
||||||
|
export function arrayEquals<T>(a: T[], b: T[], identityAccessor?: (value: T) => unknown): boolean {
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
let valueA = a[i];
|
||||||
|
let valueB = b[i];
|
||||||
|
if (identityAccessor) {
|
||||||
|
valueA = identityAccessor(valueA) as any;
|
||||||
|
valueB = identityAccessor(valueB) as any;
|
||||||
|
}
|
||||||
|
if (valueB !== valueA) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flattens an array.
|
* Flattens an array.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ElementRef} from '../linker/element_ref';
|
import {ElementRef, unwrapElementRef} from '../linker/element_ref';
|
||||||
import {QueryList} from '../linker/query_list';
|
import {QueryList} from '../linker/query_list';
|
||||||
|
|
||||||
import {asElementData, asProviderData, asQueryList, NodeDef, NodeFlags, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData} from './types';
|
import {asElementData, asProviderData, asQueryList, NodeDef, NodeFlags, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData} from './types';
|
||||||
|
@ -50,8 +50,8 @@ export function queryDef(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createQuery(): QueryList<any> {
|
export function createQuery(emitDistinctChangesOnly: boolean): QueryList<any> {
|
||||||
return new QueryList();
|
return new QueryList(emitDistinctChangesOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dirtyParentQueries(view: ViewData) {
|
export function dirtyParentQueries(view: ViewData) {
|
||||||
|
@ -107,7 +107,7 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) {
|
||||||
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query!, []);
|
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query!, []);
|
||||||
directiveInstance = view.component;
|
directiveInstance = view.component;
|
||||||
}
|
}
|
||||||
queryList.reset(newValues);
|
queryList.reset(newValues, unwrapElementRef);
|
||||||
const bindings = nodeDef.query!.bindings;
|
const bindings = nodeDef.query!.bindings;
|
||||||
let notify = false;
|
let notify = false;
|
||||||
for (let i = 0; i < bindings.length; i++) {
|
for (let i = 0; i < bindings.length; i++) {
|
||||||
|
|
|
@ -209,6 +209,7 @@ export const enum NodeFlags {
|
||||||
StaticQuery = 1 << 28,
|
StaticQuery = 1 << 28,
|
||||||
DynamicQuery = 1 << 29,
|
DynamicQuery = 1 << 29,
|
||||||
TypeNgModule = 1 << 30,
|
TypeNgModule = 1 << 30,
|
||||||
|
EmitDistinctChangesOnly = 1 << 31,
|
||||||
CatQuery = TypeContentQuery | TypeViewQuery,
|
CatQuery = TypeContentQuery | TypeViewQuery,
|
||||||
|
|
||||||
// mutually exclusive values...
|
// mutually exclusive values...
|
||||||
|
|
|
@ -327,7 +327,9 @@ function createViewNodes(view: ViewData) {
|
||||||
break;
|
break;
|
||||||
case NodeFlags.TypeContentQuery:
|
case NodeFlags.TypeContentQuery:
|
||||||
case NodeFlags.TypeViewQuery:
|
case NodeFlags.TypeViewQuery:
|
||||||
nodeData = createQuery() as any;
|
nodeData = createQuery(
|
||||||
|
(nodeDef.flags & NodeFlags.EmitDistinctChangesOnly) ===
|
||||||
|
NodeFlags.EmitDistinctChangesOnly) as any;
|
||||||
break;
|
break;
|
||||||
case NodeFlags.TypeNgContent:
|
case NodeFlags.TypeNgContent:
|
||||||
appendNgContent(view, renderHost, nodeDef);
|
appendNgContent(view, renderHost, nodeDef);
|
||||||
|
|
|
@ -1123,6 +1123,46 @@ describe('query logic', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(changes).toBe(1);
|
expect(changes).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should only fire if the content of the query changes', () => {
|
||||||
|
// When views are inserted/removed the content query need to be recomputed.
|
||||||
|
// Recomputing the query may result in no changes to the query (the item added/removed was
|
||||||
|
// not part of the query). This tests asserts that the query does not fire when no changes
|
||||||
|
// occur.
|
||||||
|
TestBed.configureTestingModule(
|
||||||
|
{declarations: [QueryCompWithStrictChangeEmitParent, QueryCompWithNoChanges]});
|
||||||
|
const fixture = TestBed.createComponent(QueryCompWithNoChanges);
|
||||||
|
let changesStrict = 0;
|
||||||
|
const componentInstance = fixture.componentInstance.queryComp;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
componentInstance.foos.changes.subscribe((value: any) => {
|
||||||
|
// subscribe to the changes and record when changes occur.
|
||||||
|
changesStrict += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// First verify that the subscription is working.
|
||||||
|
fixture.componentInstance.innerShowing = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(changesStrict).toBe(1); // We detected a change
|
||||||
|
expect(componentInstance.foos.toArray().length).toEqual(1);
|
||||||
|
|
||||||
|
|
||||||
|
// now verify that removing a view does not needlessly fire subscription
|
||||||
|
fixture.componentInstance.showing = false;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(changesStrict).toBe(1); // We detected a change
|
||||||
|
expect(componentInstance.foos.toArray().length).toEqual(1);
|
||||||
|
|
||||||
|
// now verify that adding a view does not needlessly fire subscription
|
||||||
|
fixture.componentInstance.showing = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(changesStrict).toBe(1); // We detected a change
|
||||||
|
// Note: even though the `showing` is `true` and the second `<div>` is displayed, the
|
||||||
|
// child element of that <div> is hidden because the `innerShowing` flag is still `false`,
|
||||||
|
// so we expect only one element to be present in the `foos` array.
|
||||||
|
expect(componentInstance.foos.toArray().length).toEqual(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('view boundaries', () => {
|
describe('view boundaries', () => {
|
||||||
|
@ -1219,7 +1259,7 @@ describe('query logic', () => {
|
||||||
* - detect the situation where the indexes are the same and do no processing in such case.
|
* - detect the situation where the indexes are the same and do no processing in such case.
|
||||||
*
|
*
|
||||||
* This tests asserts on the implementation choices done by the VE (detach and insert) so we
|
* This tests asserts on the implementation choices done by the VE (detach and insert) so we
|
||||||
* can replicate the same behaviour in ivy.
|
* can replicate the same behavior in ivy.
|
||||||
*/
|
*/
|
||||||
it('should notify on changes when a given view is removed and re-inserted at the same index',
|
it('should notify on changes when a given view is removed and re-inserted at the same index',
|
||||||
() => {
|
() => {
|
||||||
|
@ -1964,6 +2004,37 @@ export class QueryCompWithChanges {
|
||||||
showing = false;
|
showing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'query-with-no-changes',
|
||||||
|
template: `
|
||||||
|
<query-component>
|
||||||
|
<div *ngIf="true" #foo></div>
|
||||||
|
<div *ngIf="showing">
|
||||||
|
Showing me should not change the content of the query
|
||||||
|
<div *ngIf="innerShowing" #foo></div>
|
||||||
|
</div>
|
||||||
|
</query-component>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class QueryCompWithNoChanges {
|
||||||
|
showing: boolean = true;
|
||||||
|
innerShowing: boolean = true;
|
||||||
|
queryComp!: QueryCompWithStrictChangeEmitParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'query-component', template: `<ng-content></ng-content>`})
|
||||||
|
export class QueryCompWithStrictChangeEmitParent {
|
||||||
|
@ContentChildren('foo', {
|
||||||
|
descendants: true,
|
||||||
|
emitDistinctChangesOnly: true,
|
||||||
|
})
|
||||||
|
foos!: QueryList<any>;
|
||||||
|
|
||||||
|
constructor(public queryCompWithNoChanges: QueryCompWithNoChanges) {
|
||||||
|
queryCompWithNoChanges.queryComp = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({selector: 'query-target', template: '<ng-content></ng-content>'})
|
@Component({selector: 'query-target', template: '<ng-content></ng-content>'})
|
||||||
class SuperDirectiveQueryTarget {
|
class SuperDirectiveQueryTarget {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1982,6 +1982,9 @@
|
||||||
{
|
{
|
||||||
"name": "u"
|
"name": "u"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "unwrapElementRef"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "unwrapRNode"
|
"name": "unwrapRNode"
|
||||||
},
|
},
|
||||||
|
|
|
@ -121,22 +121,24 @@ describe('component declaration jit compilation', () => {
|
||||||
static: true,
|
static: true,
|
||||||
first: true,
|
first: true,
|
||||||
read: ElementRef,
|
read: ElementRef,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}) as ComponentDef<TestClass>;
|
}) as ComponentDef<TestClass>;
|
||||||
|
|
||||||
expectComponentDef(def, {
|
expectComponentDef(def, {
|
||||||
contentQueries: functionContaining([
|
contentQueries: functionContaining([
|
||||||
// "byRef" should use `contentQuery` with `false` for descendants flag without a read token,
|
// "byRef" should use `contentQuery` with `0` (`QueryFlags.none`) for descendants flag
|
||||||
// and bind to the full query result.
|
// without a read token, and bind to the full query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:contentQuery|anonymous)[^(]*\(dirIndex,_c0,false\)/,
|
/(?:contentQuery|anonymous)[^(]*\(dirIndex,_c0,4\)/,
|
||||||
'(ctx.byRef = _t)',
|
'(ctx.byRef = _t)',
|
||||||
|
|
||||||
// "byToken" should use `staticContentQuery` with `true` for descendants flag and
|
// "byToken" should use `staticContentQuery` with `3`
|
||||||
// `ElementRef` as read token, and bind to the first result in the query result.
|
// (`QueryFlags.descendants|QueryFlags.isStatic`) for descendants flag and `ElementRef` as
|
||||||
|
// read token, and bind to the first result in the query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:staticContentQuery|anonymous)[^(]*\(dirIndex,[^,]*String[^,]*,true,[^)]*ElementRef[^)]*\)/,
|
/(?:contentQuery|anonymous)[^(]*\(dirIndex,[^,]*String[^,]*,3,[^)]*ElementRef[^)]*\)/,
|
||||||
'(ctx.byToken = _t.first)',
|
'(ctx.byToken = _t.first)',
|
||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
@ -158,22 +160,24 @@ describe('component declaration jit compilation', () => {
|
||||||
static: true,
|
static: true,
|
||||||
first: true,
|
first: true,
|
||||||
read: ElementRef,
|
read: ElementRef,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}) as ComponentDef<TestClass>;
|
}) as ComponentDef<TestClass>;
|
||||||
|
|
||||||
expectComponentDef(def, {
|
expectComponentDef(def, {
|
||||||
viewQuery: functionContaining([
|
viewQuery: functionContaining([
|
||||||
// "byRef" should use `viewQuery` with `false` for descendants flag without a read token,
|
// "byRef" should use `viewQuery` with `0` (`QueryFlags.none`) for query flag without a read
|
||||||
// and bind to the full query result.
|
// token, and bind to the full query result. NOTE: the `anonymous` match is to support IE11,
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// as functions don't have a name there.
|
||||||
/(?:viewQuery|anonymous)[^(]*\(_c0,false\)/,
|
/(?:viewQuery|anonymous)[^(]*\(_c0,4\)/,
|
||||||
'(ctx.byRef = _t)',
|
'(ctx.byRef = _t)',
|
||||||
|
|
||||||
// "byToken" should use `staticViewQuery` with `true` for descendants flag and
|
// "byToken" should use `viewQuery` with `3`
|
||||||
// `ElementRef` as read token, and bind to the first result in the query result.
|
// (`QueryFlags.descendants|QueryFlags.isStatic`) for descendants flag and `ElementRef` as
|
||||||
|
// read token, and bind to the first result in the query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:staticViewQuery|anonymous)[^(]*\([^,]*String[^,]*,true,[^)]*ElementRef[^)]*\)/,
|
/(?:viewQuery|anonymous)[^(]*\([^,]*String[^,]*,3,[^)]*ElementRef[^)]*\)/,
|
||||||
'(ctx.byToken = _t.first)',
|
'(ctx.byToken = _t.first)',
|
||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
|
|
@ -95,22 +95,24 @@ describe('directive declaration jit compilation', () => {
|
||||||
static: true,
|
static: true,
|
||||||
first: true,
|
first: true,
|
||||||
read: ElementRef,
|
read: ElementRef,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}) as DirectiveDef<TestClass>;
|
}) as DirectiveDef<TestClass>;
|
||||||
|
|
||||||
expectDirectiveDef(def, {
|
expectDirectiveDef(def, {
|
||||||
contentQueries: functionContaining([
|
contentQueries: functionContaining([
|
||||||
// "byRef" should use `contentQuery` with `false` for descendants flag without a read token,
|
// "byRef" should use `contentQuery` with `0` (`QueryFlags.descendants|QueryFlags.isStatic`)
|
||||||
// and bind to the full query result.
|
// for descendants flag without a read token, and bind to the full query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:contentQuery|anonymous)[^(]*\(dirIndex,_c0,false\)/,
|
/(?:contentQuery|anonymous)[^(]*\(dirIndex,_c0,4\)/,
|
||||||
'(ctx.byRef = _t)',
|
'(ctx.byRef = _t)',
|
||||||
|
|
||||||
// "byToken" should use `staticContentQuery` with `true` for descendants flag and
|
// "byToken" should use `viewQuery` with `3` (`QueryFlags.static|QueryFlags.descendants`)
|
||||||
// `ElementRef` as read token, and bind to the first result in the query result.
|
// for descendants flag and `ElementRef` as read token, and bind to the first result in the
|
||||||
|
// query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:staticContentQuery|anonymous)[^(]*\(dirIndex,[^,]*String[^,]*,true,[^)]*ElementRef[^)]*\)/,
|
/(?:contentQuery|anonymous)[^(]*\([^,]*dirIndex,[^,]*String[^,]*,3,[^)]*ElementRef[^)]*\)/,
|
||||||
'(ctx.byToken = _t.first)',
|
'(ctx.byToken = _t.first)',
|
||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
@ -131,6 +133,7 @@ describe('directive declaration jit compilation', () => {
|
||||||
static: true,
|
static: true,
|
||||||
first: true,
|
first: true,
|
||||||
read: ElementRef,
|
read: ElementRef,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}) as DirectiveDef<TestClass>;
|
}) as DirectiveDef<TestClass>;
|
||||||
|
@ -140,13 +143,14 @@ describe('directive declaration jit compilation', () => {
|
||||||
// "byRef" should use `viewQuery` with `false` for descendants flag without a read token,
|
// "byRef" should use `viewQuery` with `false` for descendants flag without a read token,
|
||||||
// and bind to the full query result.
|
// and bind to the full query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:viewQuery|anonymous)[^(]*\(_c0,false\)/,
|
/(?:viewQuery|anonymous)[^(]*\(_c0,4\)/,
|
||||||
'(ctx.byRef = _t)',
|
'(ctx.byRef = _t)',
|
||||||
|
|
||||||
// "byToken" should use `staticViewQuery` with `true` for descendants flag and
|
// "byToken" should use `viewQuery` with `3` (`QueryFlags.static|QueryFlags.descendants`)
|
||||||
// `ElementRef` as read token, and bind to the first result in the query result.
|
// for descendants flag and `ElementRef` as read token, and bind to the first result in the
|
||||||
|
// query result.
|
||||||
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
// NOTE: the `anonymous` match is to support IE11, as functions don't have a name there.
|
||||||
/(?:staticViewQuery|anonymous)[^(]*\([^,]*String[^,]*,true,[^)]*ElementRef[^)]*\)/,
|
/(?:viewQuery|anonymous)[^(]*\([^,]*String[^,]*,3,[^)]*ElementRef[^)]*\)/,
|
||||||
'(ctx.byToken = _t.first)',
|
'(ctx.byToken = _t.first)',
|
||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,13 +51,15 @@ describe('jit directive helper functions', () => {
|
||||||
isViewQuery: false,
|
isViewQuery: false,
|
||||||
read: undefined,
|
read: undefined,
|
||||||
static: false,
|
static: false,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
})).toEqual({
|
})).toEqual({
|
||||||
propertyName: 'propName',
|
propertyName: 'propName',
|
||||||
predicate: ['localRef'],
|
predicate: ['localRef'],
|
||||||
descendants: false,
|
descendants: false,
|
||||||
first: false,
|
first: false,
|
||||||
read: null,
|
read: null,
|
||||||
static: false
|
static: false,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,13 +71,15 @@ describe('jit directive helper functions', () => {
|
||||||
isViewQuery: true,
|
isViewQuery: true,
|
||||||
read: undefined,
|
read: undefined,
|
||||||
static: false,
|
static: false,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
})).toEqual({
|
})).toEqual({
|
||||||
propertyName: 'propName',
|
propertyName: 'propName',
|
||||||
predicate: ['foo', 'bar', 'baz'],
|
predicate: ['foo', 'bar', 'baz'],
|
||||||
descendants: true,
|
descendants: true,
|
||||||
first: true,
|
first: true,
|
||||||
read: null,
|
read: null,
|
||||||
static: false
|
static: false,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -88,7 +92,8 @@ describe('jit directive helper functions', () => {
|
||||||
first: true,
|
first: true,
|
||||||
isViewQuery: true,
|
isViewQuery: true,
|
||||||
read: Directive,
|
read: Directive,
|
||||||
static: false
|
static: false,
|
||||||
|
emitDistinctChangesOnly: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(converted.predicate).toEqual(Directive);
|
expect(converted.predicate).toEqual(Directive);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
|
import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||||
|
import {QueryFlags} from '@angular/core/src/render3/interfaces/query';
|
||||||
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
||||||
|
|
||||||
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index';
|
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index';
|
||||||
|
@ -80,8 +81,8 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(Child, false);
|
ɵɵviewQuery(Child, QueryFlags.none);
|
||||||
ɵɵviewQuery(Child, true);
|
ɵɵviewQuery(Child, QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -119,7 +120,7 @@ describe('query', () => {
|
||||||
1, 0, [Child], [],
|
1, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(Child, false, ElementRef);
|
ɵɵviewQuery(Child, QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -158,7 +159,7 @@ describe('query', () => {
|
||||||
1, 0, [Child, OtherChild], [],
|
1, 0, [Child, OtherChild], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(Child, false, OtherChild);
|
ɵɵviewQuery(Child, QueryFlags.none, OtherChild);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -193,7 +194,7 @@ describe('query', () => {
|
||||||
1, 0, [Child, OtherChild], [],
|
1, 0, [Child, OtherChild], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(Child, false, OtherChild);
|
ɵɵviewQuery(Child, QueryFlags.none, OtherChild);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -263,9 +264,9 @@ describe('query', () => {
|
||||||
viewQuery:
|
viewQuery:
|
||||||
function(rf: RenderFlags, ctx: App) {
|
function(rf: RenderFlags, ctx: App) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(MyDirective, false);
|
ɵɵviewQuery(MyDirective, QueryFlags.none);
|
||||||
ɵɵviewQuery(Service, false);
|
ɵɵviewQuery(Service, QueryFlags.none);
|
||||||
ɵɵviewQuery(Alias, false);
|
ɵɵviewQuery(Alias, QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -315,7 +316,7 @@ describe('query', () => {
|
||||||
function(rf: RenderFlags, ctx: App) {
|
function(rf: RenderFlags, ctx: App) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(MyDirective, false, Alias);
|
ɵɵviewQuery(MyDirective, QueryFlags.none, Alias);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) &&
|
ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) &&
|
||||||
|
@ -353,7 +354,7 @@ describe('query', () => {
|
||||||
3, 0, [], [],
|
3, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false);
|
ɵɵviewQuery(['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -392,8 +393,8 @@ describe('query', () => {
|
||||||
4, 0, [], [],
|
4, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false);
|
ɵɵviewQuery(['foo'], QueryFlags.none);
|
||||||
ɵɵviewQuery(['bar'], false);
|
ɵɵviewQuery(['bar'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -441,7 +442,7 @@ describe('query', () => {
|
||||||
5, 0, [], [],
|
5, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo', 'bar'], false);
|
ɵɵviewQuery(['foo', 'bar'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -479,7 +480,7 @@ describe('query', () => {
|
||||||
3, 0, [], [],
|
3, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false);
|
ɵɵviewQuery(['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -517,7 +518,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, ElementRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -554,7 +555,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -588,7 +589,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, ViewContainerRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, ViewContainerRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -621,7 +622,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, ViewContainerRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, ViewContainerRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -655,7 +656,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, ElementRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -690,7 +691,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false);
|
ɵɵviewQuery(['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -724,7 +725,7 @@ describe('query', () => {
|
||||||
2, 0, [], [],
|
2, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, TemplateRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, TemplateRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -763,7 +764,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -810,7 +811,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -850,7 +851,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -891,7 +892,7 @@ describe('query', () => {
|
||||||
3, 0, [Child1, Child2], [],
|
3, 0, [Child1, Child2], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo', 'bar'], true);
|
ɵɵviewQuery(['foo', 'bar'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -932,8 +933,8 @@ describe('query', () => {
|
||||||
3, 0, [Child], [],
|
3, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
ɵɵviewQuery(['bar'], true);
|
ɵɵviewQuery(['bar'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -977,7 +978,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, ElementRef);
|
ɵɵviewQuery(['foo'], QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1017,7 +1018,7 @@ describe('query', () => {
|
||||||
3, 0, [Child], [],
|
3, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo', 'bar'], false);
|
ɵɵviewQuery(['foo', 'bar'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1053,7 +1054,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, Child);
|
ɵɵviewQuery(['foo'], QueryFlags.none, Child);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1088,7 +1089,7 @@ describe('query', () => {
|
||||||
1, 0, [Child, OtherChild], [],
|
1, 0, [Child, OtherChild], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(Child, false, OtherChild);
|
ɵɵviewQuery(Child, QueryFlags.none, OtherChild);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1123,7 +1124,7 @@ describe('query', () => {
|
||||||
1, 0, [Child, OtherChild], [],
|
1, 0, [Child, OtherChild], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(OtherChild, false, Child);
|
ɵɵviewQuery(OtherChild, QueryFlags.none, Child);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1155,7 +1156,7 @@ describe('query', () => {
|
||||||
1, 0, [], [],
|
1, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(TemplateRef as any, false, ElementRef);
|
ɵɵviewQuery(TemplateRef as any, QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1188,7 +1189,7 @@ describe('query', () => {
|
||||||
2, 0, [Child], [],
|
2, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], false, Child);
|
ɵɵviewQuery(['foo'], QueryFlags.none, Child);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1223,7 +1224,7 @@ describe('query', () => {
|
||||||
1, 0, [Child], [],
|
1, 0, [Child], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(TemplateRef as any, false);
|
ɵɵviewQuery(TemplateRef as any, QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1270,8 +1271,8 @@ describe('query', () => {
|
||||||
6, 0, [], [],
|
6, 0, [], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(TemplateRef as any, false);
|
ɵɵviewQuery(TemplateRef as any, QueryFlags.none);
|
||||||
ɵɵviewQuery(TemplateRef as any, false, ElementRef);
|
ɵɵviewQuery(TemplateRef as any, QueryFlags.none, ElementRef);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1334,7 +1335,7 @@ describe('query', () => {
|
||||||
3, 0, [SomeDir], [],
|
3, 0, [SomeDir], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1376,7 +1377,7 @@ describe('query', () => {
|
||||||
contentQueries:
|
contentQueries:
|
||||||
(rf: RenderFlags, ctx: any, dirIndex: number) => {
|
(rf: RenderFlags, ctx: any, dirIndex: number) => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo'], true);
|
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1463,7 +1464,7 @@ describe('query', () => {
|
||||||
5, 0, [WithContentDirective], [],
|
5, 0, [WithContentDirective], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo', 'bar'], true);
|
ɵɵviewQuery(['foo', 'bar'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1505,7 +1506,7 @@ describe('query', () => {
|
||||||
5, 0, [WithContentDirective], [],
|
5, 0, [WithContentDirective], [],
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['bar'], true);
|
ɵɵviewQuery(['bar'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1533,7 +1534,7 @@ describe('query', () => {
|
||||||
// @ContentChildren('foo, bar, baz', {descendants: true})
|
// @ContentChildren('foo, bar, baz', {descendants: true})
|
||||||
// fooBars: QueryList<ElementRef>;
|
// fooBars: QueryList<ElementRef>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo', 'bar', 'baz'], true);
|
ɵɵcontentQuery(dirIndex, ['foo', 'bar', 'baz'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1602,7 +1603,7 @@ describe('query', () => {
|
||||||
// @ContentChildren('foo', {descendants: true})
|
// @ContentChildren('foo', {descendants: true})
|
||||||
// fooBars: QueryList<ElementRef>;
|
// fooBars: QueryList<ElementRef>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo'], false);
|
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1662,7 +1663,7 @@ describe('query', () => {
|
||||||
// @ContentChildren('foo', {descendants: true})
|
// @ContentChildren('foo', {descendants: true})
|
||||||
// fooBars: QueryList<ElementRef>;
|
// fooBars: QueryList<ElementRef>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo'], false);
|
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1726,7 +1727,7 @@ describe('query', () => {
|
||||||
// @ContentChildren('foo', {descendants: false})
|
// @ContentChildren('foo', {descendants: false})
|
||||||
// foos: QueryList<ElementRef>;
|
// foos: QueryList<ElementRef>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo'], false);
|
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1748,7 +1749,7 @@ describe('query', () => {
|
||||||
// @ContentChildren('foo', {descendants: true})
|
// @ContentChildren('foo', {descendants: true})
|
||||||
// foos: QueryList<ElementRef>;
|
// foos: QueryList<ElementRef>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, ['foo'], true);
|
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1824,7 +1825,7 @@ describe('query', () => {
|
||||||
// @ContentChildren(TextDirective, {descendants: true})
|
// @ContentChildren(TextDirective, {descendants: true})
|
||||||
// texts: QueryList<TextDirective>;
|
// texts: QueryList<TextDirective>;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵcontentQuery(dirIndex, TextDirective, true);
|
ɵɵcontentQuery(dirIndex, TextDirective, QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
@ -1910,7 +1911,7 @@ describe('query', () => {
|
||||||
function(rf: RenderFlags, ctx: ViewQueryComponent) {
|
function(rf: RenderFlags, ctx: ViewQueryComponent) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(TextDirective, true);
|
ɵɵviewQuery(TextDirective, QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<TextDirective>>()) &&
|
ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<TextDirective>>()) &&
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {QueryFlags} from '@angular/core/src/render3/interfaces/query';
|
||||||
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
||||||
import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ElementRef, QueryList, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core';
|
import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ElementRef, QueryList, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core';
|
||||||
import {ViewEncapsulation} from '../../src/metadata';
|
import {ViewEncapsulation} from '../../src/metadata';
|
||||||
|
@ -368,7 +369,7 @@ describe('ViewContainerRef', () => {
|
||||||
viewQuery:
|
viewQuery:
|
||||||
function(rf: RenderFlags, ctx: any) {
|
function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
ɵɵviewQuery(['foo'], true);
|
ɵɵviewQuery(['foo'], QueryFlags.descendants);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
|
|
Loading…
Reference in New Issue