Nested Objects in Angular Material Table

My data source is structured in the following way:

[
  {
    "UserId": "00000000-0000-0000-0000-00000000",
    "FullName": "Person one",
    "Houses": [
      {
        "State": "Colorado",
        "City": "Denver",
        "Code": "C_D",
        "Purchased": True
      },
      {
        "State": "Texas",
        "City": "Austin",
        "Code": "A_D",
        "Purchased": True
      },
    ]
  },
 {
    "UserId": "00000000-0000-0000-0000-00000000",
    "FullName": "Person Two",
    "Houses": [
      {
        "State": "Colorado",
        "City": "Denver",
        "Code": "C_D",
        "Purchased": True
      },
      {
        "State": "Texas",
        "City": "Austin",
        "Code": "A_D",
        "Purchased": False
      },
    ]
  }
]

I am facing a challenge where I need to display each person as a row and have a column header for each city. The 'Houses' objects will be consistent for each person, but the data within them varies. Since I do not know the exact data, I cannot set the matColumnDef automatically.

The code snippet below is currently outputting only the first iteration and is not proceeding with the nested object structure:

            <table mat-table [dataSource]="dataSource" [trackBy]="myTrackById" fixedLayout recycleRows>

                <ng-container [matColumnDef]="hb.FullName" *ngFor="let hb of HousingBlocks; let i = index">
                    <th mat-header-cell *matHeaderCellDef> Full Name </th>
                    <td mat-cell *matCellDef> {{hb.FullName}} </td>
                </ng-container>
            
                <ng-container [matColumnDef]="eventApproval.UserName" *ngFor="let hb of HousingBlocks; let i = index">
                    <div *ngFor="let house of hb.Houses[i];let i = index">
                        <th mat-header-cell *matHeaderCellDef> 
                            {{house.City}}
                        </th>
                        <td mat-cell *matCellDef> 
                            {{house.Purchased}}
                        </td>
                    </div>
                </ng-container>

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

This results in the output similar to:

|Full name |Denver|
|----------|------|
|Person One|True  |
|Person Two|True  |

However, my desired format is:

|Full name  |Denver|Austin|
|-----------|------|------|
|Person One |True  |True  |
|Person Two |True  |False |

If anyone could provide assistance with populating the table correctly, it would be greatly appreciated. My loop dynamically auto-fills the displayed columns with distinct cities, eliminating any potential ID issues, but I'm struggling with the population logic.

Thank you.

Answer №1

Check out the code snippet below along with a fully functional example here:

HTML

<table mat-table class="text-list" [dataSource]="dataSource">
    <ng-container *ngFor="let column of displayedColumns; let first = first; let i = index" [matColumnDef]="column">
      <th mat-header-cell *matHeaderCellDef>{{ column }}</th>
      <ng-container *ngIf="first">
        <td mat-cell *matCellDef="let row">{{ row[column] }}</td>
      </ng-container>
      <ng-container *ngIf="!first">
        <td mat-cell *matCellDef="let row">|{{ row.Houses[i-1].Purchased }}</td>
      </ng-container>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky:true"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
  </table>

Class

export class AppComponent {
  name = 'Angular ' + VERSION.major;
  data = [
    {
      "UserId": "00000000-0000-0000-0000-00000000",
      "FullName": "Person one",
      "Houses": [
        {
          "State": "Colorado",
          "City": "Denver",
          "Code": "C_D",
          "Purchased": true
        },
        {
          "State": "Texas",
          "City": "Austin",
          "Code": "A_D",
          "Purchased": true
        },
      ]
    },
   {
      "UserId": "00000000-0000-0000-0000-00000000",
      "FullName": "Person Two",
      "Houses": [
        {
          "State": "Colorado",
          "City": "Denver",
          "Code": "C_D",
          "Purchased": true
        },
        {
          "State": "Texas",
          "City": "Austin",
          "Code": "A_D",
          "Purchased": false
        },
      ]
    }
  ];
  displayedColumns = ['FullName', 'Denver', 'Austin'];
  dataSource = new MatTableDataSource<any>([]);

