0

When I select the add button in the patient-allergies.component.ts, select options for the addition of patient allergies and click save, I receive the following error:

ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed.

I cannot understand why I am receiving this error as I cast the object to an array when it is passed from the rest-api.service.ts through _patientAllergies.next().

patient-allergies.component.html

<mat-card class="mat-typography">
  <mat-card-title>Allergies</mat-card-title>
  <mat-card-content>
    <hr>
    <div *ngFor="let patientAllergy of this.patientAllergies">
      <h3 *ngIf="!patientAllergy.nickname"> {{ patientAllergy.fullname }} </h3>
      <h3 *ngIf="patientAllergy.nickname"> {{ patientAllergy.fullname }} ({{ patientAllergy.nickname }}) </h3>
    </div>
  </mat-card-content>
  <mat-card-actions *ngIf="isEdit">
    <button mat-button class="dark" (click)="onAdd()">ADD</button>
    <button mat-button class="dark" (click)="onRemove()">REMOVE</button>
  </mat-card-actions>
</mat-card>

<mat-card *ngIf="isLoading" style="display: flex; justify-content: center; align-items: center">
  <mat-progress-spinner class="mat-spinner-color" mode="indeterminate"></mat-progress-spinner>
</mat-card>

patient-allergies.component.ts

import {Component, OnInit, Input, Pipe, PipeTransform} from '@angular/core';
import {RestAPIService} from 'src/app/rest-api.service';
import {ActivatedRoute} from '@angular/router';
import {MatDialog} from '@angular/material';

@Component({selector: 'app-patient-allergies', templateUrl: './patient-allergies.component.html', styleUrls: ['./patient-allergies.component.css']})
export class PatientAllergiesComponent implements OnInit {

    @Input()isEdit : boolean = false;

    constructor(private restAPIService : RestAPIService, private route : ActivatedRoute, public dialog : MatDialog) {}

    isLoading : boolean;
    patientAllergies;
    subscription = null;

    ngOnInit() {
        this.isLoading = true;
        this
            .restAPIService
            .getPatientAllergies(this.route.snapshot.params.id);

        this.subscription = this
            .restAPIService
            .patientAllergies
            .subscribe((patAllergies) => {
                this.patientAllergies = patAllergies as [];
                this.isLoading = false;
            });
    }

    onAdd() {
        let dRef = this
            .dialog
            .open(AllergiesDialogComponent, {
                disableClose: true,
                height: '800px',
                width: '600px',
                data: {
                    isAdding: true,
                    patientAllergies: this.patientAllergies
                }
            });

        dRef
            .afterClosed()
            .subscribe((res) => {
                res.forEach((ele) => {
                    this
                        .restAPIService
                        .addPatientAllergies(this.route.snapshot.params.id, ele.value.allergyID);
                });
            });
    }

    onRemove() {
        let dRef = this
            .dialog
            .open(AllergiesDialogComponent, {
                disableClose: true,
                height: '800px',
                width: '600px',
                data: {
                    isAdding: false,
                    patientAllergies: this.patientAllergies
                }
            });

        dRef
            .afterClosed()
            .subscribe((res) => {
                res.forEach((ele) => {
                    this
                        .restAPIService
                        .deletePatientAllergies(this.route.snapshot.params.id, ele.value.allergyID);
                });
            })
    }
}

import {Inject} from '@angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';
import {DialogData} from 'src/app/patient/patient.component';

@Component({selector: 'app-allergies-dialog', templateUrl: './allergies-dialog.component.html', styleUrls: ['./allergies-dialog.component.css']})
export class AllergiesDialogComponent implements OnInit {
    allergies = [];
    filterName : string;
    subscription;

    constructor(public dialogRef : MatDialogRef < AllergiesDialogComponent >, @Inject(MAT_DIALOG_DATA)public data : DialogData, private restAPIService : RestAPIService) {}

