簡體   English   中英

angular2 formArray條件驗證

[英]angular2 formArray conditional validation

我正在嘗試基於將一個字段更改到formGroup內的另一個字段進行驗證,該字段位於此組的多個實例的FormArray內。 我在其中一個字段上使用mydatepicker。 例如,當更改日期時,我希望僅驗證該組中的原因更改字段以檢查以確保未選擇第一個選項(值為0)。 我有2個問題:

  1. 當我更改日期時,不會立即檢查更改原因字段的有效性。 它只發生在我將字段的值更改為1然后更改為0.它的默認值設置為0,它應該在我更改日期時立即選擇它。
  2. 當它最終意識到表單無效時,它會對所有更新按鈕執行此操作,而不僅僅是FormGroup中已更改的Date字段。

ts文件代碼:

subscribeDateChange(formGroup){
(<any>this.rfcActionTasksForm).controls.tasks.controls[0].controls['DueDate'];
const tasks = formGroup;


const changes$ = tasks.controls['DueDate'].valueChanges;



changes$.subscribe(dd => {
  var arrayControl = this.rfcActionTasksForm.get('tasks') as FormArray;
  var item = arrayControl.at(1);
  console.log(item);
  if(tasks.value['ReasonForChangeId'] == '0'){

    tasks.controls['ReasonForChangeId'].setValidators(Validators.pattern(/([1-9])/));

  }


});
}

ngOnInit() {
this.rfcActionTasksForm = this._fb.group({
  tasks: this._fb.array([this.buildTask()])

});


}
buildTask(): FormGroup {
  return this._fb.group({
      Id: '',
      Action: ['', Validators.required],
      Step: '',
      AssignedToId: ['', Validators.required],
      AssignedToColour: '',
      DueDate: ['', Validators.required],
      ReasonForChangeId: '',
      OriginalDueDate: '',
      Completed: '',
      OverDue: ''
  },{
    validator: (formGroup: FormGroup) => {
      //return this.validateDays(formGroup);
      //console.log(formGroup.controls['DueDate']);
      //this.subscribeDateChange(formGroup.controls['DueDate'], formGroup.controls['ReasonForChangeId']);
     return this.subscribeDateChange(formGroup);
    }
    });

}

