Estoy usando formularios angulares, y me gustaría usar su detección de cambios incorporada para implementar una funcionalidad en mi aplicación. Cuando un usuario hace clic en un botón, solo debería ver un cuadro de diálogo si ha realizado algún cambio en el formulario.

Tengo cambios Variable hecha:

private changesMade: boolean;

Este es mi código TS del formulario:

this.carForm = new FormGroup({
        name: new FormControl('', [
            Validators.required,
            Validators.pattern('[a-zA-Z ]*'),
            Validators.minLength(1),
            Validators.maxLength(10)
        ])});

Este es mi código HTML del formulario:

<form [formGroup]="carForm">
        <ion-item>
          <ion-label  stacked>car name</ion-label>
          <ion-input type="text" [(ngModel)]="carname" formControlName="name"></ion-input>
        </ion-item>
</form>

Aquí está mi llamada de servicio simulada (por ahora) donde me suscribo para formar cambios después de establecer el valor de carname, que está vinculado a la entrada

setTimeout(()=>{
  this.carname = "BMW";
  this.carForm.valueChanges.subscribe(val => {
  this.changesMade = true;
    });
}, 44)

El problema aquí es que, aunque no he tocado el formulario, this.changesMade se establece en verdadero.

NOTA: Si muevo la parte de suscripción del código en el ngAfterViewInit, aún establece los cambios realizados en verdadero aunque no haya topado la entrada:

  ngOnInit(){
    //simulated server call
    setTimeout(()=>{
      this.carname = "BMW";

    }, 44)
  }
      ngAfterViewInit(){
this.carForm.valueChanges.subscribe(val => {
      this.changesMade = true;
        });
    }

He creado un STACKBLITZ demostrando el problema. ¿Cómo puedo hacer que se ejecute this.changesMade = true; solo cuando he tocado físicamente la entrada en la interfaz de usuario?

2
gfels 13 sep. 2018 a las 14:24

3 respuestas

La mejor respuesta

Entonces, al colocar la suscripción al final de la pila de llamadas (con setTimeout (0)) todo parece funcionar como se esperaba:

//simulated server call
setTimeout(()=>{
  this.carname = "BMW";
  setTimeout(function(){
  this.carForm.valueChanges.subscribe(val => {
  this.changesMade = true;
    });
  }.bind(this), 0)

}, 44)

Aquí hay un STACKBLITZ demostrando que funciona.

ACTUALIZACIÓN

Dado que el uso de formas reactivas con ngModel es en desuso en Angular 6+, es es mejor reemplazar las formas reactivas con formas basadas en plantillas en casos de uso similares.

-1
gfels 19 oct. 2018 a las 08:37

El problema aquí es que estás mezclando formas reactivas y ngModel. Como ha utilizado ngModel en su plantilla y ha configurado this.carName = 'BMW' en su componente, esto activa la detección de cambios y formGroup se actualiza y su bandera changesMade se vuelve verdadera. Elimine el ngModel y obtenga sus valores de formulario utilizando API de formulario reactivo: https : //angular.io/guide/reactive-forms#reactive-forms-api.

He actualizado el STACKBLITZ: https://stackblitz.com/ edit / ionic-qkjeu6? file = pages% 2Fhome% 2Fhome.ts

1
Milo 13 sep. 2018 a las 11:43

Utiliza dos enfoques en una forma:

Necesitas seleccionar uno.

Esta solución con formas reactivas:

1.Eliminar ngModel de la plantilla

<ion-input type="text" formControlName="name"></ion-input>

2.Agregue rxjs / first para cambios de actualización Hecho una vez y darse de baja automáticamente

import 'rxjs/add/operator/first';

3. Retire la propiedad carName de su componente y actualícela con patchValue

ngOnInit() {
  //simulated server call
  setTimeout(() => {
    this.carForm.patchValue({ name: 'BMW' })
    this.carForm.valueChanges.first().subscribe(val => {
      this.changesMade = true;
    });
  }, 44)
}

Ejemplo de Stackblitz

4
Kliment Ru 13 sep. 2018 a las 18:52