    ngOnInit() {
        this
            .restAPIService
            .getAllergies();

        if (this.data['isAdding']) {
            this.subscription = this
                .restAPIService
                .allergies
                .subscribe((allergies) => {
                    let allergiesArr = allergies as [];
                    this.allergies = [];

                    let patientAllergyNames = [];
                    this
                        .data['patientAllergies']
                        .forEach(patientAllergy => {
                            patientAllergyNames.push(patientAllergy['fullname'])
                        });

                    allergiesArr.forEach(allergy => {
                        if (!patientAllergyNames.includes(allergy['fullname'])) 
                            this.allergies.push(allergy);
                        }
                    );
                })
        } else {
            this.allergies = this.data['patientAllergies'];
        }
    }

    onClose(selectedOptions) {
        if (this.data['isAdding']) 
            this.subscription.unsubscribe();

        // either [] or the IDs of the objects to add/remove
        this
            .dialogRef
            .close(selectedOptions);
    }
}

@Pipe({name: 'filterOnName'})
export class filterNames implements PipeTransform {
    transform(listOfObjects : any, nameToFilter : string) : any {
        let allergyArr = listOfObjects as[];
        let matchedObjects = [];

        if (!listOfObjects) 
            return null;
        if (!nameToFilter) 
            return listOfObjects;

        allergyArr.forEach(allergyObj => {
            let fullname : string = allergyObj['fullname'];
            let nickname : string = allergyObj['nickname'];

            let fullnameLower = fullname.toLowerCase();
            let nicknameLower = fullname.toLowerCase();
            let filter = nameToFilter.toLowerCase();

            if (nickname) {
                if ((fullnameLower.includes(filter) || nicknameLower.includes(filter))) 
                    matchedObjects.push(allergyObj);
                }
            else {
                if (fullnameLower.includes(filter)) 
                    matchedObjects.push(allergyObj);
                }
            });

        return matchedObjects;
    }
}

rest-api.service.ts

    private _allergies;
    private allergiesSubject = new Subject();
    allergies = this
        .allergiesSubject
        .asObservable();

    private _patientAllergies;
    private patientAllergiesSubject = new Subject();
    patientAllergies = this
        .patientAllergiesSubject
        .asObservable();

getPatientAllergies(patientID) {
    const request = {
        headers: {},
        response: true
    };

    API
        .get('DiagnetAPI', '/v1/patients/' + patientID + '/allergies', request)
        .then(resp => {
            this._patientAllergies = resp.data;
            this
                .patientAllergiesSubject
                .next(this._patientAllergies);
        })
        .catch((err) => console.log(err))
}

addPatientAllergies(patientID, allergyID) {
    const request = {
        headers: {},
        response: true,
        body: allergyID
    };

    API
        .post('DiagnetAPI', '/v1/patients/' + patientID + '/allergies', request)
        .then(resp => {
            console.log(resp.data);
            this._patientAllergies = resp.data;
            this
                .patientAllergiesSubject
                .next(this._patientAllergies);
        })
        .then(() => {
           this.getPatientAllergies(patientID);
        })
        .catch((err) => console.log(err))
}

deletePatientAllergies(patientID, allergyID) {
    const request = {
        headers: {},
        response: true
    };

    API
        .del('DiagnetAPI', '/v1/patients/' + patientID + '/allergies/' + allergyID, request)
        .then((res) => console.log(res))
        .then(() => {
            this.getPatientAllergies(patientID);
        })
        .catch((err) => console.log(err))
}
mrrain
  • 134
  • 1
  • 12
  • why have you designed this in this way? the error is because your response from your service is not an array. it doesn't matter if you tell your compiler it is, it needs to actually be an array. `as []` does nothing to the response itself. just tells the compiler "shut up, i know what i'm doing" – bryan60 Mar 26 '20 at 17:20

1 Answers1

1

If your response from the api is not an array but an object, you can use the keyvalue pipe in your *ngFor loop. In your case patientAllergy would be an object with two keys, the key and the value so you can access the nickname like this: patientAllergy.value.nickname

your template:

<div *ngFor="let patientAllergy of this.patientAllergies | keyvalue">
   <h3 *ngIf="!patientAllergy.value.nickname"> {{ patientAllergy.value.fullname }} </h3>
   <h3 *ngIf="patientAllergy.value.nickname"> {{ patientAllergy.value.fullname }} ({{ patientAllergy.value.nickname }}) </h3>
</div>
Frank Adrian
  • 1,214
  • 13
  • 24