Reputation: 816
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.
Upvotes: 2
Views: 1813
Reputation: 31145
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.
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.
Upvotes: 1