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
}
)));