tegel
tegel copied to clipboard
[Bug report]: Popover based elements break when rendered with Angular @for
Requirements before reporting
- [X] No duplicated issue reported.
- [X] I have checked the latest version if the bug exist there. See all available packages at npmJS.com
- [X] I have followed the installation guide.
Package versions
@scania/tegel: 1.13.0 @scania/tegel-angular: 1.13.0
Browser
Chrome
Framework
Angular
Version
17
Reproduction steps
- Create an array of objects. Each object should have an id field that uniquely identifies it.
- Render an array of objects using Angular's @for directive. Each rendered item should contain a tds-popover-menu
- Make sure to use the track function of the
@for
loop and track the items by their unique ID property - Change the order of items
Code example
import { Component } from "@angular/core";
import { TegelModule } from "@scania/tegel-angular";
@Component({
selector: "example-product-list",
standalone: true,
imports: [TegelModule],
template: `
@for (product of products; track product.productId) {
<span>{{ product.description }}</span>
<tds-button size="sm" [attr.id]="product.productId">
<tds-icon name="kebab" slot="icon"></tds-icon>
</tds-button>
<tds-popover-menu [selector]="'#' + product.productId">
<tds-popover-menu-item>
<button (click)="moveProductDown(product.productId)">
Move down
</button>
</tds-popover-menu-item>
</tds-popover-menu>
<tds-divider></tds-divider>
}
`,
})
export class ExampleProductListComponent {
public products = [
{
productId: "product-id-1",
description: "Truck",
},
{
productId: "product-id-2",
description: "Bus",
},
];
public moveProductDown(productId: string): void {
const productIndex = this.products.findIndex(
product => product.productId === productId
);
if (productIndex >= this.products.length - 1) {
return;
}
const newProducts = structuredClone(this.products);
const matchingProduct = newProducts[productIndex];
newProducts.splice(productIndex, 1);
newProducts.splice(productIndex + 1, 0, matchingProduct);
this.products = structuredClone(newProducts);
}
}
Expected behavior
The component above renders two items. Each item contains a button that opens a popover menu. After opening the popover menu of the "Truck" item and clicking on the "Move down" button, both menu buttons should still open their respective tds-popover-menu
.
Actual behavior
After opening the popover menu of the "Truck" item and clicking on the "Move down" button, the popover menu of the "Bus" item no longer opens when clicking on the menu button.
This only seems to happen when the track function of the @for
loop is used to track items by their unique IDs. When using track $index
instead of track product.productId
this does not occur, but using track $index
causes performance issues, since angular has to re-render the whole list instead of just the elements that changed.