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 {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
|
||||
fillProperties(definition.inputs, superDef.inputs);
|
||||
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.
|
||||
*/
|
||||
readonly viewQuery: ComponentQuery<T>|null;
|
||||
viewQuery: ComponentQuery<T>|null;
|
||||
|
||||
/**
|
||||
* The view encapsulation type, which determines how styles are applied to
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {EventEmitter, Output} from '../../src/core';
|
||||
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', () => {
|
||||
it('should inherit lifecycle hooks', () => {
|
||||
|
@ -48,7 +48,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
|
||||
it('should inherit inputs', () => {
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
inputs: {
|
||||
|
@ -62,7 +61,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SubDirective extends SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: SubDirective,
|
||||
|
@ -93,7 +91,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
|
||||
it('should inherit outputs', () => {
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
outputs: {
|
||||
|
@ -107,7 +104,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SubDirective extends SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: SubDirective,
|
||||
|
@ -143,7 +139,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class Class4 extends Class5 {
|
||||
input4 = 'hehe';
|
||||
|
||||
|
@ -170,7 +165,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
}) as any;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class Class1 extends Class2 {
|
||||
input1 = 'test';
|
||||
input2 = 'whatever';
|
||||
|
@ -217,7 +211,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class Class4 extends Class5 {
|
||||
output4 = 'hehe';
|
||||
|
||||
|
@ -244,7 +237,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
}) as any;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class Class1 extends Class2 {
|
||||
output1 = 'test';
|
||||
output2 = 'whatever';
|
||||
|
@ -275,7 +267,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
it('should compose hostBindings', () => {
|
||||
const log: Array<[string, number, number]> = [];
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: SuperDirective,
|
||||
|
@ -287,7 +278,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SubDirective extends SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: SubDirective,
|
||||
|
@ -307,8 +297,110 @@ describe('InheritDefinitionFeature', () => {
|
|||
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', () => {
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SuperComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: SuperComponent,
|
||||
|
@ -321,7 +413,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
}
|
||||
|
||||
expect(() => {
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SubDirective extends SuperComponent{static ngDirectiveDef = defineDirective({
|
||||
type: SubDirective,
|
||||
selectors: [['', 'subDir', '']],
|
||||
|
@ -334,7 +425,6 @@ describe('InheritDefinitionFeature', () => {
|
|||
it('should run inherited features', () => {
|
||||
const log: any[] = [];
|
||||
|
||||
// tslint:disable-next-line:class-as-namespace
|
||||
class SuperDirective {
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: SuperDirective,
|
||||
|
|
Loading…
Reference in New Issue