Make a function return a value only when an Angular HTTP request has finished

Hello i am creating an angular async validator that has to wait for the response from a HttpRequest from a service.

I a need a function to return an observable of the information returned by the http call.

If a try diferent codes:

1- It doesn´t work because a is not defined due to the httprequest hasn´t finished when the function returns the a.

searchValue(controlName, controlValue){
   this.cts.getByParam(controlName, controlValue) // Call a function on the service that make a 
   HTTPrequest and make a subject emit a value.
   let a
   this.cts.dataGetByParamSubject.subscribe(res=>{
   a=(res)
})
return of(a)
}

2- It doesn't work because it doesn´t return any value.

searchValue(controlName, controlValue){
       this.cts.getByParam(controlName, controlValue) // Call a function on the service that make a 
       HTTPrequest and make a subject emit a value.
       let a
       this.cts.dataGetByParamSubject.subscribe(res=>{
       a=(res)
       return of(a)
    })
    }

3- It returns a Subscription not an Observable.

searchValue(controlName, controlValue){
           this.cts.getByParam(controlName, controlValue) // Call a function on the service that make a 
           HTTPrequest and make a subject emit a value.
           let a
           return this.cts.dataGetByParamSubject.subscribe(res=>{
           a=(res)
           return of(a)
        })
        }

4- It returns an observable that when you map it the res is a Subscriber and i got lost.

searchValue(controlName, controlValue){
           this.cts.getByParam(controlName, controlValue) // Call a function on the service that make a 
           HTTPrequest and make a subject emit a value.
           let a
           return of(this.cts.dataGetByParamSubject.subscribe(res=>{
           a=(res)
           return of(a)
        })
        })

Service side:

getByParam(property, value): Observable<HttpResponses> { 
    let data
    let params = new HttpParams()
    .set('schema', this.tipoConfiguracion.codigo)
    .set('property', property)
    .set('value', value)
      this.http.get<HttpResponses>(this.apiUrl + 'validation', {params: params}).subscribe(res=>{
        this.dataGetByParamSubject.next({message: res.message, data: res.data, error: res.error})
     })
     return
  }

How could i do this to work? Thank you for your help.

Upvotes: 0

Views: 962

Answers (1)

julianobrasil
julianobrasil

Reputation: 9357

[UPDATE]: I've made some editions per comments.

searchValue(controlName, controlValue) {
  // you don't need dataGetByParamSubject as it emits an object with the same
  // shape of the returning of this.cts.getByParam
  return this.cts.getByParam(controlName, controlValue);
}

Notice that as you have just one observable that have to be subscribed to after you get the return of getByParam, you also could've used mergeMap or concatMap with no distinction.

Also, notice the take(1) operator at the end of the pipe chain. I've added it because it looks like that this.cts.dataGetByParamSubject is a long-lived stream and you just want one value, is that right?

You can learn a lot about operators on https://www.learnrxjs.io.

On the service, you should do:

getByParam(property, value): Observable<HttpResponses> { 
  let data
  let params = new HttpParams()
      .set('schema', this.tipoConfiguracion.codigo)
      .set('property', property)
      .set('value', value);

  // there's no point in the dataGetByParamSubject here, as you will use 
  // it directly in your component.
  return this.http.get<HttpResponses>(this.apiUrl + 'validation', {params: params}).pipe(
    map((res: any) => ({
      message: res.message, 
      data: res.data, 
      error: res.error
    })
  ));
}

Upvotes: 2

Related Questions