2

I am retrieving data from a web api through angular 6.

I created a service with a fetch function that is called in a component constructor, which will be instanciated multiple times on the same page.

My problem is that the service is called each time my component is instanciated.

For example my code is the following :

Service :

import { Injectable } from '@angular/core';
import { Article } from '../../Classes/article'
import { Observable } from 'rxjs';
import { MessageService } from '../../Services/message/message.service'
import { HttpClient } from '@angular/common/http'


@Injectable({
  providedIn: 'root'
})
export class ArticleService {

  Values:  Observable<Article[]> ;


  constructor(private messageService: MessageService, private http : HttpClient) 
  { 
 this.buildArticles()
  }

private articlesUrl = 'http://localhost:63138/v/Article'

private buildArticles():  void {
    this.Values =  this.http.get<Article[]>(this.articlesUrl)
}

getArticles() : Observable<Article[]> {
return this.Values
  }
}

My component :

import { Component,OnInit, Input } from '@angular/core';
import { ArticleService } from 'src/app/Services/article/article.service';
import { Article } from 'src/app/Classes/Article'

@Component({
  selector: 'app-article',
  templateUrl: './article.component.html',
  styleUrls: ['./article.component.scss'],
})

export class ArticleComponent implements OnInit {

  @Input() artId  :number;


  constructor( private articleService : ArticleService) { 
    articleService.getArticles().subscribe(x=> this.articles = x);
   }
  articles : Article[];
  ngOnInit(): void {
  }
}

with the component html :

<mat-form-field>
  <mat-select [(ngModel)]="artId" >
    <mat-option *ngFor="let art of articles" [value]="art.Id"> 
 {{art.Libelle1}}</mat-option>
  </mat-select>
</mat-form-field>

Now on my app I would like the service fetch method to be called once, and reuse the data each time I instanciate a new component.

In the app.module.ts, I put providers: [ArticleService] in @NgModule but I get a request to my web api for each instance of the component.

1
  • 1
    If you would like to re-word your question, you want the getArticles() to be called only once. You actually have only one instance of the service. Just call the method in the top most relevant component and pass it to others through Input/services Commented Dec 27, 2018 at 13:47

2 Answers 2

6

Angular creates components on demand.

In your case, everytime a component is created, you make an HTTP call by using the service method to fetch your data.

The issue isn't with instances of the service (or even your component), it's the design you have chosen that doesn't suit your case.

What you need is some sort of caching. To implement that, you can use subjects :

private _cachedData: Subject<any>;
public data = this._cachedData.asObservable();

refreshData() {
  this.http.get(...).subscribe(res => this._cachedData.next(res));
}

initializeData() {
  if (!this._cachedData) {
    this._cachedData = ,new Subject();
    this.refreshData();
  }
}

This is very simple, but it should do the trick. Now you can just use myService.data.subscribe() to get the cached data, and you can initialize data in your component constructor (because your service is a singleton, if you try to call it with data already cached, the service will simply ignore the request).

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

Comments

4

By declaring your component

@Injectable({
  providedIn: 'root'
})

you guarantee that it will be one instance of your service, the problem is with the fact that every time you call subscribe the entire observer chain is executed (including get). You have to do something like this:

import { publishReplay, refCount } from 'rxjs/operators';    

return this.http.get<Article[]>(this.articlesUrl)
      .pipe(
       publishReplay(),
       refCount())

it will remit the value for every subscription.

Comments

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.