Suppose I am creating a typical to-do list that has a structure as following:
<ul>
<li>Item 1 - description for item 1</li>
<li>Item 2 - description for item 2</li>
<!-- ... -->
</ul>
I would like the list and the items to be as reusable as possible, and so I can make them into separate components:
todo-list.component.*
@Component({
selector: "todo-list",
templateUrl: "todo-list.component.html"
})
export class TodoListComponent { /* ... */ }
<ul>
<li todo-list-item *ngFor="let item of items" [item]="item"></li>
</ul>
todo-list-item.component.*
@Component({
selector: "li[todo-list-item]",
templateUrl: "todo-list-item.component.html"
})
export class TodoListItemComponent { /* ... */ }
{{ item.title }} - {{ item.description }}
So far everything will work as long as I stick with native HTML elements such as ul
and li
.
However an issue arises when I try to use Angular components instead native elements such as mat-list
and mat-list-item
:
todo-list.component.*
<mat-list>
<mat-list-item todo-list-item *ngFor="let item of items" [item]="item"></mat-list-item>
</mat-list>
todo-list-item.component.*
{{ item.title }} - {{ item.description }}
The snippets above do not work. mat-list-item
does not accept item
and also now there are two component definitions that matches mat-list-item[todo-list-item]
.
I can do it this way:
todo-list.component.*
<mat-list>
<todo-list-item *ngFor="let item of items" [item]="item"></todo-list-item>
</mat-list>
todo-list-item.component.*
<mat-list-item>
{{ item.title }} - {{ item.description }}
</mat-list-item>
However now the structure is not correct and it will not produce the correct styling:
<mat-list>
<todo-list-item>
<mat-list-item>Item 1 - description for item 1</mat-list-item>
</todo-list-item>
<todo-list-item>
<mat-list-item>Item 2 - description for item 2</mat-list-item>
</todo-list-item>
</mat-list>
mat-list-item
should be directly under mat-list
:
<mat-list>
<mat-list-item>Item 1 - description for item 1</mat-list-item>
<mat-list-item>Item 2 - description for item 2</mat-list-item>
</mat-list>
I am aware that I can combine the two components into a single one, however each of the list items can be fairly complex (with buttons and additional logic) that I would like them to be in separate components. What is the usual approach to this problem? Many of the related questions (such as this and this) that I could find assume native elements are used, which is not the case here. Specifically, how do I create the following structure using two components that I can define myself?
<todo-list>
<mat-list>
<mat-list-item>Item 1 - description for item 1</mat-list-item>
<mat-list-item>Item 2 - description for item 2</mat-list-item>
</mat-list>
</todo-list>