How to sort primeNg table with nested columns structure? - javascript

I am using primeNg . I want to implement sorting of data. The problem is that I have a column data structure where some columns have a superColumn type and that means they are divided for a set of subColumns. It works well for presenting but I have a problem with sorting it. It is never sorted on basis of the subcolumn field value but on the basis of the parent column (supercolumn) field value. That means it is taking what is in the [pSortableColumn] attribute instead of what is in the [field] attribute of the sorting icon.
Is there any way I could resolve that? This is my code below (I removed styling):
<th
*ngFor="let col of columns; let i = index;"
pResizableColumn
pReorderableColumn
[pSortableColumn]="col.field"
[pSortableColumnDisabled]="col.showSort === false"
>
<ng-container *ngIf="col.type !== 'superColumn'">
<span>{{ col.header }}</span>
<p-sortIcon [field]="col.field"></p-sortIcon>
</ng-container>
<ng-container *ngIf="col.type === 'superColumn'">
<div>{{ col.header }}</div>
<ng-container *ngFor="let subColumn of col.subColumns">
<div>
{{ subColumn.header }}
<p-sortIcon [field]="subColumn.field"></p-sortIcon>
</div>
</ng-container>
</ng-container>
</th>

Related

Angular mat-table displaying repeat rows

I am trying to create a relatively simple mat-table that displays elements from a "dataSource". My problem is that when I run my code it gives me the error: There can only be one default row without a when predicate function.
Adding multiTemplateDataRows to my <mat-table> fixes this problem but makes it so that all of the elements in my table are duplicated (two of them).
Picture displaying duplication
I want to understand why is is happening. I believe that in my case the items are duplicated because I have exactly two columns. Can someone help me understand?
My Code:
HTML:
<mat-table [dataSource]="siteContacts" multiTemplateDataRows class="table" fxLayout="column wrap">
<ng-container [matColumnDef]="col" *ngFor="let col of siteContactColumns">
<mat-header-cell *matHeaderCellDef>
</mat-header-cell>
<mat-cell *matCellDef="let element">
<div [ngSwitch]="siteContactDataSchema[col]">
<div *ngSwitchCase="'ContactTitle'">
{{element[col]}}
</div>
<span *ngSwitchDefault>
{{element[siteContactDataSchema[col][0]]}} <br>
{{element[siteContactDataSchema[col][1]]}} <br>
{{element[siteContactDataSchema[col][2]]}}
</span>
</div>
</mat-cell>
<mat-row *matRowDef="let row; let even = even; columns: siteContactColumns;" [ngClass]="{gray: even}">
</mat-row>
</ng-container>
</mat-table>
Typescript:
const SITE_CONTACTS_SCHEMA = {
"ContactTitle": "ContactTitle",
"ContactInfo": ["ContactName", "ContactCellPhone", "ContactEmail"]
}
...
siteContactDataSchema = SITE_CONTACTS_SCHEMA;
siteContactColumns: string[] = ['ContactTitle', 'ContactInfo'];
...
this.siteDirectoryService.getAllSiteContacts(this.parentSiteId).subscribe(res => {
this.siteContacts = res;
})

How to loop through unknow number of nested json object in Angular with ngFor?

I'm trying to display all the reply from this json :
https://www.reddit.com/r/AskReddit/comments/k8w43d/people_with_the_last_name_pepper_who_have.json
So, depending of the post im loading and the reply, my number of children will differ. How can I loop throught it until I reach the last reply with children (body[2].data.children) ?
Like this :
<div class="replies-box" *ngFor="let reply of comments.body[1].data.children">
<div class="reply-header">
<p class="reply-author"><b>From</b> : {{ reply.data.author }}</p>
<p class="reply-send"><b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</div>
I have only the first level of reply, is there a way to simply loop through them all ?
Thanks in advance.
I would use a recursion type of approach.
Develop a app-comment component and if comment has children, loop over the children and display the app-comment. That way it will loop over the comments until no more children
<div *ngIf='comment'>
<span *ngIf='comment.kind; else showComment'>Kind: {{ comment.kind }}</span>
<ng-template #showComment>
<span>{{ comment }}</span>
</ng-template>
<div>
<app-comment *ngFor='let child of comment.data?.children' [comment]='child'> </app-comment>
</div>
</div>
See this sample illustration
Simply use ngFor inside ngFor with help of ng-container (will not create extra dom elements)
<div class="replies-box">
<ng-container *ngFor="let commentBody of comments.body">
<ng-container *ngFor="let reply of commentBody.data.children">
<div class="reply-header">
<p class="reply-author">
<b>From</b> : {{ reply.data.author }}
</p>
<p class="reply-send">
<b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}
</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</ng-container>
</ng-container>
</div>

Conditional print on html of angular

