0

In my service class, I have two string arrays that I'm trying to fill with data from HTTP get request with the following code:

keys: string[];
values: string[];

constructor(private entityDetailsService: LinkedEntityVocabulariesService) {
    this.getEntityDetails().subscribe(data => {
        this.keys = Object.keys(data[0]);
        this.values = Object.values(data[0]);

        console.log("inside subscribe: keys: " + this.keys + ", values: " + this.values);
    });
    console.log("outside subscribe: keys: " + this.keys + ", values: " + this.values);
    this.getProperties();
}

and then I have a method called in the constructor, where Im trying to use those arrays:

getProperties() {
    console.log(this.keys);
    console.log(this.values);
}

And I'm getting the following output in the console: enter image description here

I understand that the subscription is still being executed when getProperties is finished already. What I don't know, is how to make getProperties wait and then execute with proper data in string arrays. Can someone help me with a solution? I just need to get that data outside of subscribing somehow, so I can use it in the other method.

Soroush Chehresa
  • 5,490
  • 1
  • 14
  • 29
MWPodgorni
  • 83
  • 2
  • 9

3 Answers3

0

This should work.

keys: string[];
values: string[];

constructor(private entityDetailsService: LinkedEntityVocabulariesService) {
    this.getEntityDetails().subscribe(data => {
        this.keys = Object.keys(data[0]);
        this.values = Object.values(data[0]);
        this.getProperties();
        console.log("inside subscribe: keys: " + this.keys + ", values: " + this.values);
    });
    console.log("outside subscribe: keys: " + this.keys + ", values: " + this.values);

}
Abu Taha
  • 251
  • 1
  • 14
0

You should change your properties:

keys: string[];
values: string[];

into Observables:

keys$: Observable<string[]>;
values$: Observable<string[]>;

your code will then look like that:

constructor(private entityDetailsService: LinkedEntityVocabulariesService) {
  const entityDetails$ = this.getEntityDetails().pipe(shareReplay(1));

  this.keys$ = entityDetails$.pipe(map(data => Object.keys(data[0]));
  this.values$ = entityDetails$.pipe(map(data => Object.values(data[0]));
}

Then you can use async pipe inside your component template:

<div>
 {{keys$ | async}}
</div>

<div>
 {{values$ | async}}
</div>

<-- or something like that -->
<child-component-1 [keys]="keys$ | async"></child-component-1>
<child-component-2 [values]="values$ | async"></child-component-2>

What is your use case inside template? Depending on that you should also consider changing keys$ and values$ into other Observable.

For example you could create data$: Observable<YourObject>

constructor(private entityDetailsService: LinkedEntityVocabulariesService) {
  this.data$ = this.getEntityDetails().pipe(shareReplay(1));
}

and in template use keyvalue pipe (https://angular.io/api/common/KeyValuePipe)

<div *ngFor="let item of data$ | async | keyvalue">
      {{item.key}}:{{item.value}}
</div>

Hope this helps

Mat_90
  • 86
  • 1
  • 4
0

I guess it can be managed with Subjects. Something like this (you know, as rule I try avoid http calls in constructor):

keys$: Subject<string[]> = new Subject();//<== use Subjects
private _values$: BehaviorSubject<string[]> = new BehaviorSubject(null);//<== or Behaviour Subject

get values(): string[] { return this._values.getValue()}

constructor(private entityDetailsService: LinkedEntityVocabulariesService) {
    this.getEntityDetails().subscribe(data => {
        this.keys.next(Object.keys(data[0]));
        this.values.next(Object.values(data[0]));
    });

    console.log(this.values)// to get current state

    combineLatest(this.keys$, this.values$)
    .subscribe(([keys, values]) => {
       //to get last state
       console.log(keys);
       console.log(values);
    });
}