1

I have simple component to test string interpolation. In html,

<p>{{value}}</p>

The ts file:

export class HelloComponent implements OnInit {
   value: any;
   constructor(private service: ApiService) {
        this.value = 'test';
   }
   ngOnInit() {
       this.getValue();
   }
   getValue = (): void => {
       this.value = this.service.getValue();
   }

Now since I injected the service so let's look at it.

@Injectable({
    providedIn: 'root'
})
export  class ApiService {
      url: string;
      value: any;
      constructor(private http: HttpClient) {
           this.url = 'http://localhost:8080/api/test';
      }
      getValue = () => {
          this.http.get(this.url, {responseType: 'text'}).pipe(take(1)).subscribe(
                  data => {
                      this.value = data;
                      console.log(data); // 'Hello World' is printed out.
                      return data;
                  }
          );
      }
 }

My question is that I can see the correct value in console log. But I can't get the value in the component. It is undefined value so on the screen it is nothing.

Hello
  • 796
  • 8
  • 30

1 Answers1

1

That is not how asynchronous data fetched using observables work. You could return the observable from the service and subscribe where the data is required.

Service

@Injectable({ providedIn: 'root' })
export class ApiService {
  url: string;

  constructor(private http: HttpClient) {
    this.url = 'http://localhost:8080/api/test';
  }

  getValue(): Observable<any> {
    return this.http.get(this.url, { responseType: 'text' })
  }
}

Component

export class HelloComponent implements OnInit {
   value: any;
 
   constructor(private service: ApiService) {
      this.value = 'test';
   }
 
   ngOnInit() {
      this.getValue();
   }
 
   getValue(): void {
      this.service.getValue().subscribe({
        next: data => this.value = data,
        error: error { }
      });
   }
}

Please go through this answer in it's entirety to understand why your method wasn't working.

Update: close open subscription

As mentioned in my comment, Angular HTTP observables complete after a single emission. So a take(1) would be redundant. You could however assign the subscription to a variable and call .unsubscribe() on it or use takeUntil().

I prefer takeUntil() operator since it could be used to close multiple subscriptions with a single push to an observable.

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class HelloComponent implements OnInit, OnDestroy {
   value: any;
   close$ = new Subject<any>();
 
   constructor(private service: ApiService) {
      this.value = 'test';
   }
 
   ngOnInit() {
      this.getValue();

      this.getOtherValue();  // <-- illustration
   }
 
   getValue(): void {
      this.service.getValue().pipe(
        takeUntil(this.close$)    // <-- close stream when `close$` emits
      ).subscribe({
        next: data => this.value = data,
        error: error { }
      });
   }

   getOtherValue(): void {  // <-- illustration
      this.service.getOtherValue().pipe(
        takeUntil(this.close$)    // <-- close stream when `close$` emits
      ).subscribe();
   }

   ngOnDestroy() {
     this.close$.next();    // <-- close both open subscriptions
   }
}

You could refer this post for more concise ways to close open subscriptions.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • It works. Can I apply pipe and take(1) here to unsubscribe it? – Hello Jan 29 '21 at 15:50
  • Another thing is I remove ` {responseType: 'text'}` from service then it stops working. – Hello Jan 29 '21 at 16:04
  • Updated the answer to unsubscribe the subscription @Hello – Kshitij Jan 29 '21 at 16:07
  • @Hello it is still pending for approval – Kshitij Jan 29 '21 at 18:32
  • @Hello: Angular HTTP observables complete after a single emission. So a `take(1)` would be redundant. However you could assign subscription to a variable and call `.unsubscribe()` or use `takeUntil()`. I've updated the post. – ruth Jan 31 '21 at 21:25
  • @Kshitij: Thanks for the edit, I've updated the post to include more context. – ruth Jan 31 '21 at 21:25