验证不会传播到 Angular 中的自定义表单控件 ng-select

Posted

技术标签:

【中文标题】验证不会传播到 Angular 中的自定义表单控件 ng-select【英文标题】:Validation is not propagate to Custom Form Control ng-select in Angular 【发布时间】:2020-06-12 23:43:55 【问题描述】:

我在 Angular 9 应用程序中使用带有自定义表单控件的反应式表单。

我用自定义表单控件包装了我的 ng-select 控件。

我的验证有问题。我将 formControl 设置为必需。 Documentation says ng-invalid css 类应该自动设置为 ng-select。但实际上使用自定义表单控件它不能正常工作。未设置 css 类,但设置了包装器类。我做错了什么还是这是图书馆的问题?

检查堆栈闪电战: https://stackblitz.com/edit/angular-rmvttg-ex63ka?file=src/forms-single-select-example.component.html&fbclid=IwAR2robtd_15khTVhmW59lLhn21HOHl_yYTrCWKaPRmfUt1QVvUn3n8V4Vjo

【问题讨论】:

【参考方案1】:

DiPix,问题在于 Angular 将控件状态 CSS 类添加到您的自定义控件,而不是属于您的内部控件的 ng-select

您可以注入 ngControl 并检查 control.control.invalid 和 control.control.touched

constructor(private injector:Injector)
ngOnInit()

   this.control = this.injector.get(NgControl);

然后你可以使用一些类似的

  <ng-select #mySelect  [ngClass]="'ng-invalid':control?.control.invalid,
                                    'ng-touched':control?.control.touched"
   ....>

另一种方法是询问父母的班级。所以如果你定义了一个像

这样的getter
get parentClass()

  const match = /class=\"(.*?)\">/.exec(this.element.nativeElement.parentElement.innerHTML);
  return match[0].split('"')[1]


constructor(private element:ElementRef)

你可以使用

<ng-select #mySelect  [ngClass]="parentClass" 
  ...>

你可以在your forked stackblitz看到

注意:无论如何,为了包装一个 ng-select,创建一个自定义表单控件是不必要的,只是一个带有 @Input 的 简单组件

@Input()control:any

你使用 as

    <mycontrol [control]="someForm.get('someControl')"></mycontrol>

你可以看到this another stackblitz变得多么简单

【讨论】:

那么基本上什么时候应该使用自定义表单控件? 在我看来,如果向控件添加新的外观,自定义表单控件很有用。 datePicker 是“自定义表单控件”的一个很好的例子,多选是另一个很好的例子,或者一个仪表,或者一个在下拉时显示表格的组合,(我怀疑带有掩码的输入)或...... . 如果只想“分组”输入,例如询问号码、到期日期和 CVC 的信用卡-即使显示卡类型-或带有街道、城市、国家和 CP 的一组地址,我更喜欢使用组件。但实际上这只是个人意见。我只是 Angular 的业余爱好者 对我有意义。但我有一个小问题。我已经指示寻找formControlName 属性this.hostElement.nativeElement.nextElementSibling.attributes.formControlName 现在这样的元素不存在,因为我正在使用未在DOM 上显示的[control]。知道如何获得 controlName 吗?【参考方案2】:

您可以通过InputFormGroup 向下传递到您的子组件并将其设置为ng-select 来解决此问题:

<mycontrol formControlName="someControl" [parentFormGroup]="someForm" ></mycontrol>

组件:

export class MyControlComponent implements ControlValueAccessor 

  @Input() parentFormGroup: FormGroup;
...

模板:

<ng-select #mySelect
           [formGroup]="parentFormGroup"
...

【讨论】:

以上是关于验证不会传播到 Angular 中的自定义表单控件 ng-select的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 4 中,为啥异步验证的嵌套控件不会将其有效性传播到父 FormGroup?

Angular 6. 如何在创建的自定义控件中赋予验证状态这个控件?

有没有更好的方法将值推送到表单控件,其中数组作为 Angular 中的值

Angular 2 - 单元测试绑定到嵌套的自定义表单控件

细说 Angular 的自定义表单控件

Angular - 模板驱动的表单 - 控制器中的自定义验证器功能