feat(ivy): add query inheritance (#25556)
Adds inheritance handling for the following: - viewQuery - contentQueries - contentQueriesRefresh PR Close #25556
This commit is contained in:
parent
c8b70ae8e4
commit
f54f3856cb
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
import {Type} from '../../type';
|
import {Type} from '../../type';
|
||||||
import {fillProperties} from '../../util/property';
|
import {fillProperties} from '../../util/property';
|
||||||
import {ComponentDefInternal, DirectiveDefFeature, DirectiveDefInternal} from '../interfaces/definition';
|
import {ComponentDefInternal, ComponentTemplate, DirectiveDefFeature, DirectiveDefInternal, RenderFlags} from '../interfaces/definition';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,6 +69,51 @@ export function InheritDefinitionFeature(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge View Queries
|
||||||
|
if (isComponentDef(definition) && isComponentDef(superDef)) {
|
||||||
|
const prevViewQuery = definition.viewQuery;
|
||||||
|
const superViewQuery = superDef.viewQuery;
|
||||||
|
if (superViewQuery) {
|
||||||
|
if (prevViewQuery) {
|
||||||
|
definition.viewQuery = <T>(rf: RenderFlags, ctx: T): void => {
|
||||||
|
superViewQuery(rf, ctx);
|
||||||
|
prevViewQuery(rf, ctx);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
definition.viewQuery = superViewQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge Content Queries
|
||||||
|
const prevContentQueries = definition.contentQueries;
|
||||||
|
const superContentQueries = superDef.contentQueries;
|
||||||
|
if (superContentQueries) {
|
||||||
|
if (prevContentQueries) {
|
||||||
|
definition.contentQueries = () => {
|
||||||
|
superContentQueries();
|
||||||
|
prevContentQueries();
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
definition.contentQueries = superContentQueries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge Content Queries Refresh
|
||||||
|
const prevContentQueriesRefresh = definition.contentQueriesRefresh;
|
||||||
|
const superContentQueriesRefresh = superDef.contentQueriesRefresh;
|
||||||
|
if (superContentQueriesRefresh) {
|
||||||
|
if (prevContentQueriesRefresh) {
|
||||||
|
definition.contentQueriesRefresh = (directiveIndex: number, queryIndex: number) => {
|
||||||
|
superContentQueriesRefresh(directiveIndex, queryIndex);
|
||||||
|
prevContentQueriesRefresh(directiveIndex, queryIndex);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
definition.contentQueriesRefresh = superContentQueriesRefresh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Merge inputs and outputs
|
// Merge inputs and outputs
|
||||||
fillProperties(definition.inputs, superDef.inputs);
|
fillProperties(definition.inputs, superDef.inputs);
|
||||||
fillProperties(definition.declaredInputs, superDef.declaredInputs);
|
fillProperties(definition.declaredInputs, superDef.declaredInputs);
|
||||||
|
|
|
@ -221,7 +221,7 @@ export interface ComponentDef<T, Selector extends string> extends DirectiveDef<T
|
||||||
/**
|
/**
|
||||||
* Query-related instructions for a component.
|
* Query-related instructions for a component.
|
||||||
*/
|
*/
|
||||||
readonly viewQuery: ComponentQuery<T>|null;
|
viewQuery: ComponentQuery<T>|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The view encapsulation type, which determines how styles are applied to
|
* The view encapsulation type, which determines how styles are applied to
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import {EventEmitter, Output} from '../../src/core';
|
import {EventEmitter, Output} from '../../src/core';
|
||||||
import {InheritDefinitionFeature} from '../../src/render3/features/inherit_definition_feature';
|
import {InheritDefinitionFeature} from '../../src/render3/features/inherit_definition_feature';
|
||||||
import {DirectiveDefInternal, defineBase, defineComponent, defineDirective} from '../../src/render3/index';
|
import {ComponentDefInternal, DirectiveDefInternal, RenderFlags, defineBase, defineComponent, defineDirective} from '../../src/render3/index';
|
||||||
|
|
||||||
describe('InheritDefinitionFeature', () => {
|
describe('InheritDefinitionFeature', () => {
|
||||||
it('should inherit lifecycle hooks', () => {
|
it('should inherit lifecycle hooks', () => {
|
||||||
|
@ -48,7 +48,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inherit inputs', () => {
|
it('should inherit inputs', () => {
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SuperDirective {
|
class SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
inputs: {
|
inputs: {
|
||||||
|
@ -62,7 +61,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SubDirective extends SuperDirective {
|
class SubDirective extends SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
|
@ -93,7 +91,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should inherit outputs', () => {
|
it('should inherit outputs', () => {
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SuperDirective {
|
class SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
outputs: {
|
outputs: {
|
||||||
|
@ -107,7 +104,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SubDirective extends SuperDirective {
|
class SubDirective extends SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
|
@ -143,7 +139,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class Class4 extends Class5 {
|
class Class4 extends Class5 {
|
||||||
input4 = 'hehe';
|
input4 = 'hehe';
|
||||||
|
|
||||||
|
@ -170,7 +165,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
}) as any;
|
}) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class Class1 extends Class2 {
|
class Class1 extends Class2 {
|
||||||
input1 = 'test';
|
input1 = 'test';
|
||||||
input2 = 'whatever';
|
input2 = 'whatever';
|
||||||
|
@ -217,7 +211,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class Class4 extends Class5 {
|
class Class4 extends Class5 {
|
||||||
output4 = 'hehe';
|
output4 = 'hehe';
|
||||||
|
|
||||||
|
@ -244,7 +237,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
}) as any;
|
}) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class Class1 extends Class2 {
|
class Class1 extends Class2 {
|
||||||
output1 = 'test';
|
output1 = 'test';
|
||||||
output2 = 'whatever';
|
output2 = 'whatever';
|
||||||
|
@ -275,7 +267,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
it('should compose hostBindings', () => {
|
it('should compose hostBindings', () => {
|
||||||
const log: Array<[string, number, number]> = [];
|
const log: Array<[string, number, number]> = [];
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SuperDirective {
|
class SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SuperDirective,
|
type: SuperDirective,
|
||||||
|
@ -287,7 +278,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SubDirective extends SuperDirective {
|
class SubDirective extends SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
|
@ -307,8 +297,110 @@ describe('InheritDefinitionFeature', () => {
|
||||||
expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
|
expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should compose viewQuery', () => {
|
||||||
|
const log: Array<[string, RenderFlags, any]> = [];
|
||||||
|
|
||||||
|
class SuperComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: SuperComponent,
|
||||||
|
template: () => {},
|
||||||
|
consts: 0,
|
||||||
|
vars: 0,
|
||||||
|
selectors: [['', 'superDir', '']],
|
||||||
|
viewQuery: <T>(rf: RenderFlags, ctx: T) => {
|
||||||
|
log.push(['super', rf, ctx]);
|
||||||
|
},
|
||||||
|
factory: () => new SuperComponent(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubComponent extends SuperComponent {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: SubComponent,
|
||||||
|
template: () => {},
|
||||||
|
consts: 0,
|
||||||
|
vars: 0,
|
||||||
|
selectors: [['', 'subDir', '']],
|
||||||
|
viewQuery: (directiveIndex: number, elementIndex: number) => {
|
||||||
|
log.push(['sub', directiveIndex, elementIndex]);
|
||||||
|
},
|
||||||
|
factory: () => new SubComponent(),
|
||||||
|
features: [InheritDefinitionFeature]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subDef = SubComponent.ngComponentDef as ComponentDefInternal<any>;
|
||||||
|
|
||||||
|
const context = {foo: 'bar'};
|
||||||
|
|
||||||
|
subDef.viewQuery !(1, context);
|
||||||
|
|
||||||
|
expect(log).toEqual([['super', 1, context], ['sub', 1, context]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compose contentQueries', () => {
|
||||||
|
const log: string[] = [];
|
||||||
|
|
||||||
|
class SuperDirective {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SuperDirective,
|
||||||
|
selectors: [['', 'superDir', '']],
|
||||||
|
contentQueries: () => { log.push('super'); },
|
||||||
|
factory: () => new SuperDirective(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubDirective extends SuperDirective {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SubDirective,
|
||||||
|
selectors: [['', 'subDir', '']],
|
||||||
|
contentQueries: () => { log.push('sub'); },
|
||||||
|
factory: () => new SubDirective(),
|
||||||
|
features: [InheritDefinitionFeature]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subDef = SubDirective.ngDirectiveDef as DirectiveDefInternal<any>;
|
||||||
|
|
||||||
|
subDef.contentQueries !();
|
||||||
|
|
||||||
|
expect(log).toEqual(['super', 'sub']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compose contentQueriesRefresh', () => {
|
||||||
|
const log: Array<[string, number, number]> = [];
|
||||||
|
|
||||||
|
class SuperDirective {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SuperDirective,
|
||||||
|
selectors: [['', 'superDir', '']],
|
||||||
|
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
|
||||||
|
log.push(['super', directiveIndex, queryIndex]);
|
||||||
|
},
|
||||||
|
factory: () => new SuperDirective(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubDirective extends SuperDirective {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SubDirective,
|
||||||
|
selectors: [['', 'subDir', '']],
|
||||||
|
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
|
||||||
|
log.push(['sub', directiveIndex, queryIndex]);
|
||||||
|
},
|
||||||
|
factory: () => new SubDirective(),
|
||||||
|
features: [InheritDefinitionFeature]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subDef = SubDirective.ngDirectiveDef as DirectiveDefInternal<any>;
|
||||||
|
|
||||||
|
subDef.contentQueriesRefresh !(1, 2);
|
||||||
|
|
||||||
|
expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw if inheriting a component from a directive', () => {
|
it('should throw if inheriting a component from a directive', () => {
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SuperComponent {
|
class SuperComponent {
|
||||||
static ngComponentDef = defineComponent({
|
static ngComponentDef = defineComponent({
|
||||||
type: SuperComponent,
|
type: SuperComponent,
|
||||||
|
@ -321,7 +413,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SubDirective extends SuperComponent{static ngDirectiveDef = defineDirective({
|
class SubDirective extends SuperComponent{static ngDirectiveDef = defineDirective({
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
selectors: [['', 'subDir', '']],
|
selectors: [['', 'subDir', '']],
|
||||||
|
@ -334,7 +425,6 @@ describe('InheritDefinitionFeature', () => {
|
||||||
it('should run inherited features', () => {
|
it('should run inherited features', () => {
|
||||||
const log: any[] = [];
|
const log: any[] = [];
|
||||||
|
|
||||||
// tslint:disable-next-line:class-as-namespace
|
|
||||||
class SuperDirective {
|
class SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SuperDirective,
|
type: SuperDirective,
|
||||||
|
|
Loading…
Reference in New Issue