Search code examples
angularmean-stackangular-ngmodelangular12

Angular 12: ngModel variable not updating after async get result


I know this issue is very common, but I have done some research already and didn't find any solution for my case, I have tried some stuff like ngZone and setTimeout but won't work.

What I have is a component using ngModel that is updated via a get done by a service using a utility class, as you can check below:

component

ngOnInit(): void {
    this.init();
  }

  private async init() {
    this.initModel();
    this.initForm();
  }

  private async initModel() {
    await this.getId();
    this.getModel();
  }

  private async getId(): Promise<any> {
    return this.route.paramMap.subscribe((params) => {
      this._id = params.get('id'); 
    });
  }

  private async getModel() {
    console.log('getModel: '+this._id)
    if (this._id) {
      console.log('if')
      this.operationType = constants.COMPONENT.MAINTAIN.OPERATION_TYPE.PUT;
      
      (await this.session.apiManager.WorkerApi.getWorker(this._id)).subscribe(
        (response: any) => {
          this.worker = response
          console.log('await - ' + this.worker.name)
        }
      );
      
      console.log('after');
    }
    else 
      this.worker = new Worker("");
  }

my service class Session method

public async getWorker(id: string): Promise<Observable<Worker>> {
    return await this.api.getData(this.REQUEST_URL + "/" + id);
}

my utility API class method

public getData(request?: String): Observable<any> {
    const requestUrl = this.URL + request;
    
    return this.http.get(requestUrl);
}

What is "funny" is that I have the same code for another model in another component and it works perfectly, but here it won't update my input text (below) after my "get" callback.

<input type="text" class="form-control" name="name" id="name" 
                required minlength="2" [(ngModel)]="this.worker.name">

Can you help me to understand what is wrong?

Thanks in advance!

#Edit 1

I changed the component to use the toPromiseand my console.log sequence is working now, although, the model is still not getting updated.

new getModel()

  private async getModel() {
    console.log('getModel: '+this._id)
    if (this._id) {
      console.log('if')
      this.operationType = constants.COMPONENT.MAINTAIN.OPERATION_TYPE.PUT;
      
      this.worker = (await (await this.session.apiManager.WorkerApi.getWorker(this._id)).toPromise());
      console.log('toPromise: '+this.worker.name);
      
      console.log('after');
    }
    else 
      this.worker = new Worker("");
  }

#Edit 2

I just realized that I am having trouble to get the input value via my ts code as well, it just proves that the problem is with my two-way data bind (I guess). When I call the this.worker.name on my onSubmit event, the model is empty even though the input is filled.

It makes me wonder if the issue's title is wrong or not... Maybe "Two-way ngModel data binding not working" fits better...


Solution

  • Well, I figured it out when creating a stackblitz as suggested by @H3AR7B3A7 and @Raphaël Balet. What was happening is that I had an extra HTML code using a [formGroup]:

    <form novalidate #form="ngForm" [formGroup]="formGroup" (ngSubmit)="onSubmit(form)">
    

    It means, I was trying to use both two-way data binding with ngModel AND angular reactive forms, and somehow angular was getting lost on it and my model was not working. All I needed to do was remove the [formGroup]="formGroup" and it worked perfectly.

    Also, a tip for the future viewers, the stackblitz helped me providing more precise error messages than my browser, so it helped me with other errors in my application such as null injections.