fix(ivy): pass ngContentSelectors through to defineComponent()
calls (#27867)
Libraries that create components dynamically using component factories, such as `@angular/upgrade` need to pass blocks of projected content through to the `ComponentFactory.create()` method. These blocks are extracted from the content by matching CSS selectors defined in `<ng-content select="..">` tags found in the component's template. The Angular compiler collects these CSS selectors when compiling a component's template, and exposes them via the `ComponentFactory.ngContentSelectors` property. This change ensures that this property is filled correctly when the component factory is created by compiling a component with the Ivy engine. PR Close #27867
This commit is contained in:

committed by
Andrew Kushnir

parent
e8a57f0ee6
commit
feebe03523
@ -119,7 +119,10 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
||||
super();
|
||||
this.componentType = componentDef.type;
|
||||
this.selector = componentDef.selectors[0][0] as string;
|
||||
this.ngContentSelectors = [];
|
||||
// The component definition does not include the wildcard ('*') selector in its list.
|
||||
// It is implicitly expected as the first item in the projectable nodes array.
|
||||
this.ngContentSelectors =
|
||||
componentDef.ngContentSelectors ? ['*', ...componentDef.ngContentSelectors] : [];
|
||||
}
|
||||
|
||||
create(
|
||||
|
@ -182,6 +182,11 @@ export function defineComponent<T>(componentDefinition: {
|
||||
*/
|
||||
template: ComponentTemplate<T>;
|
||||
|
||||
/**
|
||||
* An array of `ngContent[selector]` values that were found in the template.
|
||||
*/
|
||||
ngContentSelectors?: string[];
|
||||
|
||||
/**
|
||||
* Additional set of instructions specific to view query processing. This could be seen as a
|
||||
* set of instruction to be inserted into the template function.
|
||||
@ -249,6 +254,7 @@ export function defineComponent<T>(componentDefinition: {
|
||||
vars: componentDefinition.vars,
|
||||
factory: componentDefinition.factory,
|
||||
template: componentDefinition.template || null !,
|
||||
ngContentSelectors: componentDefinition.ngContentSelectors,
|
||||
hostBindings: componentDefinition.hostBindings || null,
|
||||
contentQueries: componentDefinition.contentQueries || null,
|
||||
contentQueriesRefresh: componentDefinition.contentQueriesRefresh || null,
|
||||
|
@ -189,6 +189,11 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
*/
|
||||
readonly template: ComponentTemplate<T>;
|
||||
|
||||
/**
|
||||
* An array of `ngContent[selector]` values that were found in the template.
|
||||
*/
|
||||
readonly ngContentSelectors?: string[];
|
||||
|
||||
/**
|
||||
* A set of styles that the component needs to be present for component to render correctly.
|
||||
*/
|
||||
|
@ -18,7 +18,28 @@ describe('ComponentFactory', () => {
|
||||
const cfr = injectComponentFactoryResolver();
|
||||
|
||||
describe('constructor()', () => {
|
||||
it('should correctly populate public properties', () => {
|
||||
it('should correctly populate default properties', () => {
|
||||
class TestComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: TestComponent,
|
||||
selectors: [['test', 'foo'], ['bar']],
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
template: () => undefined,
|
||||
factory: () => new TestComponent(),
|
||||
});
|
||||
}
|
||||
|
||||
const cf = cfr.resolveComponentFactory(TestComponent);
|
||||
|
||||
expect(cf.selector).toBe('test');
|
||||
expect(cf.componentType).toBe(TestComponent);
|
||||
expect(cf.ngContentSelectors).toEqual([]);
|
||||
expect(cf.inputs).toEqual([]);
|
||||
expect(cf.outputs).toEqual([]);
|
||||
});
|
||||
|
||||
it('should correctly populate defined properties', () => {
|
||||
class TestComponent {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: TestComponent,
|
||||
@ -27,6 +48,7 @@ describe('ComponentFactory', () => {
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
template: () => undefined,
|
||||
ngContentSelectors: ['a', 'b'],
|
||||
factory: () => new TestComponent(),
|
||||
inputs: {
|
||||
in1: 'in1',
|
||||
@ -42,7 +64,7 @@ describe('ComponentFactory', () => {
|
||||
const cf = cfr.resolveComponentFactory(TestComponent);
|
||||
|
||||
expect(cf.componentType).toBe(TestComponent);
|
||||
expect(cf.ngContentSelectors).toEqual([]);
|
||||
expect(cf.ngContentSelectors).toEqual(['*', 'a', 'b']);
|
||||
expect(cf.selector).toBe('test');
|
||||
|
||||
expect(cf.inputs).toEqual([
|
||||
|
Reference in New Issue
Block a user