Target iterated fa-icon row in table - Angular , primeNg - html

I have a nested table made using primeNg. Each row denotes a task. Every row has a start fa-icon which starts the task and if a particular task is started, the start button gets replaced by a stop fa-icon, incase any user wants to stop the on-going task.
The task are nested (Note the expand-arrows to the left of rows). With my current code, whenever I click on start fa-icon, all the fa-icons in the table gets 'started'. I need to specifycally grab the play fa-icon of the row where the task is initiated and replace that exact play fa-icon with stop fa-icon.
I'm replacing start fa-icon with stop fa-icon using *ngIf and Boolean variables.
.ts:
playTask:boolean = true;
stopTask:boolean = false;
playClicked(array , i , j, event:any){
this.playTask = false;
this.stopTask = true;
var target = event.target || event.srcElement || event.currentTarget;
var idAttr = target.attributes.id
console.log( "id: ", idAttr);
}
stopClicked(array , i , j, event:any){
this.playTask = true;
this.stopTask = false;
}
html:
<p-table id="main-table" [value]="tasks" dataKey="col1">
<ng-template pTemplate="header">
<tr>
<th></th>
<th>Col 1 <fa-icon [icon]="faChevronUp"></fa-icon><fa-icon [icon]="faChevronDown"></fa-icon></th>
<th>Col 2 <fa-icon [icon]="faChevronUp"></fa-icon><fa-icon [icon]="faChevronDown"></fa-icon></th>
<th>Col 3 <fa-icon [icon]="faChevronUp"></fa-icon><fa-icon [icon]="faChevronDown"></fa-icon></th>
<th>Col 4 <fa-icon [icon]="faChevronUp"></fa-icon><fa-icon [icon]="faChevronDown"></fa-icon></th>
<th>Col 5 <fa-icon [icon]="faChevronUp"></fa-icon><fa-icon [icon]="faChevronDown"></fa-icon></th>
<th>Col 6</th>
<th>Action</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-i="rowIndex" let-parentTasks let-expanded="expanded" >
<tr *ngFor="let parentTasks of tasks">
<td>
<button type="button" pButton pRipple [pRowToggler]="parentTasks" [icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-up'"></button>
</td>
<td>{{parentTasks.row1}}</td>
<td>{{parentTasks.row2}}</td>
<td>{{parentTasks.row3}}</td>
<td>{{parentTasks.row4}}</td>
<td>{{parentTasks.row5}}</td>
<td>{{parentTasks.row6}}</td>
<td>
<fa-icon *ngIf="playTask" [icon]="faPlayCircle"></fa-icon>
<fa-icon *ngIf="stopTask" [icon]="faStopCircle"></fa-icon>
<fa-icon [icon]="faCommentDots"></fa-icon>
</td>
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-parentTasks let-i="rowIndex">
<tr>
<td>
<div class="expandedRow">
<p-table [value]="parentTasks.appointments" dataKey="row1">
<ng-template pTemplate="body" let-childTasks let-j="rowIndex" let-childTasks.viewDetails="false">
<tr>
<td>
<i (click)="childTasks.viewDetails = !childTasks.viewDetails" [ngClass]="childTasks.viewDetails ? 'pi pi-chevron-down' : 'pi pi-chevron-up'"></i>
</td>
<td>{{childTasks.row1}}</td>
<td>{{childTasks.row2}}</td>
<td>{{childTasks.row3}}</td>
<td>{{childTasks.row4}}</td>
<td>{{childTasks.row5}}</td>
<td>{{childTasks.row6}}</td>
<td>
<fa-icon *ngIf="playTask" (click)="playClicked(childTasks, i, j , $event)" id="{{'play'}}" [icon]="faPlayCircle"></fa-icon>
<fa-icon *ngIf="stopTask" (click)="stopClicked(childTasks, i, j, $event)" id="{{'pause'}}" [icon]="faStopCircle"></fa-icon>
<fa-icon [icon]="faCommentDots"></fa-icon>
</td>
</tr>
</ng-template>
</p-table>
</div>
</td>
</tr>
</ng-template>
</p-table>
I have tried using $event for getting any unique ID of that row but it always returns as empty. Note: View childTasks for the (click) event.

Only the issue with above code I see, you use two way binding for icon attribute. Which is updating your icon global for entire rows of grid.
<fa-icon *ngIf="stopTask" (click)="stopClicked(childTasks, i, j, $event)" id="{{'pause'}}" [icon]="faStopCircle">
#Please try below
<i class="fa fa-stop" *ngIf="stopTask" (click)="stopClicked(childTasks, i, j, $event)" >

Related

Applying an ngClass on only 1 element of a table in angular

In my table, I'm attempting to add a read more button to each row that has a paragraph. The button is displayed for each row, and when I click one, it operates concurrently for each row.
Here is my code:
<table class="table">
<thead>
<tr>
<th scope="col">Text</th>
<th scope="col">Date</th>
<th scope="col">Comments</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of posts[0].posts">
<div [ngClass]="{'limitTextHeight': isReadMore}">
<td>{{p.post_text}}</td>
</div>
<button type="button" (click)="showText()" style="margin-top:15px">
{{ isReadMore ? 'Read More': 'Read Less' }}
</button>
<td>{{p.post_date}}</td>
<td>{{p.post_comments.length}} comment</td>
</tr>
</tbody>
</table>
and my showText() function:
showText() {
this.isReadMore = !this.isReadMore
}
This is happening because you're using single boolean variable i.e, isReadMore for all the looped tr tag.
What you can do is posts[0].posts map this posts with one more key that can be anything for example isReadMore in your case, then you will get unique instance to handle for each para, like this.
{{ p?.isReadMore ? 'Read More': 'Read Less' }}.
Hope you understood what I'm trying to say.
You are using a common variable for all the rows. That's why when you click one they all change. You should use local ones, one for each row like so:
<table class="table">
<thead>
<tr>
<th scope="col">Text</th>
<th scope="col">Date</th>
<th scope="col">Comments</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of posts[0].posts">
<div [ngClass]="{'limitTextHeight': isReadMore}">
<td>{{p.post_text}}</td>
</div>
<button type="button" (click)="showText(p)" style="margin-top:15px">
{{ p.isReadMore ? 'Read More': 'Read Less' }}
</button>
<td>{{p.post_date}}</td>
<td>{{p.post_comments.length}} comment</td>
</tr>
</tbody>
</table>
and the showText() function:
showText(post) {
post.isReadMore = !post.isReadMore
}
You could also add an *ngIf to check if there is text long enough before showing the button:
<button type="button" *ngIf="p.post_text?.length > 20" (click)="showText(p)" style="margin-top:15px">
{{ p.isReadMore ? 'Read More': 'Read Less' }}
</button>

ERROR Error: dataKey must be defined to use row expansion

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.
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:
Use let-user in the rowexpansion template. Now the user variable will contain the user data for the current expandable row.
In the inner p-table, provide the [value] input with the data for the sub table, i.e., the posts for the current user.
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.
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.
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.
You can add dataKey in first line, like this
<p-table [value]="users" dataKey="name">
Maybe it will solve your problem.

could not get query Selector inside <ng-template> in angular

I have table component.
I want to add a property to a element when [draggable]="true".
parent class
<ngx-custom-table [value]="users" [draggable]="true">
<ng-template #header let-columns>
<tr>
// removed
</tr>
</ng-template>
<ng-template #body let-data>
<tr >
<td>
</td>
<td>{{ data.id }}</td>
<tr>
</ng-template>
</ngx-custom-table>
child class
ngOnInit() {
console.log( (<HTMLElement>document.querySelector('ngx-custom-table'))); // this is defined
console.log( (<HTMLElement>document.querySelector('tr'))); // but this is null
});
Why (<HTMLElement>document.querySelector('tr')); this is null??
How can I add a property to <tr> element?

