Shubhashish Mishra
Shubhashish Mishra

Reputation: 488

Asynchronous behavior of Observable causing variable to be undefined

I created a Service in Angular2 which is responsible for making REST call to java services and get Array of products using HTTP Observable.

getAll(): Observable<Product[]>{
    let data$ = this.http
        .get(`${this.baseUrl}/productdata`, {headers: this.getHeaders()})
        .map(mapData)
        .catch(handleError);
    console.log(' object array:' , data$)
    return data$;
}

I have then written a subscriber for this Observable in my component and placed inside the ngOnInit() method and wanted to just extract the first product so placed inside ngOnInit().

this.product = this.products[0];

ngOnInit() {
 this.productService
        .getAll()
        .subscribe(
            /* happy path */ p => this.products = p,
            /* error path */ e => this.errorMessage = e,
            /* onComplete */ () => this.isLoading = false);
this.product = this.products[0];
}

But the last operation in OnInit method is causing product to be undefined because of the asynchronous behavior of Observable. Similarly, I am not able to use the property of product to interpolate in HTML component. I want the extraction to be automatic. So can you provide me a way to do that?

Upvotes: 1

Views: 1234

Answers (3)

Sixto Mitre
Sixto Mitre

Reputation: 1

Since you are using observables, you can take advantage from all the methods of an observable such as the .map() function which you're already using.

this.productService
  .getAll()
  .map(products => products[0])
  .subscribe(
    /* happy path */ product => this.product = product,
    /* error path */ e => this.errorMessage = e,
    /* onComplete */ () => this.isLoading = false
  );

Upvotes: 0

Brendan Bates
Brendan Bates

Reputation: 116

You actually answered your own question - since it's asynchronous, your call to this.product = ... is called immediately, while the observable takes some time to return. Solution is simple:

ngOnInit() {
 this.productService
    .getAll()
    .subscribe(
        /* happy path */ p => {
            this.products = p;
            this.product = this.products[0];
        },
        /* error path */ e => this.errorMessage = e,
        /* onComplete */ () => this.isLoading = false);
}

Include the set inside of the observable callback.

Upvotes: 1

LLai
LLai

Reputation: 13416

your code:

this.product = this.products[0];

is being executed before it is defined. Move it into your on success function

this.productService
    .getAll()
    .subscribe(
        /* happy path */ p => {
            this.products = p;
            this.product = this.products[0];
        },
        /* error path */ e => this.errorMessage = e,
        /* onComplete */ () => this.isLoading = false
);

Upvotes: 0

Related Questions