Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Separate List Items into Components in Angular

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>
like image 964
Derek 朕會功夫 Avatar asked Oct 23 '25 06:10

Derek 朕會功夫


1 Answers

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>

You're example is looking promising

however have you tried

<mat-list>
   <mat-list-item *ngFor="let item of items" >
     <todo-list-item [item]></todo-list-item>
   </mat-list-item>
</mat-list>

todo-list-item.component.*

    <p>{{ item.title }} - {{ item.description }}</p>

that way it should be quaranted a mat list item under mat list

like image 100
Nikolai Kiefer Avatar answered Oct 25 '25 21:10

Nikolai Kiefer