  ngOnInit(): void {
    this.dataSource.data = this.data;
  }

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 'zone' property is not recognized on the 'Observable<{}>' data type

I am currently following the meteor-ionic tutorial and encountering a typescript error: typescript: src/pages/details/details.ts, line: 35 Property 'zone' does not exist on type 'Observable<{}>'. This is my componen ...

Angular - issues with delete functionality

Recently, I implemented a delete button in my Angular program to remove a specific row from both the table and the database. However, despite feeling confident that my code should work flawlessly, it seems to be failing without any visible errors. Edit - ...

What are the possibilities of utilizing both Bootstrap 5 grid and Bootstrap 4 grid interchangeably?

After working with Bootstrap 4 in my Angular 12 project for some time, I decided to upgrade to Bootstrap 5 today. While I know that some properties have changed, I thought the grid system remained unchanged. I often use "Mix and Match" columns as describe ...

When anticipating the result of an asynchronous function, you may encounter an error message similar to "Cannot find name 'await'."

// Encountering an error - 'await' is not recognized as a valid name.ts(2304) let someVariable = await (async ():someType => { // I require the use of await here, hence the need for async return someValue; })(); // The code below works ...

"Exploring Typescript return types in relation to the .getElementsByClassName() method

I am struggling to understand why there is a difference in the results when I use getElementsByClassName on two distinct elements: Check out this code snippet: let section:HTMLElement = document.getElementById("mainSection"); // When I run this, it retu ...

The functionality of the TURF booleanwithin feature is malfunctioning and not producing the

Currently, I am working on validating whether a polygon is completely within another polygon. However, there are cases where more complex polygons should return false, but turf interprets them as valid. If you'd like to see the sandbox, click here: ...

How can I transform this imperative reducer into a more declarative format using Ramda?

I am currently working with a reducer function that aggregates values in a specific way. The first argument is the aggregated value, while the second argument represents the next value. This function reduces over the same reaction argument, aggregating th ...

How to switch from Bootstrap 4 to Bootstrap 3.3 in an Angular project

As I embarked on my quest for answers, seeking out the necessary precautions for downgrading, I stumbled upon an interesting comparison. Bootstrap 3 boasts a 4-scope grid system, whereas Bootstrap 4 offers a 5-scope grid system. [xs,sm,md,lg,xl] The offs ...

Encountered in the Angular library: NG0203 error stating that inject() should only be invoked within an injection context like a constructor, factory function, or field initializer

Having recently updated my Angular project from version 9 to 15, I encountered the following issue. Any assistance would be greatly appreciated as I have been struggling with it for over 2 weeks. The problem lies within app-lib.module.ts in the Angular li ...

Limit the use of assignment within if statements in Typescript

After encountering a detrimental bug resulting from assignment in an If statement, I have come to view if-assignment as an undesirable pattern that I would like to eliminate completely in order to receive compiler warnings instead of dealing with actual bu ...

What could be causing the success of the initial Angular 9 Put request on the MVC Core 2.2 API Controller to be followed by failures on subsequent PUT requests resulting in http error 302 and/or 503?

My journey with ASP.NET Core, Angular HttpClient, and Observables has been a learning curve. A year ago, I had questions, but as time passed, these queries no longer seemed necessary. The key lesson I learned was about utilizing the [Authorize] attribute ...

Tips for styling the value of a control in an Angular Reactive Form

What is the best way to format a value in an Angular Form Control? For example, if I have a date field returned from a database with seconds and milliseconds included, how can I format it to show only day, month, year, etc. similar to using the date pipe? ...

Checking if an instance belongs to a specific class using a custom type guard in TypeScript

After successfully implementing the function isInstanceOfClass, which determines if an instance is of a given class, I am now faced with the task of writing the correct typing for it. class Parent { isInstanceOfClass<T>(arg: T): this is T { ...

Inject Angular 2 component into designated space

I am working on a website that requires a settings dialog to be loaded in a designated area upon clicking a button. The settings dialog is a component that retrieves data from REST endpoints. I am hesitant to simply insert the component and hide it as I ...

Introduce AngularJS version 2 for better web development

I'm facing an issue with using provide in Bootstrap, and here's my code snippet: import { NgModule, provide } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from &apo ...

What is the best way to pass data between sibling components using services?

I'm looking to connect a service to a component that can fetch data, share objects, and communicate with other components that are already linked to the database. I've established a service named DashService as follows: import { Injectable } fro ...

ngsw-worker.js is not integrated with Angular Universal

Our implementation of PWA (@angular/service-worker) is functioning properly in prod mode, but we are encountering an issue in dev mode where the file "ngsw-worker.js" is not being generated. Despite adjusting the registration to enable it on all environmen ...

What is the best way to set wrapper props without hiding it from showing up in attrs?

Creating a Wrapper Component with Specific Props <script setup lang="ts"> import InputBase,{ Props as InputBaseProps } from "./InputBase.vue"; interface Props extends InputBaseProps { label?: string; labelClassName?: string; ...

Service in Angular2+ that broadcasts notifications to multiple components and aggregates results for evaluation

My objective is to develop a service that, when invoked, triggers an event and waits for subscribers to return data. Once all subscribers have responded to the event, the component that initiated the service call can proceed with their feedback. I explore ...