【问题标题】:Angular 2 - Move form validation to directiveAngular 2 - 将表单验证移动到指令
【发布时间】:2018-02-20 05:07:56
【问题描述】:

我想将表单验证移至指令,并在表单中的所有字段中保持 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>

操作

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.ts:

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>

如何将验证移至指令并保持表单处理,整个表单完好无损?

【问题讨论】:

    标签: angular angular-directive angular-forms


    【解决方案1】:

    我会为您的自定义指令实现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>
    

    Stackblitz Example

    或手动向表单添加内部输入控件:

    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

    【讨论】:

    • 谢谢。这确实是我在 stackoverflow 上收到的最佳答案和记录最多的答案。效果很棒!我最终使用(1.示例)“必需”值作为输入,我希望能够根据我的类属性激活/停用验证。
    猜你喜欢
    • 2017-04-12
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多