I am looping through a list of products and then checking if the product Id is already present in an array of products(objects) , then printing the quantity else if the product is not in the object then trying to print 0. Below is the code I have tried till now.
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart" >
<span class="count" *ngIf="cartitem.p_id==item.p_id;">
{{cartitem.qty}}
</span>
</ng-container>
</ion-item>
How to print 0 if item is not in the cartitem in same span.
You can simply do this using ternary operator like below.
<ng-container *ngFor="let cartitem of cart" >
<span class="count">
{{cartitem.p_id==item.p_id ? cartitem.qty : 0 }}
</span>
</ng-container>
Can use *ngIf else condition inside your for loop -
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart">
<span class="count" *ngIf="cartitem.p_id==item.p_id; then content else other_content">
</span>
<ng-template #content>{{cartitem.qty}}</ng-template>
<ng-template #other_content>0</ng-template>
</ng-container>
</ion-item>
Instead of using template logic I would move the logic to the class.
cart and products are obviously available in the class.
Therefore adjust the fetchProducts function in the class to return the products list as needed (with the quantity information) and use a single ngFor loop in the template.
Or add a new function getProductsWithQuantity...
In your class
public getProductsWithQuantity() {
return this.fetchProducts().map(product => {
...product,
quantity: this.getQuantity(product);
});
}
private getQuantity(product) {
const foundCartItem = this.cart.find(cartItem => product.id === cartItem.id);
if (foundCartItem) {
return foundCartItem.qty;
}
return 0;
}
In your template:
<ion-item class="added" *ngFor="let item of getProductsWithQuantity();let key=index;">
<span class="count">
{{item.qty}}
</span>
...

Angular - How to sort table data according to specific column

I have a table with 3 colums. But I want to sort the table data according to first column (Domain) alphabetically. My table html is:
<mat-table #table [dataSource]="tableData">
<ng-container cdkColumnDef="domain">
<mat-header-cell *cdkHeaderCellDef fxFlex="50%">Domain</mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="50%">{{config.domain}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="disable">
<mat-header-cell *cdkHeaderCellDef fxFlex="30%">Disabled</mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="30%">{{config.disabled}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="button">
<mat-header-cell *cdkHeaderCellDef fxFlex="15%"></mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="15%">
<mat-icon (click)="deleteDomain(config)" style="cursor: pointer">delete_forever</mat-icon>
</mat-cell>
</ng-container>
<mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *cdkRowDef="let config; columns: displayedColumns;"></mat-row>
</mat-table>
And my .ts file for this table is consisting following code :
private _domainData = new BehaviorSubject<Domain[]>([]);
#Input()
set domainData(value: Domain[]) {
this._domainData.next(value);
}
displayedColumns = ['domain', 'disable', 'button'];
tableData: Domain[];
Is it possible to achieve this ?
You can achieve this from the TypeScript by sort method when clicked on the particular column.
I don't think you need to write this logic in the back end.
If the intention is to just display the sorted data according to your Domain column. Then, please do at blackened that would be much better.
Hope this helps.
If you are using Angular Material, you can use Sort Header to sort data .
Or atleast you can use the logic they provided for sorting in first example.

how to slice td limit by 2 in table angular

I have a carsList array having 5 values. i try slice 2 by 2
<table>
<tr *ngFor="#item of carsList | slice:0:2; #i = index">
<td>{{i}}. {{item}}</td>
</tr>
</table>
above code split 2 values only. I want slice 2 by 2.
Example
0 1
2 3
4 5
Code:
https://plnkr.co/edit/BZnaSIldgO3Dmwao1mo6?p=preview
kindly help me . where is my mistake.
The slice pipe results an array with 2 elements and ngFor would iterate over the elements in the resulted array, that doesn't provide the expected result.
To achieve the result either you need to convert the array structure or do something like this with an additional ngIf with nested ngFor.
<table>
<ng-container *ngFor="#item of carsList; #i = index">
<tr *ngIf="i % 2 === 0">
<td *ngFor="#item1 of carsList|slice:i:i + 2; #i1 = index" class="car-title">{{i1}}. {{item1}}</td>
</tr>
</ng-container>
</table>
or by removing nested ngFor and simply creating 2 td manually.
<table>
<ng-container *ngFor="#item of carsList; #i = index">
<tr *ngIf="i %2 === 0">
<td>{{i}}. {{item}}</td>
<td>{{ i + 1 }}. {{carsList[i + 1]}}</td>
</tr>
</ng-container>
</table>
FYI : Where ng-container can be used to group element which doesn't put in the DOM tree.
Updated plunker link.
Pranav's answer almost conveyed the idea for achieving it, however his plunker seemed to not show exactly what the OP had, in addition to looking a bit over-complicated.
A simple fix as per the plunker in OP would be this (confirmed it to be working there),
<ul>
<ng-container *ngFor="#item of carsList; #i = index">
<li *ngIf="i % 2 === 0">
<span class="car-title">{{i}}. {{item}}</span>
</li>
</ng-container>
</ul>
Try this -
<ul>
<ng-container *ngFor="#item of carsList; #i = index">
<li *ngIf="i % 2 === 0">
<span class="car-title">{{i}}. {{item}}</span>
<span class="car-title">{{i+1}}. {{carsList[i + 1]}}</span>
</li>
</ng-container>
</ul>

Categories

Resources