2016-12-05 101 views
7

檢查Angular 2中的表單中的更改我有一個包含少量數據字段和兩個按鈕的表單。我只想在用戶對錶單進行一些更改時才啓用按鈕。我曾嘗試過使用:如何使用

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

但是,當表單加載時也會檢測到更改。是否有任何其他方式來檢查表單中的任何更改。我希望僅在用戶對字段進行更改時才調用它,而不是在表單加載時調用。以下是我的html和打字稿代碼:

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

可能的重複[如何觀察Angular 2中的表單變化?](http://stackoverflow.com/questions/34615425/how-to-watch-for-form-changes-in-angular-2) – blo0p3r

回答

0

我想你可以不理會第一個變化

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

提示:輸入skip運行ATOR

+0

是的,我們可以使用跳過運算符,但是當我形成加載時,它會調用事件4次。因此,對於每個表格,我應該知道事件被調用的次數,並在跳過時使用該數字。 – Valla

+0

這很麻煩,但我不知道更好的方法。 –

+0

檢查骯髒和感動會更好,國際海事組織。這有一個忽略程序驅動的對錶單的更改的好處。 – silentsod

7

可以使用.dirty(或.pristine)值,以確定是否用戶已經使用的UI改變控制值:

<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

髒:Boolean一個控制是如果用戶在UI中更改了值 ,則髒。

請注意,對控件值的編程更改不會標記爲髒 。

touched:boolean一旦用戶有 觸發模糊事件,控件被標記爲觸摸。

0

嘗試以下,看看形式發生了變化:

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

您可以檢查這樣的變化perticular formcontrol:

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

       ); 
5

與.dirty的問題和.pristine booleans,就是一旦他們改變了,即使你撤銷了你所介紹的所有改變,他們也不會回頭。我設法找到解決這個問題的方法,創建一個監視整個表單變化的類,並用原始表單值檢查更改後的值。這樣,如果用戶更改被撤銷,表單可以返回到原始狀態,或者可選地在您可以提供和訂閱的可觀察對象(ReplaySubject)上發佈布爾值。

的使用將是這樣的:

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); 

} 

可替換地,代替復位.pristine/.dirty布爾值的類可以被配置成發射一個布爾每當從完整形式變成了已修改和反之亦然。一個真正的布爾表示,表單回到完好無損,而假布爾意味着表單不再完整。

這裏有一個關於你將如何使用它的一個例子:

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); 

} 

最後,做類中的所有工作:

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; 
    } 
} 

重要提示:小心與初始值

該類使用JSON.stringify()快速比較整個formGroup值對象。但是,初始化控制值時要小心。

例如,對於複選框,您必須將綁定它的值設置爲布爾值。如果您使用其他類型,如「已選中」,「0」,「1」等,則比較將無法正常工作。

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

同去<select>,你必須將其值綁定到一個字符串,而不是一個數字:

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

對於普通的文本輸入控件,也可以使用一個字符串:

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

這是一個例子,爲什麼否則它不會工作。假設你有一個文本字段,並用一個整數初始化它。原始值的字符串化將是這樣的:

{字段1:34,場2:「一些文本字段」}

但是,如果用戶更新FIELD1爲不同的值,並可以追溯到34,新的字符串化將是:

{場:「34」,場2:「一些文本字段」}

正如你所看到的,雖然形式並沒有真正改變,原來和之間的字符串比較新的價值將導致錯誤的,由於引號數34左右。

+1

我最近讀到,你不應該使用'EventEmitter'來代替'@Output()'。我更新了代碼,並用'ReplaySubject'替換了'EventEmitter'。 – kontiki

+0

我希望它具有內置的這個功能: - /尤其是'stringify'問題 –

+0

您可以爲JSON.stringify設置一個'replacer'函數,它可以用來強制數字變成字符串。這應該使比較更可靠:'JSON.stringify(model,function(i,val){if(typeof(val)!=='object')return val.toString(); else return val;}) ' –

0

首先使用「NgForm」。
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)">
然後在 「的onsubmit()」 函數做到這一點 -

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

它肯定會工作。您可以打印整個「myForm」並自己查看所有可用選項。