我想将表单验证移到指令,并在表单中的所有字段中保留ngForm验证。 在以下示例中,我将以下验证(1. Works)的输入文本字段移动到指令。但是当我将它移动到指令时,模型更新正确,但form.valid操作不受指令影响。 表单无效,因为输入文本没有值。当给出一个值时,激活了按钮并且表格有效。
1。工作原理:
<form (ngSubmit)="onSubmit()" #aliasForm="ngForm">
<div class="form-group">
<label for="firstname">Fornavn</label>
<input type="text" class="form-control" id="firstname"
required
[(ngModel)]="model.primaryAlias.firstName" name="firstname"
#name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Fornavn er påkrævet
</div>
</div>
<div class="form-group col-sm-6">
<p-dropdown [style]="{'width':'150px'}" [options]="genders" [(ngModel)]="model.primaryAlias.gender" name="genders" [required]="true"></p-dropdown>
</div>
Opret
2。不使用指令(p-input):
<form (ngSubmit)="onSubmit()" #aliasForm="ngForm">
<p-input [(value)]="model.primaryAlias.firstName" directiveLabel="Fornavn"></p-input>
<div class="form-group">
<p-dropdown [style]="{'width':'150px'}" [options]="genders" [(ngModel)]="model.primaryAlias.gender" name="genders" [required]="true"></p-dropdown>
</div>
<button type="submit" class="btn btn-success pull-right" [disabled]="!aliasForm.form.valid">Opret</button></form>
P-input.html:
<div class="form-group">
<label for="firstname">Fornavn</label>
<input type="text" class="form-control" id="firstname"
required
[(ngModel)]="value" (ngModelChange)="onChange($event)" ngControl="value" name="firstname"
#name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Fornavn er påkrævet
</div>
如何将验证移至指令并保持表单处理,整个表单完好无损?
答案 0 :(得分:3)
我会为你的自定义指令实现ControlValueAccessor
,如:
<强> P-input.ts 强>
export const INPUT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputTestComponent),
multi: true
};
@Component({
selector: 'p-input',
template: `
<div class="form-group">
<label for="firstname">{{directiveLabel}}</label>
<input type="text" class="form-control" id="firstname"
required
[(ngModel)]="value"
(ngModelChange)="onModelChange($event)" #name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Fornavn er påkrævet
</div>
</div>
`,
providers: [INPUT_VALUE_ACCESSOR]
})
export class InputTestComponent implements ControlValueAccessor {
onChange = (_: any) => {};
onTouched = () => {};
value: string;
@Input() directiveLabel: string;
@ViewChild('name') inputRef: ElementRef;
constructor(private renderer: Renderer2) {}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
onModelChange(newValue: string) {
this.value = newValue;
this.onChange(this.value);
}
writeValue(val: any): void {
this.value = val;
}
setDisabledState(isDisabled: boolean): void {
this.renderer.setProperty(this.inputRef.nativeElement, 'disabled', isDisabled);
}
}
<强> parent.html 强>
<p-input required
name="firstName" [(ngModel)]="model.primaryAlias.firstName" directiveLabel="Fornavn">
</p-input>
或手动将内部输入控件添加到表单:
<强> P-input.ts 强>
@Component({
selector: 'p-input',
template: `
<div class="form-group">
<label for="firstname">{{directiveLabel}}</label>
<input type="text" class="form-control" id="firstname"
required
[(ngModel)]="value"
(ngModelChange)="onChange($event)" name="firstname"
#name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Fornavn er påkrævet
</div>
</div>
`
})
export class InputTestComponent {
@Input() value: string;
@Input() directiveLabel: string;
@Output() valueChange: EventEmitter<string> = new EventEmitter();
@ViewChild(NgControl) inputControl: NgControl;
constructor(@Optional() private controlContainer: ControlContainer) {}
ngOnInit() {
if(this.controlContainer) {
this.controlContainer.formDirective.addControl(this.inputControl);
}
}
onChange(newValue: string) {
this.value = newValue;
this.valueChange.emit(this.value);
}
}
<强> parent.html 强>
<p-input [(value)]="model.primaryAlias.firstName" directiveLabel="Fornavn"></p-input>
<强> Stackblitz Example 强>