2016-12-05 12 views
7

Mam formularz z kilkoma polami danych i dwoma przyciskami. Chcę włączyć przyciski tylko wtedy, gdy użytkownik wprowadzi pewne zmiany w formularzu. Próbowałem użyć:Jak sprawdzić zmiany w formularzu w Angular 2 przy użyciu

this.form.valueChanges.subscribe(data => console.log('form changes', data)); 

Ale zmiany są wykrywane początkowo po załadowaniu formularza. Czy jest jakiś inny sposób sprawdzenia jakichkolwiek zmian w formularzu. Chcę, aby był wywoływany tylko wtedy, gdy użytkownik wprowadza zmiany w polu, a nie po załadowaniu formularza. Oto mój kod html i maszynopis:

profile.html:

<section> 
    <div> 
     <form [formGroup]="form"> 
      <fieldset> 
       <div class="panel-group m-l-1 m-r-1 accordion vertical-scroll" id=""> 
            <div class="form-group required no-gutter"> 
             <label for="firstname" > First Name:</label> 
             <div class="col-md-7 col-lg-6"> 
              <input type="text" class="form-control" id="firstname" placeholder="" name="firstname" title="firstname" 
               formControlName="firstname" size="128" aria-required="true" maxlength="35"> 
             </div> 
            </div> 

      </fieldset> 
      <div> 
        <button class="btn btn-primary" type="button" (click)="save()" >Save</button> 
        <button class="btn btn-primary" type="button" (click)="cancel()">Cancel</button> 
       </span> 
      </div> 
     </form> 
    </div> 
</section> 

profile.component.ts:

export class ProfileComponent implements OnInit, AfterViewInit, OnChanges { 
    public form: FormGroup; 

    constructor(private formBuilder: FormBuilder, private app: Application) { 

    } 

    loadForm(): void { 
     this.form = this.formBuilder.group({    
      firstname: [this.app.firstName, Validators.required]    
     }); 
     this.form.valueChanges.subscribe(data => console.log('form changes', data)); 

    } 

    save(): void { 

    } 

    cancel(): void { 

    }; 

    ngOnInit() { 
     this.loadForm(); 
    } 

    ngAfterViewInit() { 
     this.loadForm(); 
    } 


} 
+0

