I know a similar question to this is all over the site, but my problem is slightly different from those.
I want to write a component that serves rows, but each instance may generate from one to many rows, depending on the provided data:
<tbody>
<!-- intended usage -->
<data-rows *ngFor="let row of dataRows" [row]="row">
</data-rows>
</tbody>
Needs to create:
<tbody>
<!-- from first <data-rows> instance -->
<tr><td> instance 1, row 1 </td></tr>
<!-- from second <data-rows> instance -->
<tr><td> instance 2, row 1 </td></tr>
<tr><td> instance 2, row 2 </td></tr>
<tr><td> instance 2, row 3 </td></tr>
<!-- from third <data-rows> instance -->
<tr><td> instance 3, row 1 </td></tr>
</tbody>
Most solutions propose using an attribute selector and use *ngFor on a real <tr>. This will not work in my case because there's not a one-to-one relationship between instances and rows. In addition, the parent component doesn't know how many <tr> should be rendered; that's for <data-rows> to decide.
Of course a naive implementation of <data-rows> would fail, as it would add unsupported elements to the tbody:
<tbody>
<data-rows>
<!-- from first <data-rows> instance -->
<tr><td> instance 1, row 1 </td></tr>
</data-rows>
<data-rows>
<!-- from second <data-rows> instance -->
<tr><td> instance 2, row 1 </td></tr>
<tr><td> instance 2, row 2 </td></tr>
<tr><td> instance 2, row 3 </td></tr>
</data-rows>
<data-rows>
<!-- from third <data-rows> instance -->
<tr><td> instance 3, row 1 </td></tr>
</data-rows>
</tbody>
That doesn't work because tbody can only contain <tr> elements, so the table logic breaks.
My intuition (as that of many who asked a similar question) is to render <data-rows> without the actual <data-rows> element (only its contents) but I think it might not be supported because the css emulate mode would break.
What's a good way of solving this without breaking the initial premise?
As pointed out by user charlietfl in the comments, I can use multiple TBODY tags (never occurred to me), so in my case I can easily generate:
<tbody data-rows class="instance-1">
<tr><td> instance 1, row 1 </td></tr>
</tbody>
<tbody data-rows class="instance-2">
<tr><td> instance 2, row 1 </td></tr>
<tr><td> instance 2, row 2 </td></tr>
<tr><td> instance 2, row 3 </td></tr>
</tbody>
<tbody data-rows class="instance-3">
<tr><td> instance 3, row 1 </td></tr>
</tbody>
In my component, the selector is tbody[data-rows]
, and I can have a parent template like this:
<table>
<thead>
<tr><th>Table header</th></tr>
</thead>
<tbody data-rows *ngFor="let row of data" [row]="row"></tbody>
</table>
This method has the additional advantage of allowing an even/odd styling on an instance (tbody) basis, which in my case makes sense.
The row generator's template is simply another ngIf/ngFor driven template as needed:
<tr><td>This row will always be shown</td></tr>
<tr *ngIf="..."><td>This row, only if first expansion is needed</td></tr>
<tr *ngIf="..."><td>This row, only if second expansion is needed</td></tr>
<tr *ngFor="..."><td>More additional rows</td></tr>
etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With