It might seem stupid to some but most of my confusion is caused by my frustration.
I am making API calls to some endpoints from this page: https://beacon-network.org/#/developers/api/beacon-network#bn-beacons
I have no problem at the service I am able to get the data. My service.ts:
import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {Organization} from './organization'; // it is an interface that has id and name
import {Beacons} from './beacons'; // it is an interface that has id and name
@Injectable({
providedIn: 'root'
})
export class BeaconService {
constructor(private http: HttpClient) { }
public fetchOrganizations(): Observable<Organization[]> {
return this.http.get<Organization[]>('https://beacon-network.org/api/organizations');
}
public fetchBeacons(): Observable<Beacons[]> {
return this.http.get<Beacons[]>('https://beacon-network.org/api/beacons');
}
This is my component.html
<table mat-table [dataSource]="organizations$"
>
<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="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="beacons">
<th mat-header-cell *matHeaderCellDef>Beacons</th>
<td mat-cell *matCellDef="let element"> {{beaconCount}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
This gives me a table of ID, Name and Beacons. ID and Name are matched correctly. My problem is that beacons(beacon count) should have different numbers with the right match of the company name, I checked this with Postman and as an example Wellcome Trust Sanger Institute should return 5. According to what name I get I get 1, 2, 5 or 0 for all. Some outputs should be 21, 5, 4 etc.
Finally this is my component.ts:
import {Component, OnInit} from '@angular/core';
import {Observable, Subscription} from 'rxjs';
import {BeaconService} from './beacon.service';
import {Organization} from './organization';
@Component({
selector: 'app-beacon',
templateUrl: './beacon.component.html',
styleUrls: ['./beacon.component.css']
})
export class BeaconComponent implements OnInit {
organizations$: Observable<Organization[]>;
beacon: any = {};
displayedColumns = ['id', 'name', 'beacons'];
organizations: Array<any>;
organizationId: string;
organizationName: string;
beaconData: any = {};
beacons: Array<any>;
beaconCount = 0;
organizationNameArray: Array<any> = [];
constructor(private beaconService: BeaconService) {
this.organizations$ = this.beaconService.fetchOrganizations();
}
ngOnInit() {
this.beaconService.fetchOrganizations().subscribe((organizationData) => {
this.organizations = organizationData;
for (let i = 0; i < this.organizations.length; i ) {
this.organizationId = this.organizations[i].id;
this.organizationName = this.organizations[i].name;
this.organizationNameArray.push(this.organizationName);
}
return this.organizationNameArray;
});
this.beaconService.fetchBeacons().subscribe(beacons => {
let organizationNameInBeacon;
this.beacons = beacons;
for (const beacon of this.beacons) {
this.beaconCount = 0;
for (const org of this.organizations) {
if (beacon.organization === org.name) {
organizationNameInBeacon = beacon.organization;
this.beaconCount ;
}
}
}
return this.beaconCount;
});
}
}
My output should be the name of the organization and the right beacon count for that. I need help here.
Response summary should be something like: Found: 6, Not Found: 39, Not Applicable:36
CodePudding user response:
I would just fork join the to response and then match them together and just use that observable for binding.
export class BeaconComponent implements OnInit {
displayedColumns = ['id', 'name', 'beacons'];
fetching:boolean
countedBeaconOrgs$: Observable<OrganizationBecons[]>;
constructor(private beaconService: BeaconService) {}
ngOnInit() {
this.fetching = true;
this.countedBeaconOrgs$ = forkJoin([
this.beaconService.fetchOrganizations(),
this.beaconService.fetchBeacons(),
]).pipe(
map(([orgs, beacons]): OrganizationBecons[] => {
const countedOrgs: OrganizationBecons[] = [];
for (const org of orgs) {
countedOrgs.push({
...org,
beaconCount: beacons.filter((b) => b.organization == org.name)
.length,
});
}
return countedOrgs;
}),
tap(()=> {
this.fetching=false;
})
);
}
}
export interface OrganizationBecons extends Organization {
beaconCount: number;
}
the binding
<table mat-table [dataSource]="countedBeaconOrgs$" >
<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="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *matCellDef="let element">{{ element.name }}</td>
</ng-container>
<ng-container matColumnDef="beacons">
<th mat-header-cell *matHeaderCellDef>Beacon Count</th>
<td mat-cell *matCellDef="let element">{{ element.beaconCount }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<h1 *ngIf="fetching">Loading</h1>
updated stackblitz: https://stackblitz.com/edit/angular-vjttsn?file=src/beacon/beacon.component.ts
edit: Added ugly loading to the requests.