Guide to building an interface for an object containing a nested array

While working on my Angular/TypeScript project, I encountered a challenge in processing a GET request to retrieve objects from an integration account. Here is a snippet of the response data:

{
  "value": [
    {
      "properties": {
        "publicCertificate": "<publicCertificate>",
        "createdTime": "2021-03-11T19:50:03.50193Z",
        "changedTime": "2021-03-26T07:06:12.3232003Z"
      },
      "id": "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testResourceGroup/providers/Microsoft.Logic/integrationAccounts/testIntegrationAccount/certificates/<integrationAccountCertificateName>",
      "name": "<integrationAccountCertificateName>",
      "type": "Microsoft.Logic/integrationAccounts/certificates"
    },
    {
      "properties": {
        "publicCertificate": "<publicCertificate>",
        "createdTime": "2021-05-27T12:45:33.455709Z",
        "changedTime": "2021-05-27T12:45:33.4564322Z"
      },
      "id": "/subscriptions/34adfa4f-cedf-4dc0-ba29-b6d1a69ab345/resourceGroups/testResourceGroup/providers/Microsoft.Logic/integrationAccounts/testIntegrationAccount/certificates/<integrationAccountCertificateName>",
      "name": "<integrationAccountCertificateName>",
      "type": "Microsoft.Logic/integrationAccounts/certificates"
    }
  ]
}

I am currently using the following interface structure:

export interface Certificate {
  value?: (ValueEntity)[] | null;
}

export interface ValueEntity {
  properties: Properties;
  id: string;
  name: string;
  type: string;
}
export interface Properties {
  publicCertificate: string;
  createdTime: string;
  changedTime: string;
}

My goal is to extract and display the publicCertificate, id, name, and type values from the response data. Is there a more streamlined way to define this interface?

EDIT

Below is the service I have implemented for fetching the certificates:

@Injectable()
export class IntegrationAccountService
{
  constructor(private httpclient: HttpClient, private api: ApiService) { }

  getCertificates(): Observable<any> {
    const httpOptions : Object = {
      headers: new HttpHeaders({
        'Authorization': 'Token'
      }),
      responseType: 'json'
    };
    return this.httpclient.get('URL', httpOptions);
  }
}

Component:

export class CertificateTableComponent {

  dataSource: MatTableDataSource<ValueEntity>;
  certificates: ValueEntity[] = [];
  columns: string[] = ['name', 'id', 'type', 'publicCertificate'];

  @ViewChild(MatSort, { static: true }) sort: MatSort;
  @ViewChild(MatPaginator, { static:true }) paginator: MatPaginator;

  constructor(private _integrationAccountService: IntegrationAccountService) {
  }

  ngOnInit() {

    this._integrationAccountService.getCertificates().subscribe(response => {
      this.certificates = response.data;

      this.dataSource = new MatTableDataSource(this.certificates);
      this.dataSource.sort = this.sort;
      this.dataSource.paginator = this.paginator;

    })

  }
}

Data table Component:

 <table mat-table [dataSource]="dataSource" matSort>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
      <td mat-cell *matCellDef="let row">{{ row.name }}</td>
    </ng-container>

    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th>
      <td mat-cell *matCellDef="let row">{{ row.id }}</td>
    </ng-container>

    <ng-container matColumnDef="type">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Type</th>
      <td mat-cell *matCellDef="let row">{{ row.type }}</td>
    </ng-container>

    <ng-container matColumnDef="publicCertificate">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Public Certificate</th>
      <td mat-cell *matCellDef="let row">{{ row.publicCertificate }}</td>
    </ng-container>

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

  </table>

Answer №1

Here's a helpful method that can assist you in converting your response object into the appropriate response:

retrievePropertySources(response): Array<PropertiesSource> {
    let resultList: PropertiesSource[] = [];
    resultList = response.value.map(data => {
      let res : PropertiesSource = data.properties.key.keyVault;
      res.publicCertificate = data.properties.publicCertificate;
      return res;
    });
    console.log('result ', resultList);
    return resultList;
  }

I have also created a StackBlitz for your convenience.

Enjoy coding! :)

Answer №2

Your sample JSON data appears to have some issues. Feel free to use this tool to rectify any errors. Once the JSON is valid, we will be able to assist you more effectively.

Additional Note:

It would be beneficial for your service if you specify the type instead of returning an 'Observable'. This will enhance auto-completion when accessing the result data in other parts of your code:

this.http.get<Response<ExtLanguage[]>>(languagesURL)

@Injectable()
export class integrationAccountService
{
  constructor(private httpclient: HttpClient, private api: ApiService) { }

  getcertificates(): Observable<Certificate> {
    const httpOptions : Object = {
      headers: new HttpHeaders({
        'Authorization': 'Token'
      }),
      responseType: 'json'
    };
    return this.httpclient.get<Certificate>('URL', httpOptions);
  }
}

Furthermore, ensure that your component deals with the resulting data correctly as there is no 'response.data' property. You may need to restructure the received data into a new format:

export interface FlatRow {
    name: string;
    id: string;
    type: string;
    publicCertificate: string;
}

export class CertificateTableComponent {

  dataSource: MatTableDataSource<ValueEntity>;
  //certificates: ValueEntity[] = [];
  data: FlatRow[] = [];
  columns: string[] = ['name', 'id', 'type', 'publicCertificate'];

  @ViewChild(MatSort, { static: true }) sort: MatSort;
  @ViewChild(MatPaginator, { static:true }) paginator: MatPaginator;

  constructor(private _integrationAccountService: integrationAccountService) {
  }

