0

I'am working on an Angular Project and I have a Problem which I didn't mange to solve...

//part of class Data
constructor(private fetchData: FetchData) {
  this.subscription = timer(0, 1000000).pipe(
        switchMap(() => this.fetchData.getData())
    ).subscribe((result) => this.data = result);
}

private data: any;
private subscription: Subscription;

public getData(): Object {
    return this.data.data_property;
}

It reports errors because of a runtime condition and I want to solve this Problem by waiting for the variable to be filled. The whole app needs it, so it is pretty important. I want to solve it with an Observable from Angulars rxjs but I didn't really got it to work, I'am pretty new to this. By the way, both, the FetchData and the Data Class are @Injectable Services.

If somebody has an additional Tip for me to convert the variable data to a type of Interface e.g. "myData" I would be very happy, too, because I don't want to use the hack with any. Problem is the getData of FetchData returns just an Object from HttpClient:

//part of class FetchData
getData() {
    return this.http.get(this.dataUrl)
    .pipe(
        catchError(this.handleError)
      );
}  

Tanks for helping anyways. Love Stackoverflow community :D

jshAMG
  • 23
  • 8

2 Answers2

0

Main problem

  1. If you need load some data before app is loaded app_initializer can be used Angular: How to correctly implement APP_INITIALIZER
  2. Maybe in this snipped a reference to a class field this.data should be used instead of class Data itself
public getData(): Object {
    return this.data.data_property;
}

Response type
Http methods let you provide a generic, like this this.http.get<CustomResponseInterface>()

  • thanks for the answer, i will read sth about the app_initializer and the second thing was a mistake sorry :D i change my variables here for better understanding – jshAMG Jun 16 '19 at 16:22
0

One of the approaches could be the following -

Have your data service setup like this -

  export class DataService {

  //This is
  private _data$: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  data$: Observable<any>;

  constructor(private fetchData: FetchData) {
    this.data$ = this._data$.pipe(filter(d => !!d));
    this.getData();
   }      

  getData() {

    timer(0, 1000000).pipe(
      switchMap(() => this.fetchData.getData()),
      tap(d => {
        this._data$.next(d);
      })
    ).subscribe();
  }
}

Now to make use of the DataService.data$ do the following in the component [In this example I am assuming it is HomeComponent] where you want to use the fetched data [you can use data$ observable in as many component/services as you want, it will emit last fetched data from the backend] -

export class HomeComponent implements OnInit {

  constructor(private dataService: DataService) { }

  data$: Observable<any>;

  ngOnInit() {
    this.data$ = this.dataService.data$;
  }    
}

in html of HomeComponent

<div *ngIf="data$ | async as data">
  <!-- Render your 'data' -->
</div>
user2216584
  • 5,387
  • 3
  • 22
  • 29
  • the constructor of my listComponent looks like this ``` constructor(private data: Data) { this.keyList = Object.keys(this.data.getData()); } ``` so the variable has to be filled before the component loads – jshAMG Jun 16 '19 at 16:26
  • and sorry i corrected my code, I thought I just simplify my constructor but it changes a lot of the concept. The Data constructor creates a Observable which renews my data in a fixed time period – jshAMG Jun 16 '19 at 16:30
  • thanks, seems to be the best solution for me because i dont want to mess with any router resolver... But I Have a few questions for better understanding, is there a way to use the super-type Observable instead of BehaviorSubject? Also "filter(d => !!d)" is somehow not working, do i have to import something? i just know about the .filter function... and what is tap doing? thanks for your help!!!!! really appreciate it. – jshAMG Jun 16 '19 at 16:59
  • @jshAMG Yes, `filter` is rxjs operator. I hope it solved your problem. If it solved your issue I would request to mark this solution as answered so that other community members can take advantage of the solution in case they have a similar problem. – user2216584 Jun 16 '19 at 17:12
  • @jshAMG `tap` is again a rxjs operator which does not do anything with the value [i.e. if there is another operator in the observable pipeline then value will be passed as is] but you can use it to do anything with the value. Refer https://rxjs-dev.firebaseapp.com/api/operators/tap. I did not understand what do you mean by "super-type Observable"? – user2216584 Jun 16 '19 at 17:25
  • I don't know I just never heard or used BehaviorSubject and read that it is technically a sub class of Observable, so i thought i could just use Observable instead, but the is no .next function on observables. Other question i still have is, do i now have to subscribe in every component to the stock Observable to access a value that my data var was before or what is the concept? – jshAMG Jun 16 '19 at 17:31
  • @jshAMG Reactive is in the heart of Angular instead of Imperative style of coding. Observable is absolutely perfect to use [use async - https://angular.io/api/common/AsyncPipe] as it is one of the ways to trigger the angular change detection. Although you can use a variable but you need to make sure to update that variable whenever you want to refresh your view on data change. Observable provides that abstraction for you. Behavior subject is not subclass of Observable. It is an observer as well as observable (https://rxjs.dev/guide/subject#behaviorsubject) – user2216584 Jun 16 '19 at 17:41
  • okay i figure that out in an hour and if it works, then i mark it as solved. thank you very much sir! – jshAMG Jun 16 '19 at 18:12
  • sorry took me some time, cause i had to eat :D but now everything is working like a charm. thank you so much for your help. not only my problem is solved, I also got a very different perspective on supplying components with values, so much better to supply them asynchronous... THANK YOU!!! – jshAMG Jun 16 '19 at 22:57
  • @jshAMG good to know that your problem is solved! I make use of ‘async’ pipe as much as possible. I rarely subscribe the observable. The best part of async is that it subscribe/unsubscribe automatically. I would highly recommend to make use of async as much as possible. Angular community also promotes it. – user2216584 Jun 16 '19 at 23:16