Możliwy duplikat [Jak obejrzeć zmiany formy w Angular 2?] (Http://stackoverflow.com/questions/34615425/how-to-watch-for-form-changes-in-angular-2) – blo0p3r

Odpowiedz

0

Myślę, że można po prostu zignorować pierwsze zmiany

this.form.valueChanges 
.skip(1) 
.subscribe(data => console.log('form changes', data)); 

Podpowiedź: import skip oper ator

+0

Tak, możemy użyć operatora pomijania, ale kiedy formuję ładunki, wywołuje zdarzenie 4 razy. Tak więc dla każdego formularza powinienem wiedzieć, ile razy zdarzenie jest wywoływane i użyć tego numeru w pominięciu. – Valla

+0

To dość kłopotliwe, ale nie znam lepszego sposobu. –

+0

Kontrola zabrudzenia i dotyku byłaby lepsza, IMO. Ma to zalety ignorowania programowo wprowadzanych zmian w formularzu. – silentsod

7

Można użyć wartości .dirty (lub .pristine), aby ustalić, czy użytkownik korzystał z interfejsu użytkownika, aby zmienić wartość sterowania:

<button class="btn btn-primary" type="button" (click)="save()" [disabled]="!form.dirty" >Save</button> 
<button class="btn btn-primary" type="button" [disabled]="!form.dirty"(click)="cancel()">Cancel</button> 

https://angular.io/docs/ts/latest/api/forms/index/AbstractControl-class.html#!#dirty-anchor

brudny: Boolean kontrola jest brudny, jeśli użytkownik zmienił wartość w interfejsie użytkownika na wartość .

Należy pamiętać, że programowa zmiana wartości kontrolki nie oznacza jej zabrudzenia jako .

dotknięty: boolean Kontrolka jest zaznaczona dotknięta, gdy użytkownik ma , wywołuje zdarzenie rozmycia.

0

spróbuj wykonać następujące czynności, aby sprawdzić, czy forma uległa zmianie:

ngOnChanges() { 
    if (!!this.form && this.form.dirty) { 
     console.log("The form is dirty!"); 
    } 
    else { 
     console.log("No changes yet!"); 
    }  
} 
0

można sprawdzić za zmianami w perticular formcontrol jak ten:

this.profileForm.controls['phone'].valueChanges.subscribe(
       data => console.log('form changes', data) 

       ); 
5

Problem z .dirty i .piękne booleans, jest to, że gdy się zmienią, nie wrócą, nawet jeśli cofniesz wszystkie wprowadzone zmiany. Udało mi się znaleźć sposób na rozwiązanie tego problemu, tworząc klasę, która monitoruje zmiany w całym formularzu i sprawdzi zmienione wartości z oryginalnymi wartościami formularza. W ten sposób, jeśli zmiany użytkownika zostaną cofnięte, formularz może powrócić do pierwotnego poziomu lub opcjonalnie emitować wartość logiczną na obserwowalnym (ReplaySubject), który można dostarczyć i zasubskrybować.

Zastosowanie będzie mniej więcej tak:

private _formIntactChecker:FormIntactChecker; 

constructor(private _fb: FormBuilder) { 

    this._form = _fb.group({ 
     ... 
    }); 

    // from now on, you can trust the .dirty and .pristine to reset 
    // if the user undoes his changes. 
    this._formIntactChecker = new FormIntactChecker(this._form); 

} 

Alternatywnie, zamiast przestawiania wartości logicznych .pristine/.dirty klasa może być skonfigurowany do wysyłania logiczną, przy każdej zmianie formy od nienaruszonej modyfikowane i nawzajem. Prawdziwa wartość boolowska oznacza, że ​​forma wróciła do stanu nienaruszonego, podczas gdy fałszywa wartość boolowska oznacza, że ​​formularz nie jest już nienaruszony.

Oto przykład, w jaki sposób chcesz go używać:

private _formIntactChecker:FormIntactChecker; 

constructor(private _fb: FormBuilder) { 

    this._form = _fb.group({ 
     ... 
    }); 

    var rs = new ReplaySubject() 

    rs.subscribe((isIntact: boolean) => { 
     if (isIntact) { 
      // do something if form went back to intact 
     } else { 
      // do something if form went dirty 
     } 
    }) 

    // When using the class with a ReplaySubject, the .pristine/.dirty 
    // will not change their behaviour, even if the user undoes his changes, 
    // but we can do whatever we want in the subject's subscription. 
    this._formChecker = new FormIntactChecker(this._form, rs); 

} 

Wreszcie klasa, która wykonuje całą pracę:

import { FormGroup } from '@angular/forms'; 
import { ReplaySubject } from 'rxjs'; 

export class FormIntactChecker { 

    private _originalValue:any; 
    private _lastNotify:boolean; 

    constructor(private _form: FormGroup, private _replaySubject?:ReplaySubject<boolean>) { 

     // When the form loads, changes are made for each control separately 
     // and it is hard to determine when it has actually finished initializing, 
     // To solve it, we keep updating the original value, until the form goes 
     // dirty. When it does, we no longer update the original value. 

     this._form.statusChanges.subscribe(change => { 
      if(!this._form.dirty) { 
       this._originalValue = JSON.stringify(this._form.value); 
      } 
     }) 

     // Every time the form changes, we compare it with the original value. 
     // If it is different, we emit a value to the Subject (if one was provided) 
     // If it is the same, we emit a value to the Subject (if one was provided), or 
     // we mark the form as pristine again. 

     this._form.valueChanges.subscribe(changedValue => { 

      if(this._form.dirty) { 
       var current_value = JSON.stringify(this._form.value); 

       if (this._originalValue != current_value) { 
        if(this._replaySubject && (this._lastNotify == null || this._lastNotify == true)) { 
         this._replaySubject.next(false); 
         this._lastNotify = false; 
        } 
       } else { 
        if(this._replaySubject) 
         this._replaySubject.next(true); 
        else 
         this._form.markAsPristine(); 

        this._lastNotify = true; 
       } 
      } 
     }) 
    } 

    // This method can be call to make the current values of the 
    // form, the new "orginal" values. This method is useful when 
    // you save the contents of the form but keep it on screen. From 
    // now on, the new values are to be considered the original values 
    markIntact() { 
     this._originalValue = JSON.stringify(this._form.value); 

     if(this._replaySubject) 
      this._replaySubject.next(true); 
     else 
      this._form.markAsPristine(); 

     this._lastNotify = true; 
    } 
} 

UWAGA: Ostrożnie z wartościami początkowymi

Klasa używa JSON.stringify(), aby szybko porównać cały obiekt klasy FormGrup. Należy jednak zachować ostrożność podczas inicjowania wartości kontrolnych.

Na przykład w przypadku pól wyboru należy ustawić wartość wiążącą je na wartość logiczną. Jeśli użyjesz innych typów, takich jak "sprawdzone", "0", "1" itp., Porównanie nie będzie działać poprawnie.

<input type="checkbox" ... [(ngModel)]="variable"> <!-- variable must be a boolean --> 

To samo tyczy się <select>, trzeba związać swoją wartość na ciąg znaków, a nie liczba:

<select ... [(ngModel)]="variable"> <!-- variable must be a string --> 

Dla stałych kontroli wprowadzania tekstu, również użyć ciągu:

<input type="text" ... [(ngModel)]="variable"> <!-- variable must be a string --> 

Oto przykład, dlaczego w przeciwnym razie nie będzie działać. Załóżmy, że masz pole tekstowe i zainicjujesz je za pomocą liczby całkowitej. Stringify pierwotnej wartości byłoby coś takiego:

{pole1: 34, pole2: „niektóre pola tekstowego”}

Jednakże, jeśli aktualizacje użytkownika pole1 na inną wartość i wraca do 34, nowa stringify będą:

{pole: „34”, pole2: „niektóre pola tekstowego”}

Jak widać, mimo że forma tak naprawdę nie zmieniło, porównanie ciąg między oryginałem a nowa wartość spowoduje fałszywe, ze względu na notowania wokół liczby 34.

+1

Ostatnio czytałem, że nie należy używać 'EventEmitter' dla niczego innego niż' @Output() '. Zaktualizowałem kod i zastąpiłem 'EventEmitter' przez' ReplaySubject'. – kontiki

+0

Żałuję, że nie ma wbudowanej tej funkcji: -/Zwłaszcza problemy 'stringify' –

+0

Można ustawić funkcję "zastępującą" dla JSON.stringify, która może być użyta do wymuszenia na liczbach, aby stały się łańcuchami. To powinno uczynić porównanie bardziej niezawodnym: 'JSON.stringify (model, function (i, val) {if (typeof (val)! == 'object') zwraca val.toString(); else return val;}) ' –

0

przede wszystkim użyj "NgForm".
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
Następnie w funkcji "onSubmit()" to zrobić -

onSubmit(myForm: NgForm): void { 
    let formControls = myForm.controls; 
    if(formControls.firstName.dirty) { 
    console.log("It's dirty"); 
    } 
    else { 
    console.log("not dirty"); 
    } 
} 

To na pewno działa. Możesz wydrukować cały "myForm" i sprawdzić, jakie opcje są dostępne.

Powiązane problemy