Properly showcase a list of data in a mat-table with dynamically grouped columns

I have encountered an issue that is proving difficult for me to solve.

Upon making a request to my API, I receive a dataset structured like this:

[
  {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"},
  {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType: "02XX", points: 15, type: "Type_1"},
  {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType: "03XX", points: 1,  type: "Type_1"},
  {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
  {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType: "05XX", points: 26, type: "Type_2"}
]

In order to structure my data by type, I use the following grouping method:

Array.prototype.groupBy = function(k) {
   return this.reduce((acc, item) => (acc[item[k]] = [...(acc[item[k]] || []), item], acc), {});
};

var TABLE_DATA = Object.values(API_DATA.groupBy("type"));

[
  [
    {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"},
    {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType: "02XX", points: 15, type: "Type_1"},
    {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType: "03XX", points: 1,  type: "Type_1"}
  ],
  [
    {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
    {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType: "05XX", points: 26, type: "Type_2"}
  ]
]

To display this data using an Angular Material mat-table as shown in the example image https://i.sstatic.net/yvDwk.png, I need to navigate through a list of lists. This poses a challenge in correctly rendering the items within the table.

The table columns should ideally be dynamic, but I am unsure how to achieve this with Angular Material:

<ng-container matColumnDef="{{column}}" *ngFor="let column of definedColumns">
  <th mat-header-cell *matHeaderCellDef> {{column}} </th>
  <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
</ng-container>

Access Stackblitz link here

Your assistance on this matter is greatly appreciated.

Answer №1

To achieve the desired outcome, you must iterate over your dataset and assign the various values to your new object.

For a functional demonstration, refer to this live stack example: https://stackblitz.com/edit/datasource-mat-table-with-group-by-xyz123

The following functions extracted from the stackblitz are relevant:

  updatedData: ElementType[];

  // Transforms "Grade X" into "gradeX"
  transformGradeToKey(grade: string): string{
    return `grade${grade.split(" ")[1]}`;
  }

  // Consider appropriate typing for parameter "data"
  updateDataFromAPI(data: any[]): void {
  // Utilizing a map to avoid full list iteration for type === "someType" check every time
  let transformedData = new Map<string, ElementType>();
   
   data.forEach(value => {
     let currentVal = transformedData.get(value.type) || {type: value.type, gradeA: undefined, gradeB: undefined, gradeC: undefined};
     const gradeKey = this.transformGradeToKey(value.grade);
     const newGradeValue: number = (currentVal[gradeKey] || 0) + value.points;
     currentVal = {...currentVal, [gradeKey]: newGradeValue };
     transformedData.set(value.type, currentVal);
   })
   
   this.updatedData = [...transformedData].map(([key, val]) => val);
  }

Answer №2

Initialization of data while grouping by type :

ngOnInit() {
    this.API_DATA = [
      {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType:   "01XX", points: 22, type: "Type_1"},
      {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType:   "02XX", points: 15, type: "Type_1"},
      {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType:   "03XX", points: 1,  type: "Type_1"},
      {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
      {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType:   "05XX", points: 16, type: "Type_2"}
    ];

    const key = 'type'
    const dataTable = Object.values(this.API_DATA.reduce((acc, item) => (acc[item[key]] = [...(acc[item[key]] || []), item], acc), {}));

    this.dataSource = dataTable;
  }

mat-table in Angular material with customizable columns :

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  
  <ng-container matColumnDef="{{column}}" *ngFor="let column of definedColumns; let index = index;">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <td mat-cell *matCellDef="let elements">
      <span *ngFor="let element of elements; let first = first;">
        <span *ngIf="index == 0 && first">{{element.type}}</span>
        <span *ngIf="element.grade == column">{{element.points}}</span>
      </span>
    </td>
  </ng-container>

  <ng-container matColumnDef="action">
    <th mat-header-cell *matHeaderCellDef class="text-right">
        <button mat-icon-button (click)="log('add')">
            <mat-icon color="accent">add_circle_outline</mat-icon>
        </button>
    </th>
    <td mat-cell *matCellDef="let gradingIndex" class="text-right">
        <button mat-icon-button>
            <mat-icon color="primary" (click)="log(gradingIndex)">edit</mat-icon>
        </button>
        <button mat-icon-button (click)="log(gradingIndex)">
            <mat-icon color="warn">delete</mat-icon>
        </button>
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

Outcome:

https://example.com/image.png

Live demo: here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The component is failing to store its value within the database

I'm encountering an problem when attempting to save an option in the database. To address this issue, I created a component in Svelte called StatePicker that is responsible for saving US States. However, when I try to save it in the database using a ...

Having trouble with my implementation of ConvertFrom-Json using an array in an Azure ARM template parameter - seeking help in PowerShell

I'm attempting to include a $paramObject in a fresh ARM template deployment. I suspect that there is something missing in my PowerShell script to properly convert the arrays for template usage. $ResourceGroupName = "rg-testtemplate" New-AzRes ...

What is the location of the Typescript project path in Visual Studio 2015 Cordova?

In my development journey, I decided to create a Typescript blank Cordova project within Visual Studio 2015. After adding a small test bit of ts code... function onResume() { // TODO: This application has been reactivated. Restore application st ...

Error occurs when attempting to save and update the model in the store without establishing a connection to the backend

Looking to update my model in the store without connecting to the backend. Once successfully updated, I need to retrieve the updated model using its id. However, I'm encountering an error when trying to push the model to the store (updating the exist ...

TypeScript does not recognize the $.ajax function

Looking for help with this code snippet: $.ajax({ url: modal.href, dataType: 'json', type: 'POST', data: modal.$form.serializeArray() }) .done(onSubmitDone) .fail(onSubmitFail); ...

Guide on integrating a plain Service/Provider into nest.js

I recently created a basic TypeScript class in nest.js called JwtTokenService.js. // JwtTokenService.js import { Injectable, Optional } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { JwtPayload } from ' ...

When dealing with ReactJS, utilize the onChange event for handling updates to nested

I am currently learning ReactJS and struggling with a simple logic problem (I'm not very good at JS). I have a form that includes fields for name, email, and message. @ContactUsNew = React.createClass getInitialState: -> message: @props.mess ...

Use JavaScript to retrieve a value and display it on a PHP page

I am trying to create a system that can generate and deliver JSON data. Here is the PHP code I have so far: <?php header("Content-Type:application/json"); require "data.php"; if(!empty($_GET['name'])) { $name=$_GET['name']; ...

Attempting to modify a JSON file within a React application

I recently obtained a JSON file named 'DealerList.json' which I managed to import into my app using the following code snippet: import DealerList from './json/DealerList' let tasks = DealerList; The tasks now store the JSON data and I ...

Searching for JSON nodes with regular expressions

In a lengthy JSON string, I am trying to extract the value of a specific node within a particular node. For example, extracting the description node from the person node: "person":{"age":"10", "description":"example",job:{"title":"sales","salary":"$300 ...

Navigating Paths and Passing Parameters in Angular Routing

My application is a Single Page Application (SPA) that requires specific arguments to be passed in order to launch successfully. Users typically access the SPA by using direct links such as https://myapp.com/index.html?test=123&test2=12314 or https://m ...

Testing the service in Angular that has multiple dependencies using unit tests

I am seeking guidance on testing the functionality of the Service below, which requires two dependencies in its constructor. I am unsure how to set up the testing environment and how to incorporate MatDialog in the testing process. Should simulated reque ...

How can you update ngModel in Angular and mark the form as dirty or invalid programmatically?

My form is connected to a model as shown below In the component file: myTextModel: string; updateMyTextModel(): void { this.myTextModel = "updated model value"; //todo- set form dirty (or invalid or touched) here } Html template: <form #test ...

Adding an object to an array in Postgres with TypeORM

I am currently facing an issue with the column in my Postgres database that has a data type of json. The code snippet for this scenario is as follows: @Column({ type: 'jsonb', nullable: false, default: [] }) us ...

Facing issues with Observable and HTTP JSON in Angular

I've been struggling with an issue where I'm unable to display the "datos" variable in the *ngFor loop. I suspect the problem lies in the rendering process, so I tried implementing "Observable", but unfortunately, it didn't resolve the issue ...

JSON only retrieve the corresponding data

I am looking to send a JSON object back to Postman without including a "title" like: { "name": { "name": "Three Rivers Campground", "lengthLimit": 25, "elevation": 6332, ...

how to include extra arguments in json.dump in python2

In my python2 code, I am using json.dump with a custom encoder and I need to pass an additional parameter to the encoder like this: json.dump(data, fp, type, cls=MyEncoder) After reading about it in How to pass parameters to a custom JSONEncoder default( ...

Encountered a Next-Auth Error: Unable to fetch data, TypeError: fetch failed within

I've been struggling with a unique issue that I haven't found a solution for in any other forum. My Configuration NextJS: v13.0.3 NextAuth: v4.16.4 npm: v8.19.2 node: v18.12.1 When the Issue Arises This particular error only occurs in the pr ...

Error: Unable to inject HttpClient dependency. Angular 5

I recently switched to using the Angular template in Visual Studio 2017 and decided to update to Angular 5.2. However, I encountered an error while trying to make a http call from the service class. The error message I received is: https://i.sstatic.net/p ...

Organize the JSON formatting in cakePHP for optimal output

What is the most effective way to customize the JSON output in cakephp 2.x? Here is the code snippet from my controller: $questions = $this->Question->find('threaded', array( 'fields' => array( 'label', &a ...