I have a search field that receives some value to search and populates an array. If the value the user provides is invalid a boolean is set to true, displaying an error message and the input's outline color changes to red.

I have a function that receives the value provided and makes an HTTP get request. Inside the .subscribe() function I update the error message and change the input's outline color to red.

I've searched for similar problems and found that most of the cases involved people not updating variables inside the subscription, however that is not the case with my code.

MyComponent.component.ts

constructor(public rest: RestService) { }

private onCreateNewRequest(value: any) {
  let message = "Required!";
  if (value === undefined || value === "" || value.length < 0) {
    this.setErrorMessage(message);
    this.setIsFormInvalid(true);
    this.setNewRequestInputInvalid()
  } else {
    this.getOrderByNumber(this.setNewRequestInputInvalid, value);
  }
}

private getOrderByNumber(callback, value: string) {
  let message = "Invalid Order!";
  this.rest.getOrderByNumber(value).subscribe((orderNrData: {}) => {
    if (Object.entries(orderNrData).length !== 0) {
      this.onCreateReturn(orderNrData);
    } else {
      callback();
      this.setErrorMessage(message);
      this.setIsFormInvalid(true);
    }
  }, error => {
    callback();
    this.setErrorMessage(message);
    this.setIsFormInvalid(true);
  });
}

private setErrorMessage(message: string) {
  this.errorMessage = message;
}

private setIsFormInvalid(status: boolean) {
  this.isFormInvalid = status;
}

private setNewRequestInputInvalid() {
  document.getElementById('new-request-input-id').style['border-color'] = 'red';
}

MyComponent.component.html

<div class="row">
  <div class="col-2 d-flex align-items-center">Order: </div>
  <div class="col-8">
    <input class="form-control align-middle new-request-input-class" id="new-request-input-id" type="text" placeholder="Ex: EU030327" aria-label="Search" (input)="resetValidator()" (keyup.enter)="onCreateNewRequest(searchInput.value)" #searchInput>
  </div>
  <div class="col-2"></div>
</div>

<div class="row">
  <div class="col-2"></div>
  <div class="col-8 error-label-col" id="error-label-id" *ngIf="isFormInvalid">
    <small>{{getErrorMessage()}}</small>
  </div>
</div>

Rest.service.ts

private extractData(res: Response) {
  let body = res;
  return body || {};
}

getOrderByNumber(order_nr): Observable<any> {
  return this.http.get(endpoint + 'orders/number/' + order_nr, httpOptions).pipe(
            map(this.extractData));
} 

My code successfully changes the input's outline color to red but somehow fails to change isFormInvalid to true. Because of this, the *ngIf won't trigger and the message is never shown to the user.

EDIT:

If I use ChangeDetectorRef after I change isFormInvalid everything works as expected...

constructor(private ref: ChangeDetectorRef) { }

private getOrderByNumber(callback, value: string) {
  let message = "Invalid Order!";
  this.rest.getOrderByNumber(value).subscribe((orderNrData: {}) => {
    if (Object.entries(orderNrData).length !== 0) {
      this.onCreateReturn(orderNrData);
    } else {
      callback();
      this.setErrorMessage(message);
      this.setIsFormInvalid(true);
      this.ref.detectChanges(); // here
    }
  }, error => {
    callback();
    this.setErrorMessage(message);
    this.setIsFormInvalid(true);
    this.ref.detectChanges(); // here
  });
}

Why is Angular only detecting these changes if I force it to detect them? Also, is this a good practice?

0 Answers