Angular 2 - с помощью ngControl с дополнительными полями

Мне тяжело пытаться использовать как * ngIf внутри формы, так и ngFormModel для проверки указанной формы.

Используйте случай: на основе ввода пользователя, скрыть или деактивировать некоторые конкретные поля в форме. Но в случае показа этих входов они должны быть проверены.

Если требуется только базовая проверка, я могу сделать так или иначе:

  • Если вход требуется только, он работает A-OK с помощью ngControl и required
  • Если необходим конкретный формат, можно использовать атрибут pattern. Это не Angular, но он работает.

Но для того, чтобы реализовать более сложные проверки, я пытался использовать ngControl, связанный с ngFormModel, чтобы использовать пользовательские проверки. Я использовал фрагменты кода, найденные на следующих страницах:

Как добавить шаблон проверки формы в angular2 (и ссылки, на которые они ссылаются)

Angular2 Формы: проверки, ngControl, ngModel и т.д.

Мой код выглядит следующим образом:

HTML

<div>
  <h1>Rundown of the problem</h1>
  <form (ngSubmit)="submitForm()" #formState="ngForm" [ngFormModel]="myForm">
    <div class="checkbox">
      <label>
        <input type="checkbox" [(ngModel)]="model.hideField" ngControl="hideField"> Is the input below useless for you ?
      </label>
    </div>

    <div *ngIf="!model.hideField">
      <div class="form-group">
        <label for="optionalField">Potentially irrelevant field </label>
        <input type="text" class="form-control" [(ngModel)]="model.optionalField" ngControl="optionalField" required #optionalField="ngForm">
        <div [hidden]="optionalField.valid || optionalField.pristine" class="alert alert-warning">
          This input must go through myCustomValidator(), so behave.
        </div>
      </div>
    </div>

    <button type="submit" class="btn btn-primary" [disabled]="!formState.form.valid">I can't be enabled without accessing the input :(</button>
    <button type="submit" class="btn btn-default">Submit without using form.valid (boo !)</button>
  </form>
</div>

Ответ 1

Что вы можете попробовать сделать, это reset валидаторы на вашем элементе управления. Это означает, что если вы хотите, чтобы новый набор валидаторов был привязан к элементу управления из-за изменения состояния, вы бы переопределили функцию валидатора.

В вашем случае, когда ваш флажок установлен/не установлен, вы хотите следующее:

  • Задайте ввод как необязательный (не обязательно), но все еще проверяйте его на свой пользовательский валидатор.
  • Отмените проверку валидаторов на исходное состояние, если флажок снят.
  • Повторите проверку элемента управления, чтобы обновить form.valid.

Посмотрите мой пример plnkr на основе Angular.io Forms Guide

if (optional)
   this.heroFormModel.controls['name'].validator = Validators.minLength(3);
else
   this.heroFormModel.controls['name'].validator =
        Validators.compose([Validators.minLength(3), Validators.required]);

this.heroFormModel.controls['name'].updateValueAndValidity();

Ответ 2

Я просто столкнулся с одной и той же проблемой и нашел обходное решение, основанное на ручном включении и исключении элементов управления:

import {Directive, Host, SkipSelf, OnDestroy, Input, OnInit} from 'angular2/core';
import {ControlContainer} from 'angular2/common';

@Directive({
  selector: '[ngControl]'
})
export class MyControl implements OnInit, OnDestroy {
  @Input() ngControl:string;
  constructor(@Host() @SkipSelf() private _parent:ControlContainer) {}

  ngOnInit():void {
    // see https://github.com/angular/angular/issues/6005
    setTimeout(() => this.formDirective.form.include(this.ngControl));
  }

  ngOnDestroy():void {
    this.formDirective.form.exclude(this.ngControl);
  }

  get formDirective():any {
    return this._parent.formDirective;
  }
}

Чтобы сделать эту работу, все динамические элементы управления сначала должны быть исключены из формы; Подробнее см. plunkr.

Ответ 3

Вот обновленная версия для RC4. Я также переименовал его в npControl для моих целей.

import { Directive, Host, OnDestroy, Input, OnInit } from '@angular/core';
import { ControlContainer } from '@angular/forms';

@Directive({
  selector: '[npControl]'
})
export class NPControlDirective implements OnInit, OnDestroy {
  @Input() npControl: string;

  constructor(@Host() private _parent: ControlContainer
  ) { }

  ngOnInit(): void {
    console.log('include ', this.npControl);
    setTimeout(() => this.formDirective.form.include(this.npControl));
  }

  ngOnDestroy(): void {
    console.log('exclude ', this.npControl);
    this.formDirective.form.exclude(this.npControl);
  }

  get formDirective(): any {
    return this._parent;
  }
}