Search code examples
validationionic3angular4-forms

Ionic 3 input underline don't change color due to validator until you focus on the input at least once


My problem is that the underline doesn't change color until you focus on the input at least once. I put a loop in enviarElastic() to mark as touched but even then it only changes color when you focus. If you push the button it should change the color of the underline when the input is empty

constructor(public navCtrl: NavController, public navParams: NavParams, public actionSheetCtrl: ActionSheetController, public servicioCamara:ServicioCamaraProvider,
          public http:ServicioHttpProvider, public modalCtrl: ModalController, public  toastCtrl:ToastController, private formBuilder: FormBuilder) {
this.form = this.formBuilder.group({
  idContenedor: ['',[Validators.required,Validators.minLength(3)]],
  tipo_contenedor1: [''],
  tipo_incidencia1: ['', [Validators.required, Validators.minLength(2)]],
  descripcion_incidencia1: ['', Validators.compose([Validators.required, 
  Validators.minLength(1)])]
});}

 public enviarElastic(){
for (var i in this.form.controls) {
  this.form.controls[i].markAsTouched();
  this.form.controls[i].updateValueAndValidity({ onlySelf: false, emitEvent: true});
}

var formu=this.formulario;
if(this.formulario.id_contendor=="" || this.formulario.tipo_incidencia=="" || this.formulario.tipo_contenedor=="" || this.formulario.descripcion_incidencia==""  ){
  this.presentToast("Falta de rellenar Algun campo");
}else{
  var imagenes=this.cargarEntidadesImagenes();

  let body= {
    "type":"incidencia",
    "id_contendor" :formu.id_contendor.toString(),
    "tipo_contendor" :formu.tipo_contenedor.toString(),
    "tipo_incidencia" :formu.tipo_incidencia.toString(),
    "descripcion_incidencia": formu.descripcion_incidencia.toString(),
    "imagenes":imagenes
  };
  this.http.ngPost(body);
}

And this is the html

  <form class="contact_form" [formGroup]="form" (ngSubmit)="enviarElastic()" action="#" method="post" novalidate>
<ion-list>
    <ion-item>
      <ion-label  color="dark" stacked>Identificador del contenedor:</ion-label>
      <ion-input formControlName="idContenedor" type="text" placeholder="IdContenedor" [(ngModel)]="formulario.id_contendor" ></ion-input>
    </ion-item>
  <ion-item>
    <ion-label color="dark" stacked>Tipo de contenedor</ion-label>
    <ion-select formControlName="tipo_contenedor1" [(ngModel)]="formulario.tipo_contenedor">
      <ion-option value="Papel y Carton" >Papel y Carton</ion-option>
      <ion-option value="Plastico">Plastico</ion-option>
    </ion-select>
  </ion-item>
    <ion-item>
      <ion-label color="dark" stacked>Tipo de Incidencia:</ion-label>
      <ion-input formControlName="tipo_incidencia1" type="text" placeholder="Tipo de incidencia" [(ngModel)]="formulario.tipo_incidencia" ></ion-input>
    </ion-item>
  <ion-item>
    <ion-icon name="images" item-start></ion-icon>
    <ion-label >Imagenes :{{servicioCamara.imagenes_base64.length}} </ion-label>
    <div class="buttons" item-end>
      <button value="Enviar" (click)="mostrarSeleccionadorImagenes()"  ion-button>Seleccionar</button>
    </div>
  </ion-item>
  <ion-item>
      <ion-label color="dark" stacked >Descripcion de la incidencia</ion-label>
      <ion-textarea  formControlName="descripcion_incidencia1" placeholder="Escribe aqui la descripcion de la incidencia" [ngModel]="formulario.descripcion_incidencia" ></ion-textarea>
  </ion-item>
</ion-list>

<button value="Enviar"    type="submit" class="button button-block button-positive" ion-button>Enviar</button>


Solution

  • It is because of a bug in the Ionic. It leaves ion-item element untouched. The problem is described here: https://forum.ionicframework.com/t/ionic-form-validate-from-code-remove-ng-untouched/98010

    A workaround which is essentially the same as described in the link above:

    public onSubmit() {
      if (!this.form.valid) {
         this.markAllAsTouched(this.form);
         return;
      }
    }
    
    private markAllAsTouched(formGroup: FormGroup) {
      Object.keys(formGroup.controls).forEach((controlName) => {
        const control = formGroup.get(controlName);
        const element = document.querySelector('[formControlName="' + controlName + '"]');
    
          if (control instanceof FormControl) {
            control.markAsTouched({ onlySelf: true });
            if (element) {
              const ionItem = element.closest("ion-item");  // Note that .closest is not supported by IE11. See https://stackoverflow.com/questions/18663941/finding-closest-element-without-jquery for alternatives
              this.setControlCss(ionItem, formGroup.controls[controlName]);
            }
          } else if (control instanceof FormGroup) {
            this.markAllAsTouched(control);
          }
      });
    }
    
    private setControlCss(element: any, control: AbstractControl) {
      this.renderer.setElementClass(element, "ng-untouched", control.untouched);
      this.renderer.setElementClass(element, "ng-touched", control.touched);
      this.renderer.setElementClass(element, "ng-pristine", control.pristine);
      this.renderer.setElementClass(element, "ng-dirty", control.dirty);
      this.renderer.setElementClass(element, "ng-valid", control.valid);
      this.renderer.setElementClass(element, "ng-invalid", !control.valid);
    }