Home > Net >  How to Get Data From One Array of Objects into another in Array of Objects in TypeScript
How to Get Data From One Array of Objects into another in Array of Objects in TypeScript

Time:12-11

I have a get request in a component that returns a response

  getPaymentIntents():Observable<Payment>>{
    const url: string = 'https://store.com//payments';

    return this.http.get<Payment>>
    (url);
  }

The response data looks something like this (the "Payment" type)

[
    {
        "id": "pi_3K4B432423dqM1gTYncsL",
        "amount": 2000,
        "amount_capturable": 0,
        "amount_received": 0,
        "application": null,
        "canceled_at": null,
        "cancellation_reason": null,
        "created": 1638911287,
        "currency": "usd",
        "customer": "cus_KjDBkdsaHIT6AN"
},
    {
        "id": "pi_3K4BW7EE9YQoA1qM1gTYncsL",
        "amount": 1000,
        "amount_capturable": 0,
        "amount_received": 0,
        "application": null,
        "canceled_at": null,
        "cancellation_reason": null,
        "created": 1638913687,
        "currency": "usd",
        "customer": "cus_KjDBkxEVHIT6AN"
}
]

I want this data to be in a "Material Table" https://material.angular.io/components/table/overview

But I only want it to display a subset of the data. (In the future I will want to combine another response's data into the table as well)

The type I want to pass to the table as a dataSource is this

export interface OrderToProcess{
  Id: string,
  Amount: number,
  Currency: string
}

How do I go about converting one type into the other, I've tried filter() map() object.entries() and I'm sure I'm not using them right but none seem to do what I am after.

Thanks for any help!

CodePudding user response:

You are indeed looking for map. Assuming we have the following function to mock your HTTP call:

  // Imports needed for rest of example code
  import { map, Observable, of } from 'rxjs';

  /**
   * getPaymentIntents mocks HTTP call with static data
   */
  getPaymentIntents(): Observable<any> {
    return of([
      {
        id: 'pi_3K4B432423dqM1gTYncsL',
        amount: 2000,
        amount_capturable: 0,
        amount_received: 0,
        application: null,
        canceled_at: null,
        cancellation_reason: null,
        created: 1638911287,
        currency: 'usd',
        customer: 'cus_KjDBkdsaHIT6AN',
      },
      {
        id: 'pi_3K4BW7EE9YQoA1qM1gTYncsL',
        amount: 1000,
        amount_capturable: 0,
        amount_received: 0,
        application: null,
        canceled_at: null,
        cancellation_reason: null,
        created: 1638913687,
        currency: 'usd',
        customer: 'cus_KjDBkxEVHIT6AN',
      },
    ]);
  }
}

You can map to your type in your component using the following (or something similar:

  // Table columns
  displayedColumns: string[] = ['id', 'amount', 'currency'];
  // Our table data source
  dataSource$: Observable<OrderToProcess[]>;
  constructor() {
    this.dataSource$ = this.getPaymentIntents().pipe(
      // Map data to an array of type OrderToProcess.
      map((data) => {
        let transformedData: OrderToProcess[] = [];
        for (let i = 0; i < data.length; i  ) {
          transformedData.push({
            Id: data[i].id,
            Amount: data[i].amount,
            Currency: data[i].currency,
          });
        }
        return transformedData;
      })
    );
  }

And to display them in your table:

<table mat-table [dataSource]="dataSource$" >
  <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="amount">
    <th mat-header-cell *matHeaderCellDef>Amount</th>
    <td mat-cell *matCellDef="let element">{{element.Amount}}</td>
  </ng-container>

  <ng-container matColumnDef="currency">
    <th mat-header-cell *matHeaderCellDef>Currency</th>
    <td mat-cell *matCellDef="let element">{{element.Currency}}</td>
  </ng-container>

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

If you paste this in to your project I believe it should help you accomplish what you're aiming for.

CodePudding user response:

I guess that you just need to do this:

TS

...
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
...

// Declare your interface before declaring your Class, right after your imports
export interface OrderToProcess{
  Id: string,
  Amount: number,
  Currency: string
}

...
// In your class attributes declaration
dataSource$: Observable<OrderToProcess[]>;
...

constructor() {

    this.dataSource$ = this.getPaymentIntents()
    .pipe(
      map( (data:Payment[]) => {

        let ordersToProcess: OrderToProcess[] = data.map( payment => 
           {
              Id: payment.id,
              Amount: payment.amount,
              Currency: payment.currency
           }
        );

        return ordersToProcess;

      }) //end map rxjs
    ); //end pipe rxjs

}

Then, in your HTML just pass the dataSource$ observable to your material table as usual ([dataSource]="dataSource$")

NOTE: I'm not completely sure, but maybe you can even simplify it further just by doing the following:


 this.dataSource$ = this.getPaymentIntents()
    .pipe(
      map( (data:Payment[]) => data.map( payment => 
           {
              Id: payment.id,
              Amount: payment.amount,
              Currency: payment.currency
           }
    )));
  • Related