Angular Material - Get value of one column for a mat-table using a service

Viewed 2094

Situation

I have a table filled with data from interface A. But one of the columns should be filled with filtered data of interface B based on id of interface A.

What I tried

html:

<mat-table [dataSource]="dataSource">
    ...
    <ng-container matColumnDef="title">
        <mat-header-cell *matHeaderCellDef> Title</mat-header-cell>
        <mat-cell *matCellDef="let element"> {{getValueOfInterfaceB(element.id)}} </mat-cell>
    </ng-container>
    ...
</mat-table>

ts:

getValueOfInterfaceB(id: number){
    let filter: any = {Id: id}
    this.entrieService.getEntries(filter).subscribe((entries: Entry[]) => {
        console.log(entries);
    })
}

Problem

If I run the application these lines will be executed over and over. How would I solve this if I do not want to run the code over and over?


Edit: Errors getting while trying solution of @Eliseo

error TS2304: Cannot find name 'res'.
res[] => {

error TS1011: An element access expression should take an argument.
res[] => {

error TS1005: ',' expected.
res[] => {

error TS18004: No value exists in scope for the shorthand property 'res'. Either declare one or provide an initializer.
res.forEach((value,index)=>{

error TS2769: No overload matches this call.
res.forEach((value,index)=>{
2 Answers

it's better add a new property to an array of object than call a function in the .html. If the "calculated column" go from an API, you should create an array of subscriptions (use map) and using forkJoin subscribe to the array of obs

I imagine you has an array of data [{Id:0},{Id:1}....]

you make something like

//create an array of obs
const obs$[]=this.dataarray.map(x=>this.entrieService.getEntries({Id:x.id})
//subscribe to forkJoin
forkJoin(obs).subscribe(res[]=>{
    //in res[0] you has the response to this.entrieService.getEntries({Id:0})
    //in res[1] you has the response to this.entrieService.getEntries({Id:1})
    ...
    //so you can iterate using forEach and index and make some like
    res.forEach((value,index)=>{
        this.dataarray[index].newProperty=value
    })
}

Then create the dataSource. Remember, if you has a complex "column calculate", calcule the column only one time in ngOnInit

you can do it that way:

entries: Entry[] = [];
getValueOfInterfaceB(id: number){
   if (this.entries.length)
        return entries;

    let filter: any = {Id: id}
    this.entrieService.getEntries(filter).subscribe((entries: Entry[]) => {
       this.entries = entries;
        console.log(entries);
    })
}

additionally you can add async pipe in html

<mat-table [dataSource]="dataSource">
    ...
    <ng-container matColumnDef="title">
        <mat-header-cell *matHeaderCellDef> Title</mat-header-cell>
        <mat-cell *matCellDef="let element"> {{getValueOfInterfaceB(element.id) | async }} </mat-cell>
    </ng-container>
    ...
</mat-table>
Related