title: Angular 5 - Service implementation for caching
body: <p>I'm looking for a proper approach to implement Angular services.</p>
  
  <p><strong>My Service</strong>:</p>
  
  <pre><code>const endpoint = 'http://127.0.0.1:8000/api/brands/'
  
  @Injectable()
  export class BrandService {
  
    private brands:Observable&lt;Array&lt;Brand&gt;&gt;;
  
    constructor(private http: Http) { }
  
    list(): Observable&lt;Array&lt;Brand&gt;&gt; {
      if(!this.brands){
        this.brands = this.http.get(endpoint).
                            .map(response =&gt; response.json())
                            .publishReplay(1) // publishReplay(1) tells rxjs to cache the most recent value which is perfect for single value http calls
                            .refCount(); // refCount() is used to keep the observable alive for as long as there are subscribers
      }    
      return this.brands;
    }
  
    clearCache() {
      this.brands = null;
    }
  
    create(brand: Brand): Observable&lt;Brand&gt; {
      Object.entries(brand).forEach(([key, value]) =&gt; {
        formData.append(key, value);
      });
      return this.http.post(endpoint+'create/', formData)
        .map(response =&gt; response.json())
        .catch(this.handleError);
    }
  
    get(id): Observable&lt;Brand&gt; {
      return this.http.get(endpoint+id)
          .map(response =&gt; response.json())
          .catch(this.handleError);
    }
  
    private handleError(error:any, caught:any): any {
      console.log(error, caught);
    }
  
  }
  </code></pre>
  
  <p>I managed to create a caching mechanism simply using the <code>publishReplay</code> method with the Observable object.
  Now, I would like to have my service automatically updates the list every minute.
  I tried using <code>setInterval(this.clearCache, 1000*60)</code> and it clears, but what I would to accomplish is to update the list and notify all subscribers every minute if the list has changed.</p>
  
  <p>What's the best practice to keep up-to-date all data limiting the server requests?</p>
  
  <p><strong>UPDATE 1 (Validator Issue)</strong>:</p>
  
  <p>As suggested by martin, I changed the list method as follow:</p>
  
  <pre><code>list(): Observable&lt;Array&lt;Brand&gt;&gt; {
      if(!this.brands){
        this.brands = Observable.timer(0, 60 * 1000)
                          .switchMap(() =&gt; {
                            console.log('REQUESTING DATA....')
                            return this.http.get(endpoint);
                          })
                          .map(response =&gt; response.json())
                          .publishReplay(1)
                          .refCount();
      }
      return this.brands;
    }
  </code></pre>
  
  <p>It's working fine, except with validators.</p>
  
  <p>The following validator was working before:</p>
  
  <pre><code>private brandNameValidator(control: FormControl) {
      return this.brandService.list().map(res =&gt; {
        return res.filter(brand =&gt; 
              brand.name.toLowerCase() === control.value.toLowerCase() &amp;&amp; (!this.editMode || brand.id != this.brand.id)
          ).length&gt;0 ? { nameAlreadyExist: true } : null;
      });
    }
  </code></pre>
  
  <p>Now, the field remains in PENDING status.</p>
  
  <p><strong>UPDATE 2 (Validator Solution)</strong>:</p>
  
  <p>I solved the issue using the <code>Promise</code> object:</p>
  
  <pre><code>private brandNameValidator(control: FormControl) {
      return new Promise (resolve =&gt; {
        let subscription = this.brandService.list().subscribe(res =&gt; {
          let brandsFound = res.filter(brand =&gt; 
            brand.name.toLowerCase() === control.value.toLowerCase() &amp;&amp; (!this.editMode || brand.id != this.brand.id)
          )
          if (brandsFound.length&gt;0) {
            resolve({ nameAlreadyExist: true });
          } else {
            resolve(null);
          }
          subscription.unsubscribe();
        })
      });
  }
  </code></pre>
  
  <p><strong>UPDATE 3 (Forcing List Update)</strong>:</p>
  
  <p>Right after a new brand has been created, I would like to force the list update. I don't want to wait the next minute when I know that the list has been updated.</p>
  
  <pre><code>  create(brand: Brand): Observable&lt;Brand&gt; {
      Object.entries(brand).forEach(([key, value]) =&gt; {
        formData.append(key, value);
      });
      return this.http.post(endpoint+'create/', formData)
        .map(response =&gt; {
          // TODO - Need to update this.brands, but I cannot use the next() method since it isn't a Subject object, but an Observable.
          // All observers need to updated about the addition
          return response.json();
        })
        .catch(this.handleError);
    }
  </code></pre>