  ngOnInit() {

    this._integrationAccountService.getcertificates().subscribe(response => {
      //this.certificates = response.data;
      this.data = [];
      if (response.value) {
          for (let entity of response.value) {
              let row: FlatRow = {
                  name: entity.name,
                  id: entity.id,
                  type: entity.type,
                  publicCertificate: entity.properties?.publicCertificate;
              };
          }
      }

      this.dataSource = new MatTableDataSource(this.data);
      this.dataSource.sort = this.sort;
      this.dataSource.paginator = this.paginator;

    })

  }
}

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

Angular 2 - Issue with ngOnInit not being called upon routing to the same component multiple times

Currently, I am developing a web application using Angular 2. When there is data in my array, I navigate to the xyz component and store it in a service component. The ngOnInit() method of the xyz component retrieves data from the service and displays it ...

Using AngularJS with CDN: A beginner's guide

If I need to create an app using AngularJS with Cordova in Visual Studio, do I need anything else besides the Google CDN for AngularJS? <!doctype html> <html ng-app> <head> <title>My Angular App</title> <script s ...

Duplicate NgRx Effects found during loading process

My feature module is quite simple; it offers services and imports its own stats fragment as a feature: @NgModule({ imports: [ CommonModule, StoreModule.forFeature('alarms', alarmsReducer, { initialState: alarmsInitialState }), Effe ...

Different methods for organizing an array of strings based on eslint/prettier

I possess an assortment of keys that I desire to sort in alphabetical order whenever I execute eslint --fix/prettier. My inference is that such a feature does not exist by default due to its potential impact on the code's behavior. Therefore, my quer ...

Utilizing Angular 16 to Link Component Input with Parent Route Parameter

Picture a scenario where there is a component (some.component.ts) in Angular 16 that retrieves the value for its foo property from activeRoute, specifically from the parent route. Take a look at the code snippet below: @Input() foo!: string; constructor(p ...

What is the best method to include spacing between strings in an array and then combine them into a csv-friendly format?

The method I am currently employing involves the following: var authorsNameList = authors.map(x => x.FirstName + ' ' + x.LastName); Yet, this generates an outcome similar to this: Bob Smith,Bill Jones,Nancy Smith Nevertheless, the desired ...

Issue with dynamically typed object properties in Typescript codebases

Check out this TypeScript code snippet: export type Mutation = (state: State, data: unknown) => void export type Mutations = { [key: string]: Mutation } private buildMutations(): Mutations { return { ['3']: (state, data) => ...

There is no overload that matches this call in Next.js/Typescript

I encountered a type error stating that no overload matches this call. Overload 1 of 3, '(props: PolymorphicComponentProps<"web", FastOmit<Omit<AnchorHTMLAttributes, keyof InternalLinkProps> & InternalLinkProps & { ...; ...

Mapping an array based on its individual values

How can I sum values in an array of objects based on a specific condition? [{amount:100, prefix:'a'},{amount:50, prefix:'b'},{amount:70, prefix:'a'},{amount:100, prefix:'b'}] Is there a method to map and calculate t ...

Exploring methods to access specific values from an array containing multiple values using Lodash in Angular 4

Hey, I have an array that looks like this: [ 0: "Migration, MD" 1: "Lution, MD" 2: "Mover, MD" 3: "Dee" 4: "Prov10A" ] I would like to extract the values that contain the word "MD" in them. In other words, I want a result like this: [ 0: "Migratio ...

The switch statement and corresponding if-else loop consistently produce incorrect results

I'm currently facing an issue where I need to display different icons next to documents based on their file types using Angular framework. However, no matter what file type I set as the fileExtension variable (e.g., txt or jpg), it always defaults to ...

Utilizing a feature module imported from a separate Angular4 project

I have a question about setting up an Angular 4 project. Can feature modules be loaded from another Angular 4 project? I am currently attempting to maintain separate project repositories and dynamically load feature modules into the main project. This wa ...

Linking typescript error messages with their respective compiler configurations (tsconfig.json)

Is there a way to identify which compiler option corresponds to a specific Typescript error? While working with Typescript in VSCode, I often encounter errors like initializer provides no value for this binding element. (Please note that these are warnin ...

Removing a row from a FormArray within a FormGroup is not the appropriate method for managing input fields within a MatTable

I am encountering an issue with my MatTable, which is formed from a formarray. When I delete a row, the values in the input fields of my table are not updating as expected. However, the data in the object reflects the correct changes after deleting the r ...

The concept of overloaded function types in TypeScript

Is it possible to create an overloaded function type without specifying a concrete function? By examining the type of an overloaded function, it appears that using multiple call signatures on an interface or object type is the recommended approach: functi ...

Leverage functionalities from the rxjs npm package within an Angular application without the need for npm install

In the midst of updating my Angular 4 application to use rxjs version 6.3+, I discovered that many changes in rxjs are causing issues with my existing codebase. One of the new features we need to implement requires this update, but it's proving to be ...

Angular removing every query string parameters

Linked to but distinct from: How to maintain query string parameters in URL when accessing a route of an Angular 2 app? I am facing an issue with my basic Angular application where adding a query parameter results in its removal, both from the browser&apo ...

NestJS does not recognize TypeORM .env configuration in production build

Currently, I am developing a NestJS application that interacts with a postgres database using TypeORM. During the development phase (npm run start:debug), everything functions perfectly. However, when I proceed to build the application with npm run build a ...

An issue occurred while attempting to retrieve Firebase data using an HTTP GET request

When trying to retrieve my data from firestore using an HTTP get request, I encountered an error. It might be helpful if my data in firestore was stored in JSON format. I'm not sure if this is feasible. <!DOCTYPE html> <html lang="en"> ...

Effective methods for transmitting reactive form control between child and parent components in Angular 2

I am working with a nested reactive form structure and I have the following setup: Parent HTML Code <form> <child-component></child-component> <button mat-raised-button color="primary">Save</button> </form> Child HT ...