angulartypescriptasync-awaitpromiseobservable

Losing reference to this in async function inside subscribe


I'm almost new to Angular and I'm really lost with the async and sync methods, await, observables, promises... I have a button that opens a modal window, reads a barcode and with the information of this barcode makes a request to the server and does something with the result. This is my code:

The method called by the button:

<button mat-fab [disabled]="!empleado" extended color="accent" (click)="scanearPlano()" class="mb-2">
scanearPlano(){
    this.dialogInfoEscanenando = this.dialog.open(InfoEscaneandoComponent);
    this.dialogInfoEscanenando.afterClosed().subscribe((datosRecibidos) => {
      if (datosRecibidos) {
        //Obtenemos la info del código de barras
        if(datosRecibidos && datosRecibidos != ''){
          this.inputOf = datosRecibidos;
          this.buscarOF(true);
        }
      }
    });
  }
async buscarOF(autoPlay: boolean){
    if(this.inputOf){
      this.sinOf = false;
      this.partida = null;
      this.plano = null;
      this.inputPlano = '';

      const ordf = this.inputOf;
      try{
        const ordenFabricacion = await this.registroActividadService.getOrdenFabricacion(ordf);
        if(ordenFabricacion){
          this.ordenFabricacion = ordenFabricacion;
          this.inputPedido = this.ordenFabricacion.partida.split("_")[0];
          this.inputPartida = this.ordenFabricacion.partida.split("_")[1];
          await this.buscarPartida(false);
          this.inputOf = this.ordenFabricacion.numero;
          this.plano = this.ordenFabricacion.articulo;
          this.inputPlano = this.ordenFabricacion.articulo.terminoBusqueda;
          if(autoPlay){
            this.play(true);
          }
        }else{
          alert("No se ha encontrado la OF " +ordf);
        }
      }catch (err){
        if (err instanceof Error) {
          this.showError("Error al intentar acceder a los datos. " + err.name, err.message);
        } else {
          this.showError("Error inesperado.", "Ha ocurrido un error desconocido.");
        }
        this.ordenFabricacion = null;
      }
    }else{
      this.inputPedido = '';
      this.inputPartida = '';
      this.partida = null;
      this.inputPlano = '';
      this.plano = null;
    }
  }

As you can see buscarOf is an async method. This is because it is making some requests to the server and I have to use await with them because I have to wait for its results to continue.

My problem is that inside buscarOf, the reference to this is lost, it is undefined. If I call a not async method inside the afterClosed subscribe, this is defined, so I assume that the problem is with async methods.

As I want you to have all the information about my code to try to guide me on the right way, this is how I make the server request:

public async getOrdenFabricacion(numero: string): Promise<OrdenFabricacion>{
    let queryParams = new HttpParams().append("numero", numero);
    return await firstValueFrom(this.http.get<OrdenFabricacion>(this.getOrdenFabricacionUrl, { params: queryParams }));
  }

I have tried to bind this to both methods, but it hasn't worked:

constructor(){
    this.scanearPlano = this.scanearPlano.bind(this);
    this.buscarOF = this.buscarOF.bind(this);
  }

I hope someone can help me. Thanks!!


Solution

  • The issue you're experiencing is unrelated to whether the function is asynchronous or not. The problem lies in the fact that the this context is lost when calling the buscarOF() function within your subscription.

    One solution is to use an arrow function, which inherits the this context from its parent scope, also known as "lexical scoping". You can modify your function from:

    async buscarOF(autoPlay: boolean) {}
    

    to an arrow function:

    buscarOF = async (autoPlay: boolean) => {}
    

    Additionally, please note the following: