什么是自定义表单字段和验证的最佳实践?

时间:2018-04-03 10:13:19

标签: angular

我正在构建一个组件库,需要对表单字段验证做出决定。

我的公司正在构建自定义主题,并且作为其中一部分,表单字段是自定义的。

他们有验证信息,验证颜色等。

创建自包含输入字段的想法

<app-custom-input
    [(value)]="fieldString"
    [validations]="{
        required: { message: 'Field is required' }
     }">
</app-custom-input>

Or

<app-custom-input
    [(value)]="fieldString"
    [validations]="[
       { 
           validator: Validators.required, 
           message: 'Field is required'
       }
    ]">
</app-custom-input>

如果该字段与验证项目不匹配,则该字段会更改其样式,附加消息等,所有这些都在内部发生。在外部,你只需要一个字符串值,不用担心。

我已经看过一些例子,人们会重复标记构成表单字段,消息,提示,错误等。

任何最佳做法?第一种方法有什么问题吗?

2 个答案:

答案 0 :(得分:1)

我通过在本机表单控件周围构建包装器并通过用户定义的数据类型仅在1个文件中合并自定义验证来完成类似的操作。

我做的如下:

Custom Input Field Component会接受数据类型并将其传递给Validator Service(见下文)。

以角度形式提供验证器服务,该服务将采用数据类型的名称并从json文件中查找以显示maxminlength等约束,requiredpattern并构建一个表单控件,由Custom Input Field Component消耗掉。

attachValidator(datatype, extras = null , name) {

let min_len
let max_len
let max
let min
let allowed_values
let spans
let pattern
let validators = []
let type = this.typeService.getTypeAttrs(datatype)

for (let key in type) {
  switch (key) {
    case 'max_value': { max = type[key]; validators.push(this.maxValidator(max)); } break;
    case 'min_value': { min = type[key]; validators.push(this.minValidator(min)); } break;
    case 'allowed_values': { allowed_values = type[key]; validators.push(this.allowedValuesValidator(allowed_values)) } break;
    case 'max_decimals': { spans = type[key]; validators.push(this.decValidator(spans)) } break;
    case 'pattern': { spans = type[key];pattern = spans; validators.push(this.patternValidator(spans)) } break;
    case 'min_length': { spans = type[key];validators.push(Validators.minLength(spans)) } break;
    case 'max_length': { spans = type[key];validators.push(Validators.maxLength(spans)) } break;

  }
}

for (let key in extras) {
  if (extras[key] != undefined) {
    switch (key) {
      case 'required': { if (extras[key]) { validators.push(Validators.required) } } break;
      case 'integer': { if (extras[key]) { validators.push(this.isInteger()) } } break;

    }
  }
}
return [new FormControl(name, validators) , Validators.compose(validators) , pattern]
  }

HTML下面是我的自定义输入文本组件,其后面有所有Control_Value_Accessor jugglery。

您可以为错误字段添加通用标记,例如

<mat-form-field [floatPlaceholder]="float" *ngIf="!isDisabled">
<mat-placeholder>
    <span style="font-size:1.18em;">{{label}}</span>
</mat-placeholder>
<input #txtip="ngModel" [ngClass]="{readonly : checkMode() == true}" type="{{inputtype}}" matInput [minlength]="min_length" [maxlength]="max_length" [(ngModel)]="value" name="{{name}}" [required]="required" [pattern]="pattern"
    [readonly]="checkMode()" [errorStateMatcher]="myErrorStateMatcher" (blur)="emitBlur()">

<mat-hint>
    <strong>{{placeholder}}</strong>
</mat-hint>
<mat-error *ngIf="showErrors || txtip.invalid">
    <ui-message [showIcons]='false' [msgs]="errorMsgs"></ui-message>
</mat-error>
</mat-form-field>

这对你的问题有非常稀少的信息,但相关的,我已经做了比这更多的信息。请随意发表评论,并询问您是否觉得答案令人困惑。

答案 1 :(得分:1)

我经常和你描述的目标相同。您说过将完整的输入逻辑(包括提示,验证行为等)拆分为单独的组件,而这正是我通常所做的。我认为它看起来相当优雅,所以最终在带有表单的组件中,你没有比处理简单input时更多的逻辑,并且所有其他逻辑都封装在具有输入本身的重复子组件中。您需要的只是在子组件中实现ControlValueAccessor接口,并且可以通过常规[(ngModel)]绑定父组件中的输入值。你可以找到一些关于实现ControlValueAccessor接口的教程,但是我第一次看到这个:http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel。乍一看,它看起来有点复杂,但是当你几次写下这个逻辑时,它就会变得简单。