1

I've been struggling with angular2 these days and I'm currently stuck on some issues related to async http loading.

Here is what I got:

  • 1 service component (MyCustomHttpService) containing methods to perform http calls to a REST API
  • 1 class (DataProvider) that properties have to be populated with the data retrieved
  • 1 view component (MyCmp) that calls a getter of the class in order to push the data to the view

What I would like to do:

When I call "DataProvider.getDataProviderSpecification()"

  • I load the data if it's not loaded yet
  • Otherwise, I return the data already loaded

This logic has to be in the DataProvider class and not in the custom http service or the view component.

I found a real dirty workaround. And since I know that it is reaaally bad I am seeking advice on how to improve that piece of code.

Thanks in advance for your help.

It looks like that (code cleaned):

/** CLASS **/
@Component()
export class DataProvider {
    private treestructure: any = null;

    constructor(private httpService: MyCustomHttpService) {}

    public getDataProviderSpecification() {
        if(this.treestructure == null) {
            return Observable.create(observer => {
             // http service to get REST data
             this.httpService.getDocumentDataProviderTree(this.documentID)
                    .subscribe((tree)=> {
                        this.treestructure= tree;
                        observer.next(this.treestructure);
                        observer.complete();
                    });
            });
        } else {
            return Observable.create(observer => {
                observer.next(this.treestructure);
                observer.complete();
            });
        }
    }
...
}


/** VIEW COMPONENT **/
@Component({
    selector: 'my-cmp',
    template: '<tree-cmp [structure]="tree"></tree-cmp>',
    inputs: ['dataprovider'],
    directives: [TreeComponent]
})
export class MyCmp {
    @Input() dataprovider: DataProvider;
    tree: any;
    showDetails(id) {
        this.dataprovider.getDataProviderSpecification().subscribe((treestructure) => {
            this.tree = treestructure;
        });
    } 
}
Noël Rimbert
  • 183
  • 1
  • 7

1 Answers1

3

This should do what you want:

public getDataProviderSpecification() {
    if(this.treestructure) {
        return Observable.of(this.treestructure); 
    else if(this.observable) {
      // if `this.observable` is set then the request is in progress
      // return the `Observable` for the ongoing request
      return this.observable;
    } else {
      // create the request, store the `Observable` for subsequent subscribers
      this.observable = this.httpService.getDocumentDataProviderTree(this.documentID)
          //.map(res => res.json())
          .do(val => {
            this.treestructure = val;
            // when the cached data is available we don't need the `Observable` reference anymore
            this.observable = null;
          })
          // make it shared so more than one subscriber can get the result
          .share();
      return this.observable;
    }
}    

See also https://stackoverflow.com/a/36291681/217408

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567