ERROR Error: dataKey must be defined to use row expansion

Viewed 52

I'm trying to figure out how to use Row Expansion in PrimeEng. I was just following the guide in their documentation and it shows that I should define my datakey. I already defined it below if I'm not mistaken. I'm new to this, please don't judge.

<p-table [value]="users" [paginator]="true" [rows]="10" [showCurrentPageReport]="true"
    currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
    [rowsPerPageOptions]="[10, 25, 50]">
   
<ng-template pTemplate="header">
    <tr>
        <th style="width:2rem">blank</th>
        <th style="width:1rem">ID</th>
        <th style="width:8rem">Name</th>
        <th style="width:8rem">Username</th>
        <th style="width:8rem">Email</th>
        <th style="width:8rem">Street</th>
        <th style="width:8rem">Suite</th>
        <th style="width:8rem">City</th>
        <th style="width:8rem">Zip code</th>
        <th style="width:8rem">LAT</th>
        <th style="width:8rem">LNG</th>
        <th style="width:8rem">Phone</th>
        <th style="width:8rem">Website</th>
    </tr>
</ng-template>

<ng-template pTemplate="body" let-user let-expanded="expanded">
    <tr>
        <td>
            <!-- <button type="button" pButton pRipple (click)="viewPostUser(user.id)" class="p-button-text p-button-rounded p-button-plain" ></button> -->
            <button type="button" pButton pRipple [pRowToggler]="posts" (click)="viewPostUser(user.id)" class="p-button-text p-button-rounded p-button-plain" [icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></button>
        </td>
        <td>{{user.id}}</td>
        <td>{{user.name}}</td>
        <td>{{user.username}}</td>
        <td>{{user.email}}</td>
        <td>{{user.address.street}}</td>
        <td>{{user.address.suite}}</td>
        <td>{{user.address.city}}</td>
        <td>{{user.address.zipcode}}</td>
        <td>{{user.address.geo.lat}}</td>
        <td>{{user.address.geo.lng}}</td>
        <td>{{user.phone}}</td>
        <td>{{user.website}}</td>

        
    </tr>
</ng-template>

Here is my row expansion ng-template.

<ng-template pTemplate="rowexpansion" let-posts>
    <tr>
        <td colspan="7">
            <div class="p-p-3">
                <p-table [value]="posts.userId" [dataKey]="posts.userId">
                    <ng-template pTemplate="header">
                        <tr>
                            <th style="width:4rem">userID</th>
                            <th style="width:4rem">ID</th>
                            <th style="width:4rem">Title</th>
                            <th style="width:4rem">Body</th>
                        </tr>
                    </ng-template>
                    <ng-template pTemplate="body" let-posts>
                        <tr>
                            <td>{{posts.userId}}</td>
                            <td>{{posts.id}}</td>
                            <td>{{posts.title}}</td>
                            <td>{{posts.body}}</td>
                            <td><p-button type="button" icon="pi pi-search"></p-button></td>
                        </tr>
                    </ng-template>
                </p-table>

            </div>
        </td>
    </tr>
</ng-template>

I've tried searching the error that I have, but it points me to updating the version.

2 Answers

I think here is where you get it wrong:

[value]="posts.userId" [dataKey]="posts.userId"

[value] is the collection that you want to iterate through, which should be posts in this case
[dataKey] is the property of one item in that collection which you could just define by name: userId

So the final code is:

[value]="posts" [dataKey]="userId"

First, to fix the error you're seeing, add the attribute dataKey="id" to the p-table element.

Next, using let-posts is probably not what you wanted. You didn't write how your data structure is constructed but I'll assume each user has a property called posts. You need to change your template like this:

<ng-template pTemplate="rowexpansion" let-user>
    <tr>
        <td colspan="7">
            <div class="p-p-3">
                <p-table [value]="user.posts" dataKey="id">
                    <ng-template pTemplate="header">
                        <tr>
                            <th style="width:4rem">userID</th>
                            <th style="width:4rem">ID</th>
                            <th style="width:4rem">Title</th>
                            <th style="width:4rem">Body</th>
                        </tr>
                    </ng-template>
                    <ng-template pTemplate="body" let-post>
                        <tr>
                            <td>{{post.userId}}</td>
                            <td>{{post.id}}</td>
                            <td>{{post.title}}</td>
                            <td>{{post.body}}</td>
                            <td><p-button type="button" icon="pi pi-search"></p-button></td>
                        </tr>
                    </ng-template>
                </p-table>

            </div>
        </td>
    </tr>
</ng-template>

Explanation:

  1. Use let-user in the rowexpansion template. Now the user variable will contain the user data for the current expandable row.
  2. In the inner p-table, provide the [value] input with the data for the sub table, i.e., the posts for the current user.
  3. In the inner p-table, provide the dataKey input with the name of the field which is the unique key of the table. This might be even not necessary in your case.
  4. In the inner p-table, in the body template, use let-post instead of let-posts since each iteration, i.e., each row of the inner table showing posts for the user, will store the current row, which is a single post.
  5. In each <td> element in the inner table's body template, use post.<field-name>. post will contain the data for the current row so all you need to do is access the field you need inside the object.
Related