2

I have 3 independent places in my code which call VerificationService method getOrganizationView().

getOrganizationView(): Observable<any> {
  return this.httpClient.http.post(...)
}

First place is principal service:

@Injectable()
export class Principal {
   constructor(private verificationService: VerificationService) {}
   identity(force?: boolean): Promise<any> {
      return this.verificationService.getOrganizationView().toPromise().then((response ) => {
          ...
      })
   }
}

And one more service called LinkAccessService which do the same Principal that's not the point

And one more place is component:

export class VerificationComponent implements OnInit {
   constructor(private verificationService: VerificationService) {
   }

   ngOnInit() {
     this.verificationService.getOrganizationView()
       .subscribe((data: VerificationView) => {
         ...
     });
  }
}

And at loading app moment I had 3 calls instead single request, but these entities absolutely independent and I can't share data like between components directive and so on...

How traditionally in Angular 2+ resolve issue like this? I'm not mean distinct code for answer, I mean idea.

Pavel
  • 2,005
  • 5
  • 36
  • 68
  • cache this observable this.cahced$= this.cahced$ || this.httpClient.http.post(...) – ABOS Dec 11 '18 at 17:35
  • @ABOS that won't change anything. Each subscription will still cause a request to be sent. – JB Nizet Dec 11 '18 at 17:44
  • please use subject if(!this.cached$) { this.cached$ = new Subject(); this.httpClient.http.post(...).subscribe(this.cached$)} return this.cached$; – ABOS Dec 11 '18 at 17:46
  • 1
    https://stackoverflow.com/a/52717933/5695162 – Vikas Dec 11 '18 at 18:37

3 Answers3

3

The simplest way to cache your data is using shareReplay rxjs operator:

import { shareReplay } from 'rxjs/operators';

@Injectable()
export class VerificationService {
  organizationViewCache$: Observable<any>;

  getOrganizationView() {
    if (!this.organizationViewCache$) {
      this.organizationViewCache$ = this.http.get(...).pipe(shareReplay(1));
    }

    return this.organizationViewCache$;
  }
}

See also:

yurzui
  • 205,937
  • 32
  • 433
  • 399
2

You could build a service that retrieves and caches the data. Any component that injects the service can then access that cached data without another request to the server.

export class ProductService {
    private productsUrl = 'api/products';
    products: IProduct[];

    getProducts(): Observable<IProduct> {
        // Returns the cached list if it exists.
        if (this.products) {
            return of(this.products);
        }
        return this.http.get<IProduct[]>(this.productsUrl)
                        .pipe(
                            tap(data => this.products = data),
                            catchError(this.handleError)
                        );
    }
}

There are several other answers, including using RxJS ReplaySubject here: What is the correct way to share the result of an Angular Http network call in RxJs 5?

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • This will still send 3 requests since the 3 calls happen at initialization time: The 3 calls would see an undefined products and would all send the request. – JB Nizet Dec 11 '18 at 17:47
  • Ah. That was not clear to me from the question. And sorry about the mix up on my getProducts() return type. – DeborahK Dec 11 '18 at 17:54
  • @DeborahK I can't figure out how this protect me from redundant requests, Observable it's async action. While the first request handling on the server side we have empty cash and `if (this.products)` return false, and we go to make the next call. – Pavel Dec 11 '18 at 18:25
  • Yea, that is what JB said as well. I thought they were different components that were loaded/unloaded at different times. I didn't realize that they were *all* executed at start up. Did you see the end of my reply with the link to the `ReplaySubject` example? – DeborahK Dec 11 '18 at 19:13
0

I'm not 100% sure how your app is set up. But I would look into using an Event Emitter if I were you. You can have it emit an event, that your different components will listen to. Whichever component is supposed to make the call will make it appropriately and the others should not.

Jon
  • 2,456
  • 21
  • 28
  • unfortunately, I know how to use event emitter for exchange data between components^ but in my case, I need sharing data with two services and only one component. – Pavel Dec 11 '18 at 18:17
  • Oh I see. I completely misunderstood your requirements – Jon Dec 11 '18 at 18:22