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;
        });
    } 
}

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

3 Comments

Hey Günter! I think you have a typo / you missed something in your snippet. this.observable is never set... I think something like: this.observable = this.httpService.getDocumentDataProviderTree....
Just tried it, it does exactly what I need. Thanks !
Glad to hear. Thanks for the feedback :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.