I have a Nested JSON and I want to output it to Mat-Table... Can you guys help me with this, please?
I can output the json susa, how do I output mandantKagAccountEntity?
My code:
// Nested JSON
{
"success": true,
"susa": [
{
"accountlinevaluesId": 1,
"accountlineId": 1,
"mandantKagId": 660,
"mandantAccountsId": 1,
"period": "7",
"accountNumber": 27,
"name": "EDV-Hardware/Software",
"amount": 55.16859,
"mandantKagAccountEntity": {
"mandantKagId": 660,
"mandantId": 1,
"kagNumber": 2000,
"kagText": "A. I. 1. EDV-Software"
}
},
] }
// test.component.ts
private loadData() {
const yearString = this.year ? `${this.year}` : `${new Date().getFullYear()}`;
this.balanceListService.getDataForAllMonth(yearString).subscribe(
(resp: any) => {
const data = resp.success ? resp.susa : null;
if (null !== data && data) {
.... }
}
}
It depends what exactly you want to pass to mat-table.
If it's an array of the nested property mandantKagAccountEntity, then this should do the trick:
const data = resp.success ? resp.susa.map((item) => item.mandantKagAccountEntity) : null;
If you only want the very first occurrence of mandantKagAccountEntity, then you don't have to iterate over the entire nested object:
const data = resp.success ? resp.susa[0]?.mandantKagAccountEntity : null;
// EDIT: OP had a misleading question. He actually wants to display the entire data, including the nested object. Here's the answer to that:
displayedColumns is being used by mat-table to define which columns to show. You can edit the names to your liking.
displayedColumns: string[] = [
'accountlinevaluesId',
'accountlineId',
'mandantKagId',
'mandantAccountsId',
'period',
'accountNumber',
'name',
'amount',
'mandantKagAccountEntity-mandantKagId',
'mandantKagAccountEntity-mandantId',
'mandantKagAccountEntity-kagNumber',
'mandantKagAccountEntity-kagText',
];
Each column needs a container inside the mat-table that defines how to display the property:
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<ng-container matColumnDef="accountlinevaluesId">
<th mat-header-cell *matHeaderCellDef> accountlinevaluesId</th>
<td mat-cell *matCellDef="let element"> {{element.accountlinevaluesId}}</td>
</ng-container>
<ng-container matColumnDef="accountlineId">
<th mat-header-cell *matHeaderCellDef> accountlineId</th>
<td mat-cell *matCellDef="let element"> {{element.accountlineId}}</td>
</ng-container>
<ng-container matColumnDef="mandantKagId">
<th mat-header-cell *matHeaderCellDef> mandantKagId</th>
<td mat-cell *matCellDef="let element"> {{element.mandantKagId}}</td>
</ng-container>
<ng-container matColumnDef="mandantAccountsId">
<th mat-header-cell *matHeaderCellDef> mandantAccountsId</th>
<td mat-cell *matCellDef="let element"> {{element.mandantAccountsId}}</td>
</ng-container>
<ng-container matColumnDef="period">
<th mat-header-cell *matHeaderCellDef> period</th>
<td mat-cell *matCellDef="let element"> {{element.period}}</td>
</ng-container>
<ng-container matColumnDef="accountNumber">
<th mat-header-cell *matHeaderCellDef> accountNumber</th>
<td mat-cell *matCellDef="let element"> {{element.accountNumber}}</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> name</th>
<td mat-cell *matCellDef="let element"> {{element.name}}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef> amount</th>
<td mat-cell *matCellDef="let element"> {{element.amount}}</td>
</ng-container>
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> position</th>
<td mat-cell *matCellDef="let element"> {{element.position}}</td>
</ng-container>
<ng-container matColumnDef="mandantKagAccountEntity-mandantKagId">
<th mat-header-cell *matHeaderCellDef> mandantKagAccountEntity-mandantKagId</th>
<td mat-cell *matCellDef="let element"> {{element.mandantKagAccountEntity.mandantKagId}}</td>
</ng-container>
<ng-container matColumnDef="mandantKagAccountEntity-mandantId">
<th mat-header-cell *matHeaderCellDef> mandantKagAccountEntity-mandantId</th>
<td mat-cell *matCellDef="let element"> {{element.mandantKagAccountEntity.mandantId}}</td>
</ng-container>
<ng-container matColumnDef="mandantKagAccountEntity-kagNumber">
<th mat-header-cell *matHeaderCellDef> mandantKagAccountEntity-kagNumber</th>
<td mat-cell *matCellDef="let element"> {{element.mandantKagAccountEntity.kagNumber}}</td>
</ng-container>
<ng-container matColumnDef="mandantKagAccountEntity-kagText">
<th mat-header-cell *matHeaderCellDef> mandantKagAccountEntity-kagText</th>
<td mat-cell *matCellDef="let element"> {{element.mandantKagAccountEntity.kagText}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
Considering you do want to show all data, there's no further mapping of the response needed, other than
this.dataSource = resp.success ? resp.susa : null;
I have solved the problem. Again for your understanding :) The code outputs the whole JSON object (including nesting). Hope I can help those of you who have the exact same problem I had.
// Fill the table with data
private loadData() {
this.balanceListService.getDataForAllMonth(yearString).subscribe(
(resp: any) => {
let data = resp.susa;
if (null !== data && data) {
data = data.map((item) => {
const kag = item.mandantKagAccountEntity;
delete item.mandantKagAccountEntity;
return { ...item, ...kag }; // merge two objects into one
});
}
});
}
Related
This question already has an answer here:
Mat Table:-How to get one particular element of a particular row on a button click in Mat table angular?
(1 answer)
Closed yesterday.
I have an array of objects that I am using to make a table in Angular. The table works great and adds the data correctly. I am now wanting to be able to edit each object within the table. For example if I wanted to change John Smiths name. How would I make each object in the array its own element so that I can make changes to them individually? Right now if I check 'this.dataFromQuery' it brings back the entire result.
Array: `[
{ first_name: 'John ', last_name: 'Smith', jobNumber: 123 },
{ first_name: 'Smith', last_name: 'John', jobNumber: 321 },
{ first_name: 'Alex', last_name: 'Mason', jobNumber: 10101 },
{ first_name: 'Mason', last_name: 'Alex', jobNumber: 100101 }
]`
Table HTML `
<table mat-table [dataSource]="dataFromQuery.result" class="mat-elevation-z8">
<ng-container matColumnDef="first_name">
<th mat-header-cell *matHeaderCellDef>First Name</th>
<td mat-cell *matCellDef="let element"> {{element.first_name}} </td>
</ng-container>
<ng-container matColumnDef="last_name">
<th mat-header-cell *matHeaderCellDef>Last Name </th>
<td mat-cell *matCellDef="let element"> {{element.last_name}} </td>
</ng-container>
<ng-container matColumnDef="job_Number">
<th mat-header-cell *matHeaderCellDef> Job Number </th>
<td mat-cell *matCellDef="let element"> {{element.jobNumber}} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element">
<button (click)="openDialog()" mat-mini-fab color="primary" aria-label="Example icon button with a menu icon">
<mat-icon>edit</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>"
`
TS
getDataFromAPi(){
this.service.showDataToClient().subscribe((response) => {
console.log("Query Results ", response)
this.dataFromQuery = response
return this.dataFromQuery.result
}, (error) => {
console.log("error", error)
})
}
You already have the "current" row element at hand. All you need to do ti is pass it into the click handler and edit the signature of the method:
<table mat-table [dataSource]="dataFromQuery.result" class="mat-elevation-z8">
...
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let element"> <!--- Here you have the row data as "element". Pass it to the "click" handler next line: -->
<button (click)="openDialog(element)" mat-mini-fab color="primary" aria-label="Example icon button with a menu icon">
<mat-icon>edit</mat-icon>
</button>
</td>
</ng-container>
</table>"
Inside your .ts file you need to edit the signature:
openDialog(element: SomeType) {}
I have stored some data in db.json. In the ts file I have used the get function and received it in a variable. The data is coming through successfully( I checked using console.log). However it is not displaying in the html table i have created.
Below is my html file
<p>people works!</p>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- Position Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element; let i = index"> {{i+1}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="company">
<th mat-header-cell *matHeaderCellDef> Comapnay </th>
<td mat-cell *matCellDef="let element"> {{element.company}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef> Email </th>
<td mat-cell *matCellDef="let element"> {{element.email}} </td>
</ng-container>
<ng-container matColumnDef="address">
<th mat-header-cell *matHeaderCellDef> Address </th>
<td mat-cell *matCellDef="let element"> {{element.address}} </td>
</ng-container>
<ng-container matColumnDef="active">
<th mat-header-cell *matHeaderCellDef> Active </th>
<td mat-cell *matCellDef="let element"> {{element.active}} </td>
</ng-container>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef> Action </th>
<td mat-cell *matCellDef="let element; let j = index"><button (click) = "detail(j)"> {{element.action}} </button></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div id = "Detail">
{{userDetail.id}}<br>
{{userDetail.name}}<br>
{{userDetail.company}}<br>
{{userDetail.email}}<br>
{{userDetail.active}}<br>
{{userDetail.action}}
</div>
And the next code is my ts file
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { user } from './userInterface';
#Component({
selector: 'app-people',
templateUrl: './people.component.html',
styleUrls: ['./people.component.css']
})
export class PeopleComponent implements OnInit {
displayedColumns=["id","name","company","email","address","active","action"];
UserDb:user[]=[];
dataSource = this.UserDb;
userDetail: user={
id: 0,
name: '',
company: '',
email: '',
address: '',
active: false,
action: ''
};
detail(rowid: number) {
this.userDetail = this.UserDb[rowid];
}
constructor(private _http: HttpClient) {
}
ngOnInit(): void {
console.log("im working");
this._http.get("http://localhost:3002/posts").subscribe((users:any)=>{
this.UserDb = users;
console.log(this.UserDb);
})
}
}
`
My entire data is being shown in the console.
data in the console. But not showing under the table
It looks that dataSource gets the value of UserDB before UserDB is populated. So, you get valid data in the console; but not in HTML. Why do you use two variables in the first place?
Hi I found the error in the code. Actually, the variables used in json needs to be exactly the same to the one used in the front-end part of the program.Like in my ts code i have used 'id' and 'name'.But in json the same variables I've written as 'Id' and 'Name'. Hence, the problem.
As show below code i want to add space after every value in listing in angular. This data are come in table view.
In HTML file
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType}} </td>
</ng-container>
In ts file
bindTableCol() : void {
if(DNHelper.loginUserData && DNHelper.loginUserData.resourcePreference1 && DNHelper.loginUserData.resourcePreference1.length > 0){
this.displayedColumns = DNHelper.getColumnTable(DNHelper.loginUserData.resourcePreference1);
this.displayedColumns.push('view_more');
this.displayedColumns.push('action');
} else {
this.displayedColumns = ['divisonName', 'categoryName', 'rType', 'resourceStatus', 'view_more', 'action'];
}
}
In Result (These are values)
CRWT1,CRWT2IA,CRWT2,CRWT3,ENG1
Expected Result
CRWT1, CRWT2IA, CRWT2, CRWT3, ENG1
There snap of generated html
To minimize the load on your application, you might also consider creating a pipe.
It could look something like this, as far as usage: <p>{{ element.rType|join:', ' }}</p>.
The transform function would look like this:
#Pipe({
name: 'join'
})
export class JoinPipe implements PipeTransform {
transform(input:Array<any>, sep = ','): string {
return input.join(sep);
}
}
You can try this :
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType.split(",").join(", ")}} </td>
</ng-container>
Use this code It will help you.
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType.replaceAll(',',', '}} </td>
</ng-container>
I am trying to sort a mat-table using the mat-sort-header. I am able to do it with common attributes like string or number.
<table #tablaClientes mat-table [dataSource]="dataSource" matSort multiTemplateDataRows>
<!-- Id Column -->
<ng-container matColumnDef="idIngreso">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Id Comprobante</th>
<td mat-cell *matCellDef="let row">{{row.idIngreso}}</td>
</ng-container>
<!-- Proveedor Column -->
<ng-container matColumnDef="idProveedor">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Nombre Proveedor</th>
<td mat-cell *matCellDef="let row">{{row.idProveedor.nombre}}</td>
</ng-container>
<!-- Fecha Compra Column -->
<ng-container matColumnDef="fechaCompra">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Fecha de Compra</th>
<td mat-cell *matCellDef="let row">{{row.fechaCompra}}</td>
</ng-container>
<!-- Fecha Recepcion Column -->
<ng-container matColumnDef="fechaRecepcion">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Fecha de Recepcion</th>
<td mat-cell *matCellDef="let row">{{row.fechaRecepcion}}</td>
</ng-container>
<!-- Monto Total Column -->
<ng-container matColumnDef="totalIngreso">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Monto Total</th>
<td mat-cell *matCellDef="let row">{{row.totalIngreso |currency}}</td>
</ng-container>
However I can't sort by idProveedor since it's an object.
Thank you very much!
The easer way is add to your dataSource a new property and sort by this new property like this SO (really if you don't need the "idProveedor" object, your dataSource can be transform to some like
this.data.forEach(x=>{
x.proveedorNombre=x.idProveedor.nombre
delete x.idProveedor
}
Another solution is create a sortingDataAccesor
this.dataSource.sortingDataAccessor = (item, property) => {
if (property=="idProveedor")
return item.nombre;
if (property=="idIngreso")
return item.idIngreso
if (property=="fechaCompra")
return item.fechaCompra
...
}
An example simple in this stackblitz
I wanted to use table with filtering from Angular Material, but I can not filter complex types (Branch.category). Actual filter working only for subjectName.
TS:
export class Subject {
id: Number = null;
subjectName: String = '';
branch: Branch = new Branch;
}
export class Branch {
category: String = '';
}
displayedColumns: string[] = ['id', 'subjectName', 'category'];
dataSource;
subjects: Subject[];
constructor() {
this.subjects = [];
this.subjects.push({id:1, subjectName: 'Biology', branch: {category: 'science'}});
this.subjects.push({id:2, subjectName: 'physics', branch: {category: 'science'}});
this.subjects.push({id:3, subjectName: 'english', branch: {category: 'humanities'}});
this.dataSource = new MatTableDataSource(this.subjects);
}
applyFilter(filterValue: string) {
console.log(filterValue);
this.dataSource.filter = filterValue.trim().toLowerCase();
}
HTML:
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="search">
</mat-form-field>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> ID </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<ng-container matColumnDef="subjectName">
<th mat-header-cell *matHeaderCellDef> subjectName </th>
<td mat-cell *matCellDef="let element"> {{element.subjectName}} </td>
</ng-container>
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef> category </th>
<td mat-cell *matCellDef="let element"> {{element.branch.category}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let element; columns: displayedColumns;"
[ngClass]="{'highlight': selectedRowIndex == element.id}"
(click)="highlight(element)"></tr>
</table>
I would like to make two separate filters: subjectName and category.
Welcome to StackOverflow, I think you might want to do a custom filter for your data table, you can do this by overriding the filterPredicate property of the data source like this:
this.dataSource.filterPredicate = (data, filter) => {
const customField = data.branch.category;
return customField === filter;
}
This is just a small example for you and it may need some fix for you to work. Just let me know how it fits and we can work on it. You can read the docs for more info here.
Edit: Found this Github issue and I think it will be useful for you.