I am trying to create a component with multi-slot transclusion in Angular 6, following this blog post (which is for Angular 2).
I created a component:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-criteria', template: ` <div class="adoption-grid-column adopter"> <div class="adoption-grid-icon "> <ng-content select="level-icon"></ng-content> </div> <div class="adoption-grid-body"> <ng-content select="level-description"></ng-content> </div> </div> `, styles: [] }) export class CriteriaComponent implements OnInit { constructor() {} ngOnInit() {} }
and then I am trying to use it like this
<app-criteria> <level-icon> foo </level-icon> <level-description> bar </level-description> </app-criteria>
But it throws a compile error:
ERROR in : 'level-icon' is not a known element
What am I missing here?
I realize I could create sub-components here, but I’m looking for a solution where I can pass blocks of html into slots in my component (such as bulleted lists, images, etc.)
Advertisement
Answer
The easiest solution (the one I prefer) is to create subcomponents with ng-content
as you mentioned. If you don’t want to create such components, there are two things you can do.
CUSTOM_ELEMENTS_SCHEMA
You can tell angular to skip over the components it does not recognize by adding CUSTOM_ELEMENTS_SCHEMA
to schema
array of your feature module.
E.g.
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @NgModule({ imports: [...] schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class CustomModule { }
With this way, angular will not complain about level-icon
or level-description
and transclusion will work just fine. However, setting this option may hide other problems you could have. For example, you can make a typo when using a component and since you told angular you would have CUSTOM_ELEMENTS
, it will not give you an error. You end up debugging your code and wondering why the brand new component you just developed is not working.
- Selecting classes or attributes other than elements.
When you write <ng-content select="level-icon"></ng-content>
angular will actually look for html elements called level-icon
. You can have it search for classes, attributes etc. So what you can do is to change this
<ng-content select="level-icon"></ng-content>
to
<ng-content select="[level-icon]"></ng-content>
or
<ng-content select=".level-icon"></ng-content>
And use your component as follows
<app-criteria> <div level-icon> foo </div> </app-criteria>
or
<app-criteria> <div class="level-icon"> foo </div> </app-criteria>
With this way, you can select
for ul
, or img
. Basically anything you want.
If you still want to use <level-icon>
as element, you either have to create a subcomponent or use CUSTOM_ELEMENTS_SCHEMA
.