3

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>
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • When you say `mat-list-item` does not accept `item` what do you mean exactly? – gotnull Dec 02 '18 at 23:51
  • @fuzz [`mat-list-item`](https://material.angular.io/components/list/api#MatListItem) is an Angular component that is already defined instead of a native HTML element that I can redefine by using the selector. Because of that, I don't have control over its inputs. – Derek 朕會功夫 Dec 02 '18 at 23:53
  • 1
    how exactly is the Styling off – Nikolai Kiefer Dec 03 '18 at 00:03
  • 1
    @NikolaiKiefer Let's just say the structure needs to be exact where `mat-list-item` has to be directly under `mat-list`. The styling being incorrect is just a side-effect caused by the incorrect structure. – Derek 朕會功夫 Dec 03 '18 at 00:04
  • could you provide a screenshot of the styling – Nikolai Kiefer Dec 03 '18 at 00:22

1 Answers1

3

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

Nikolai Kiefer
  • 568
  • 5
  • 15