.`);
});
// https://stackblitz.com/edit/angular-wlenwd?file=src%2Fapp%2Fapp.component.ts
it('should support view and content queries matching the same element', () => {
/**
*
*
* class Cmpt {
* @ViewChildren('foo, bar') foos;
* }
*/
const AppComponent = createComponent(
'app-component',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0);
{ ɵɵelement(1, 'div', null, 2); }
ɵɵelementEnd();
ɵɵelement(3, 'div', 1, 3);
}
},
5, 0, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵviewQuery(['foo', 'bar'], QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery
>()) &&
(ctx.foos = tmp as QueryList);
}
},
[], [], undefined, [['with-content', ''], ['id', 'after'], ['foo', ''], ['bar', '']]);
const fixture = new ComponentFixture(AppComponent);
const viewQList = fixture.component.foos;
expect(viewQList.length).toBe(2);
expect(withContentInstance!.foos.length).toBe(1);
expect(viewQList.first.nativeElement).toBe(withContentInstance!.foos.first.nativeElement);
expect(viewQList.last.nativeElement.id).toBe('after');
});
it('should not report deep content query matches found above content children', () => {
/**
*
*
<-- should match content query
*
* <-- should not match content query
* class AppComponent {
* @ViewChildren('bar') bars: QueryList;
* }
*/
const AppComponent = createComponent(
'app-component',
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0);
{ ɵɵelement(1, 'div', 1, 2); }
ɵɵelementEnd();
ɵɵelement(3, 'div', null, 2);
}
},
5, 0, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵviewQuery(['bar'], QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) &&
(ctx.bars = tmp as QueryList);
}
},
[], [], undefined, [['with-content', ''], ['id', 'yes'], ['foo', '']]);
const fixture = new ComponentFixture(AppComponent);
expect(withContentInstance!.foos.length).toBe(1);
expect(withContentInstance!.foos.first.nativeElement.id).toEqual('yes');
});
it('should report results to appropriate queries where deep content queries are nested', () => {
class QueryDirective {
fooBars: any;
static ɵfac = () => new QueryDirective();
static ɵdir = ɵɵdefineDirective({
type: QueryDirective,
selectors: [['', 'query', '']],
exportAs: ['query'],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren('foo, bar, baz', {descendants: true})
// fooBars: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, ['foo', 'bar', 'baz'], QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.fooBars = tmp);
}
}
});
}
let outInstance: QueryDirective;
let inInstance: QueryDirective;
const AppComponent = createComponent(
'app-component',
/**
*
*/
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0, 4);
{
ɵɵelement(2, 'span', 1, 5);
ɵɵelementStart(4, 'div', 0, 6);
{ ɵɵelement(6, 'span', 2, 7); }
ɵɵelementEnd();
ɵɵelement(8, 'span', 3, 8);
}
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
const lView = getLView();
outInstance = load(lView, HEADER_OFFSET + 1);
inInstance = load(lView, HEADER_OFFSET + 5);
}
},
10, 0, [QueryDirective], [], null, [], [], undefined, [
[AttributeMarker.Bindings, 'query'], ['id', 'foo'], ['id', 'bar'], ['id', 'baz'],
['out', 'query'], ['foo', ''], ['in', 'query'], ['bar', ''], ['baz', '']
]);
const fixture = new ComponentFixture(AppComponent);
expect(outInstance!.fooBars.length).toBe(3);
expect(inInstance!.fooBars.length).toBe(1);
});
it('should support nested shallow content queries ', () => {
let outInstance: QueryDirective;
let inInstance: QueryDirective;
class QueryDirective {
fooBars: any;
static ɵfac = () => new QueryDirective();
static ɵdir = ɵɵdefineDirective({
type: QueryDirective,
selectors: [['', 'query', '']],
exportAs: ['query'],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren('foo', {descendants: true})
// fooBars: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.fooBars = tmp);
}
}
});
}
const AppComponent = createComponent(
'app-component',
/**
*
*/
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0, 2);
{
ɵɵelementStart(2, 'div', 0, 3);
{ ɵɵelement(5, 'span', 1, 4); }
ɵɵelementEnd();
}
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
const lView = getLView();
outInstance = load(lView, HEADER_OFFSET + 1);
inInstance = load(lView, HEADER_OFFSET + 3);
}
},
7, 0, [QueryDirective], [], null, [], [], undefined, [
['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], ['foo', '']
]);
const fixture = new ComponentFixture(AppComponent);
expect(outInstance!.fooBars.length).toBe(1);
expect(inInstance!.fooBars.length).toBe(1);
});
it('should support nested shallow content queries across multiple component instances', () => {
let outInstance: QueryDirective;
let inInstance: QueryDirective;
class QueryDirective {
fooBars: any;
static ɵfac = () => new QueryDirective();
static ɵdir = ɵɵdefineDirective({
type: QueryDirective,
selectors: [['', 'query', '']],
exportAs: ['query'],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren('foo', {descendants: true})
// fooBars: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.fooBars = tmp);
}
}
});
}
const AppComponent = createComponent(
'app-component',
/**
*
*/
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0, 2);
{
ɵɵelementStart(2, 'div', 0, 3);
{ ɵɵelement(5, 'span', 1, 4); }
ɵɵelementEnd();
}
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
const lView = getLView();
outInstance = load(lView, HEADER_OFFSET + 1);
inInstance = load(lView, HEADER_OFFSET + 3);
}
},
7, 0, [QueryDirective], [], null, [], [], undefined, [
['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], ['foo', '']
]);
const fixture1 = new ComponentFixture(AppComponent);
expect(outInstance!.fooBars.length).toBe(1);
expect(inInstance!.fooBars.length).toBe(1);
outInstance = inInstance = null!;
const fixture2 = new ComponentFixture(AppComponent);
expect(outInstance!.fooBars.length).toBe(1);
expect(inInstance!.fooBars.length).toBe(1);
});
it('should respect shallow flag on content queries when mixing deep and shallow queries',
() => {
class ShallowQueryDirective {
foos: any;
static ɵfac = () => new ShallowQueryDirective();
static ɵdir = ɵɵdefineDirective({
type: ShallowQueryDirective,
selectors: [['', 'shallow-query', '']],
exportAs: ['shallow-query'],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren('foo', {descendants: false})
// foos: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.none);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.foos = tmp);
}
}
});
}
class DeepQueryDirective {
foos: any;
static ɵfac = () => new DeepQueryDirective();
static ɵdir = ɵɵdefineDirective({
type: DeepQueryDirective,
selectors: [['', 'deep-query', '']],
exportAs: ['deep-query'],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren('foo', {descendants: true})
// foos: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, ['foo'], QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.foos = tmp);
}
}
});
}
let shallowInstance: ShallowQueryDirective;
let deepInstance: DeepQueryDirective;
const AppComponent = createComponent(
'app-component',
/**
*
*/
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0, 1);
{
ɵɵelement(3, 'span', null, 2);
ɵɵelementStart(5, 'div');
{ ɵɵelement(6, 'span', null, 2); }
ɵɵelementEnd();
}
ɵɵelementEnd();
}
if (rf & RenderFlags.Update) {
const lView = getLView();
shallowInstance = load(lView, HEADER_OFFSET + 1);
deepInstance = load(lView, HEADER_OFFSET + 2);
}
},
8, 0, [ShallowQueryDirective, DeepQueryDirective], [], null, [], [], undefined, [
[AttributeMarker.Bindings, 'shallow-query', 'deep-query'],
['shallow', 'shallow-query', 'deep', 'deep-query'], ['foo', '']
]);
const fixture = new ComponentFixture(AppComponent);
expect(shallowInstance!.foos.length).toBe(1);
expect(deepInstance!.foos.length).toBe(2);
});
});
describe('order', () => {
class TextDirective {
value!: string;
static ɵfac = () => new TextDirective();
static ɵdir = ɵɵdefineDirective(
{type: TextDirective, selectors: [['', 'text', '']], inputs: {value: 'text'}});
}
it('should register content matches from top to bottom', () => {
let contentQueryDirective: ContentQueryDirective;
class ContentQueryDirective {
// @ContentChildren(TextDirective)
texts!: QueryList;
static ɵfac = () => contentQueryDirective = new ContentQueryDirective();
static ɵcmp = ɵɵdefineDirective({
type: ContentQueryDirective,
selectors: [['', 'content-query', '']],
contentQueries:
(rf: RenderFlags, ctx: any, dirIndex: number) => {
// @ContentChildren(TextDirective, {descendants: true})
// texts: QueryList;
if (rf & RenderFlags.Create) {
ɵɵcontentQuery(dirIndex, TextDirective, QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
let tmp: any;
ɵɵqueryRefresh(tmp = ɵɵloadQuery()) && (ctx.texts = tmp);
}
}
});
}
const AppComponent = createComponent(
'app-component',
/**
*
*/
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
ɵɵelementStart(0, 'div', 0);
{
ɵɵelement(1, 'span', 1);
ɵɵelementStart(2, 'div', 2);
ɵɵelementStart(3, 'span', 3);
{ ɵɵelement(4, 'span', 4); }
ɵɵelementEnd();
ɵɵelementEnd();
ɵɵelement(5, 'span', 5);
}
ɵɵelementEnd();
}
},
6, 0, [TextDirective, ContentQueryDirective], [], null, [], [], undefined, [
['content-query'], ['text', 'A'], ['text', 'B'], ['text', 'C'], ['text', 'D'],
['text', 'E']
]);
new ComponentFixture(AppComponent);
expect(contentQueryDirective!.texts.map(item => item.value)).toEqual([
'A', 'B', 'C', 'D', 'E'
]);
});
it('should register view matches from top to bottom', () => {
/**
*
*
*
*
*
*
*
*/
class ViewQueryComponent {
// @ViewChildren(TextDirective)
texts!: QueryList;
static ɵfac = () => new ViewQueryComponent();
static ɵcmp = ɵɵdefineComponent({
type: ViewQueryComponent,
selectors: [['view-query']],
consts: [['text', 'A'], ['text', 'B'], ['text', 'C'], ['text', 'D'], ['text', 'E']],
template:
function(rf: RenderFlags, ctx: ViewQueryComponent) {
if (rf & RenderFlags.Create) {
ɵɵelement(0, 'span', 0);
ɵɵelementStart(1, 'div', 1);
ɵɵelementStart(2, 'span', 2);
{ ɵɵelement(3, 'span', 3); }
ɵɵelementEnd();
ɵɵelementEnd();
ɵɵelement(4, 'span', 4);
}
},
decls: 5,
vars: 0,
viewQuery:
function(rf: RenderFlags, ctx: ViewQueryComponent) {
let tmp: any;
if (rf & RenderFlags.Create) {
ɵɵviewQuery(TextDirective, QueryFlags.descendants);
}
if (rf & RenderFlags.Update) {
ɵɵqueryRefresh(tmp = ɵɵloadQuery>()) &&
(ctx.texts = tmp as QueryList);
}
},
directives: [TextDirective]
});
}
const fixture = new ComponentFixture(ViewQueryComponent);
expect(fixture.component.texts.map(item => item.value)).toEqual(['A', 'B', 'C', 'D', 'E']);
});
});
});