0

card.service.ts

@Injectable({
providedIn: 'root'
})

export class CardService {
drugs: Drugs = [];

public objObservable: any;
private objObserver: any;

constructor() {
    this.objObservable = new Observable((localObserver) => {
        this.objObserver = localObserver; // Convert this.objObserver from any to an observer object
        this.objObserver.next(this.drugs); // Connect this.drugs to observable object by observer
    });
}

getDrugs(): Observable<Drugs> {
    return this.objObservable;
}

addDrug(newDrug: Drug) {
    this.drugs = [...this.drugs, newDrug];
    return this.objObserver.next(this.drugs);
}

removeDrug(neo4jId: string) {
    this.drugs = this.drugs.filter((item: Drug) => item.neo4jId !== neo4jId);
    return this.objObserver.next(this.drugs);
}

I am using this service to add and remove some Drugs into an Observable in my Home component. In the card Component i want to loop in this Observable and give out the values i need to show in the html.

card.component.html

<div>
{{  this.cardService.getDrugs() | async | json }}
</div>

this one is giving me all the output of the observable as json and then i tried to do something like

<div>
{{  (this.cardService.getDrugs() | async | json).type }}
</div>

to only show me the type, but this is not working. How can i loop through all Objects in this observable and output only the types f.e.?

Drug Model:

export interface Drug {

neo4jId?: string;
drugId?: string;
tradingName: string;
type: string;
quantity: number;
expire: Date;
entryDate: Date;
lastModified?: Date;
slot: number;
substances?: Substance[]
};

export interface Drugs extends Array<Drug> { }
  • It is a little unclear. Is `drugs: Drugs = [];` an array of type `Drugs`. Or is it meant to be `drugs = Drug[]` an array of type `Drug`? – ruth Mar 18 '20 at 11:22

3 Answers3

0

Is there any specific purpose to separating drugs container and it's observable? Please check if the following fulfills the requirement

@Injectable({
 providedIn: 'root'
})
export class CardService {
 private drugsSource = new BehaviorSubject<Array<Drug>>([]);
 private drugs$ = this.drugsSource.asObservable();

 constructor() { }

 getDrugs(): any {
   return this.drugs$;
 }

 addDrug(newDrug: Drug) {
   this.drugsSource.next([...this.drugsSource.getValue(), newDrug]);
 }

 removeDrug(neo4jId: string) {
   this.drugsSource.next(this.drugsSource.getValue().filter((item: Drug) => item.neo4jId !== neo4jId));
 }
}

It doesn't make much sense to return obserables from add and remove method when there is a separate get method. So subscribe to it whenever you add or remove values.

Component

this._cardService.addDrug(drug);
this._cardService.getDrugs().subscribe(drugs => { 
  // handle value 
});

// similarly for removing
this._cardService.removeDrug('34');
this._cardService.getDrugs().subscribe(drugs => { 
  // handle value 
});

Update To display type in HTML, you need to write a pipe.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'drugsType'
})
export class TypeOfPipe implements PipeTransform {

  transform(drugs: any): any {
    let result = [];
    for (const drug of drugs) {
      let obj = {};
      for (const key of Object.keys(drug)) {
        obj[key] = typeof drug[key];
      }
      result.push(obj);
    }
    return result;
  }

}

Working example: Stackblitz

ruth
  • 29,535
  • 4
  • 30
  • 57
0

I usually use a BehaviorSubject for what you are trying to accomplish. See if this works for you. You can check a working example here https://stackblitz.com/edit/ng-service-behaviorsubject

import { Injectable } from '@angular/core'
import { BehaviorSubject, Observable } from 'rxjs';

export interface Drug {
  neo4jId: string;
  Description: string;
}

@Injectable({
  providedIn: 'root'
})
export class CardService {
  private bsDrugs = new BehaviorSubject<Drug[]>([])

  constructor() {
  }

  getDrugs(): Observable<Drug[]> {
      return this.bsDrugs;
  }

  addDrug(newDrug: Drug) {
      let drugs = [...this.bsDrugs.value, newDrug];
      this.bsDrugs.next(drugs);
  }

  removeDrug(neo4jId?: string) {
    let drugs = [];
    if (neo4jId) {
      drugs = this.bsDrugs.value.filter((item: Drug) => item.neo4jId !== neo4jId);
    } else {
      if (this.bsDrugs.value.length > 0 ) {
        this.bsDrugs.value.pop();
        drugs = this.bsDrugs.value;
      }
    }

    this.bsDrugs.next(drugs);
  }
}
wFitz
  • 1,266
  • 8
  • 13
0

i solved the problem like this

@Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.css']
})
export class CardComponent implements OnInit {
  drugList: Observable<Array<Drug>>;
  subscription: Subscription;

constructor(private cardService: CardService) { }

ngOnInit() {

 this.drugList = this.cardService.getDrugs();

}

}

and in the html

<div *ngFor="let drug of drugList | async">
  <p>{{   drug.tradingName    }}</p>
  <p>{{   drug.type  }}</p>
  <p>{{   drug.quantity  }}</p>
  <p>{{   drug.slot  }}</p>
</div>

the style can be made better of course. My point was just how to get access to the Objects in the Observable