Cannot read property 'subscribe' of undefined [SOLVED]


#1

Error in asynchronous validation:

EXCEPTION: Cannot read property 'subscribe' of undefined

Registro.ts

constructor(public navCtrl: NavController, public navParams: NavParams,
    public alertCtrl: AlertController, public formBuilder: FormBuilder, public db: VentasServicio,
    public api: ApiRest) {

    let isUsuarioInventiva = (control: FormControl) => {
      if (control.value !== "") {
        this.api.getUsuarioInventiva(control.value).subscribe(data => {
          if (data === null) {
            control.setErrors({ "is_not_usuario_inventiva": true });
            return { "is_not_usuario_inventiva": true };
          }
        });
      }
    };

    this.registroFrm = this.formBuilder.group({
      'usuarioInventiva': ['', Validators.required, isUsuarioInventiva]
    });
  }

Registro.html

      <ion-item>
        <ion-label stacked>Usuario Inventiva</ion-label>
        <ion-input formControlName="usuarioInventiva" type='text' autocapitalize="off"></ion-input>
      </ion-item>
      <ion-item *ngIf="registroFrm.get('usuarioInventiva').pending">
        <p>Verificando en Inventiva...</p>
      </ion-item>
      <ion-item *ngIf="registroFrm.get('usuarioInventiva').errors && registroFrm.get('usuarioInventiva').dirty">
        <p *ngIf="registroFrm.get('usuarioInventiva').hasError('required')" color="danger">Campo requerido</p>
        <p *ngIf="registroFrm.get('usuarioInventiva').hasError('is_not_usuario_inventiva')" color="danger">Usuario no encontrado</p>
      </ion-item>

Thanks!


#2

Async validators must return a future (Promise or Observable). Yours is not returning anything. It is a common misconception that things like then() and subscribe() magically pause time and that anything returned out of them will be returned by the enclosing function. It doesn’t and it won’t.

If you’re new to asynchronous programming, and you’re writing a function that is calling something else that generates a future, your function must also return a future, and the first word of your function should be “return”. Following that rule will save you from 80% of common async bugs, including this one.

let isUsuarioInventiva = (control: FormControl) => {
  return control.value === "" 
    ? Observable.of({}) 
    : this.api.getUsuarioInventiva(control.value)
      .map(data => data ? {} : {"is_not_usuario_inventiva": true}); 
};