Toggle table row based on if condition not working

Need to toggle one table row based on if condition not working.
If status id none I need to open a form in popup but if status is done popup shouldn't open.
<ng-container *ngFor="let person of personList |
searchFilter:searchValue;index as i">
<tr *ngIf="person.status == 'none'"
data-toggle="modal" data-target="#personModal"
(click)="function(person.id)">
<tr *ngIf="person.status == 'done'" >
<td>Place</td>
<td>Job</td>
</tr>
</tr>
</ng-container>
When I tried this solution the row is not displaying in the table list
Probably you should do something like this:
<ng-container *ngFor="let person of personList | searchFilter:searchValue;index as i">
<tr *ngIf="person.status == 'none'" data-toggle="modal" data-target="#personModal"
(click)="someFunction(person.id)">
<td>Place</td>
<td>Job</td>
</tr>
<tr *ngIf="person.status == 'done'" >
<td>Place</td>
<td>Job</td>
</tr>
</ng-container>
But it's important to see your TypeScript code. You should make a Stackblitz example.

SelectAll checkbox in header should get unchecked when move to next page when using p-tableHeaderCheckbox and p-table

I am using <p-table> which has <p-tableHeaderCheckbox></p-tableHeaderCheckbox> to check and uncheck the check box. Everything is working fine but when I am move to next page in table then everything is unchecked but selectAll option is still checked . How to uncheck the header checkbox.
<p-table #dtGrid [columns]="staticColumns" [value]="serviceIdData"
[styleClass]="'table'" scrollHeight="{{scrollHeight}}" [rows]="10"
[paginator]="true" (onRowSelect)="onRowSelect($event)" [pageLinks]="3"
(onRowUnselect)="onRowUnselect($event)" [rowsPerPageOptions]="[10,25,50,100]"
styleClass="table-light" (onHeaderCheckboxToggle)="handleHeaderCheckboxToggle($event)"
[scrollable]="true" [lazy]="true" [(selection)]="selectedRecords"
(onLazyLoad)="onLazyLoad($event);" [totalRecords]="totalRecords" scrollHeight="450px" [responsive]="true">
<ng-template pTemplate="colgroup" let-columns>
<colgroup>
<col *ngFor="let col of columns" [ngStyle]="{'width': col.width}">
</colgroup>
</ng-template>
<ng-template pTemplate="header" let-columns>
<tr>
<th role="columnheader" style="width:20px;">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th *ngFor="let col of columns" [pSortableColumn]="col.fieldName" (click)="placeSortIcon()">
<div>
<span pTooltip={{col.tooltip}} tooltipPosition="top" [innerHtml]="col.label" [ngClass]="'ui-column-title'"></span>
<span *ngIf="dtGrid.sortField === col.fieldName" class="fa" [ngClass]="{'fa-sort-desc': dtGrid.sortOrder === -1, 'fa-sort-asc': dtGrid.sortOrder === 1}"></span>
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-columns="columns" let-data>
<tr [pSelectableRow]="data" [pSelectableRowDisabled]="data.moved">
<td class="rowDataStyle" style="width:20px;">
<span *ngIf="data.moved"><img name="loading" src="assets/images/lock.png"></span>
<p-tableCheckbox [value]="data" [hidden]="data.moved" [disabled]="data.moved" binary="data.selected"></p-tableCheckbox>
<!-- {{data.selected}} , {{data.moved}} -->
</td>
<td *ngFor="let column of columns">
<span [ngClass]="'ui-cell-data'">
{{data[column.fieldName]}}</span>
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage" let-columns>
<tr>
<td [attr.colspan]="columns.length">
No records found
</td>
</tr>
</ng-template>
</p-table>
Checkbox still checked on moving to next page, click on this to see screenshot of the output table
// Declair variables
checkBoxSelection = [];
checkBoxSelectionOldStore = [];
// put after serviceIdData variable ex. blelow
// After API Success
this.serviceIdData = response.data;
this.checkBoxSelection = _.cloneDeep(Array(Number((this.totalRecords/e.rows).toFixed())).fill([]));
this.checkBoxSelection = this.checkBoxSelectionOldStore.length ? _.cloneDeep(this.checkBoxSelectionOldStore) : this.checkBoxSelection;
handleHeaderCheckboxToggle($event: any) {
const isChecked = $event.checked;
this.selectedItems = [];
this.checkBoxSelection[this.pageIndex] = isChecked ? _.cloneDeep(this.items) : [];
this.onRowSelect();
}
onRowSelect() {
this.checkBoxSelectionOldStore = _.cloneDeep(this.checkBoxSelection);
this.selectedItems = [];
_.forEach(this.checkBoxSelectionOldStore, (value) => {
if (value.length > 0) {
_.forEach(value, (v) => {
this.selectedItems.push(v);
});
}
});
}
// finally Your selected records in this.selectedItems
<p-table [value]="serviceIdData" (onHeaderCheckboxToggle)="handleHeaderCheckboxToggle($event)" [(selection)]="selectedRecords" (onLazyLoad)="onLazyLoad($event);" [totalRecords]="totalRecords" (onRowSelect)="onRowSelect()" [(selection)]="checkBoxSelection[pageIndex]">
</p-table>