HTML:

    <form class="multi-col implementation" *ngIf="rfc.Plan [formGroup]="rfcActionTasksForm">
  <div class="task-item" formArrayName="tasks" *ngFor="let task of tasks.controls; let i = index">
    <div [formGroupName]="i">
      <div class="row header-row">
          <div class="col-md-12">
            <h5 class="no-margin">Step {{i + 1}}</h5>
            <input
                [style.display]="'none'"
                formControlName="Step">
            <input
                [style.display]="'none'"
                formControlName="AssignedToColour">
            <input
                [style.display]="'none'"
                formControlName="Id">
          </div>
      </div>
      <div class="input-row row">
          <div class="col-md-11">
            <label for="{{'task' + i}}">Action:</label>
              <div
                    [ngClass]="{'has-error': (tasks.get(i + '.Action').touched || tasks.get(i + '.Action').dirty) && !tasks.get(i + '.Action').valid }">
                <textarea 
                rows="6"
                id="{{'task' + i}}"
                formControlName="Action"></textarea>

                <span class="help-block" *ngIf="(tasks.get(i + '.Action').touched || tasks.get(i + '.Action').dirty) && tasks.get(i + '.Action').errors">
                      <span *ngIf="tasks.get(i + '.Action').errors.required">
                          Please enter a title.
                      </span>
                  </span>

              </div>
          </div>

          <div class="col-md-1 text-center">
            <label>Status</label>
            <i *ngIf="tasks.get(i + '.Completed').value" class="glyphicon glyphicon-ok-sign ok" title="Completed"></i>
            <i *ngIf="!tasks.get(i + '.Completed').value && !tasks.get(i + '.OverDue').value" class="glyphicon glyphicon-minus-sign pending" title="In progress"></i>
            <i *ngIf="!tasks.get(i + '.Completed').value && tasks.get(i + '.OverDue').value" class="glyphicon glyphicon-exclamation-sign text-danger" title="Overdue!"></i>
          </div>

      </div>
      <div class="input-row row">
        <div class="col-md-3 assigned-to">
          <div
                [ngClass]="{'has-error': (tasks.get(i + '.AssignedToId').touched || tasks.get(i + '.AssignedToId').dirty) && !tasks.get(i + '.AssignedToId').valid }">
              <label for="{{'assignedTo' + i}}">Assigned to:</label>
              <div class="color-block" [style.background]="tasks.get(i + '.AssignedToColour').value"></div>
              <label class="fa select">
                <select
                  *ngIf="users"
                  id="{{'assignedTo' + i}}"
                  formControlName="AssignedToId">
                  <option 

                    *ngFor="let user of users | trueValueFilter: 'IsActive'"
                    [value]="user.Id">{{user.Name}}</option>
                </select>
              </label>

              <span class="help-block" *ngIf="(tasks.get(i + '.AssignedToId').touched || tasks.get(i + '.AssignedToId').dirty) && tasks.get(i + '.AssignedToId').errors">
                  <span *ngIf="tasks.get(i + '.AssignedToId').errors.required">
                      Please select a user.
                  </span>
              </span>

            </div>
        </div>
        <div class="col-md-3">
           <div 
                [ngClass]="{'has-error': (tasks.get(i + '.DueDate').touched || tasks.get(i + '.DueDate').dirty) && !tasks.get(i + '.DueDate').valid }">
              <label for="{{'dueDate' + i}}">Due date:</label>
              <my-date-picker 
                  class="datepicker"
                  type="text" 
                  id="{{'dueDate' + i}}"

                  formControlName="DueDate"
                  [options]="myDatePickerOptions"></my-date-picker>

                  <span class="help-block" *ngIf="(tasks.get(i + '.DueDate').touched || tasks.get(i + '.DueDate').dirty) && tasks.get(i + '.DueDate').errors">
                    <span *ngIf="tasks.get(i + '.DueDate').errors.required">
                        Please set a due date.
                    </span>
                  </span>

            </div>
        </div>
        <div class="col-md-2">


            <label for="{{'reason' + i}}">Reason for change:</label>
            <label class="fa select">
              <select
                class="reason-select"
                *ngIf="reasons" 
                id="{{'reason' + i}}"
                formControlName="ReasonForChangeId">
                <option 

                  *ngFor="let reason of reasons"
                  [value]="reason.Id">{{reason.Reason}}</option>
              </select>
            </label>


        </div>
        <div class="col-md-3">
          <div class="text-center">
              <label for="{{'OriginalDueDate' + i}}">Original due date:</label>
              <span>{{tasks.get(i + '.OriginalDueDate').value  | dateToStringFilter}}</span>
              <input 
                readonly
                type="text"
                id="{{'OriginalDueDate' + i}}"
                 [style.display]="'none'"
                formControlName="OriginalDueDate">

            </div>
        </div>
        <div class="col-md-1">
           <div class="text-center">
              <label for="{{'completed' + i}}">Completed:</label>

                  <div class="checkbox-group">
                    <input type="checkbox"
                      type="checkbox" 
                      id="{{'completed' + i}}"
                      formControlName="Completed">
                    <label class="checkbox" for="{{'completed' + i}}"></label>

                </div>

            </div>
        </div>
      </div>

      <div class="row">
        <div class="col-md-12">
          <div>

            <button 
              class="glyphicon glyphicon-plus-sign btn-icon add" 
              title="Insert task after this one" 
              (click)="insertTaskField(i)"></button>

            <button 
              class="glyphicon glyphicon-remove-sign btn-icon delete" 
              title="Delete this task" 
              (click)="removeTaskField(i, tasks.get(i + '.Id')?.value)"></button>

              <button 
              *ngIf="!tasks.get(i + '.Id').value"
              (click)="saveNewTask(rfc.Id, i);"
              [disabled]="!rfcActionTasksForm.valid"
              class="pull-right">Save new</button>
              <button 
               *ngIf="tasks.get(i + '.Id')?.value"
               [disabled]="!rfcActionTasksForm.valid"
               (click)="updateTask(i, tasks.get(i + '.Id')?.value)"
                class="pull-right">Update</button>

          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row last">
    <div class="col-md-12">
      <button 
        class="pull-right"
        [disabled]="enableUpdateAll === false"
        (click)="reOrderTasks()">Update All</button>
    </div>
  </div>

</form>

我在這看到多個問題:

驗證者應采用以下形式:

(control: AbstractControl): {[key: string]: any} => {
    if(isValid(control))
      return null;
    else
      return {"myValidator":"invalid thing detected"};
 }

您每次都返回undefined因此無法正常工作。 您無法訂閱,因為這意味着每次您在表單中進行更改時,您都會重新訂閱整個組的價值變化,這是無意義的。

忘掉valueChanges,你需要同步控制。 檢查是否存在錯誤並使用子控件的setError()方法。

就像是 :

(group: FromGroup): {[key: string]: any} => {
    if(!isValid(group)){
      group.get("myChildControl").setErrors({"localError":"error detected !"});
      return {"groupError":"error detected !"};
    }
    return null;
 }

我不確定你是否應該使用setError(errors,{emitEvent:false})的第二個參數setError(errors,{emitEvent:false})來避免傳播。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM