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