Angular Validators:我可以根据验证器为表单元素添加样式吗? [英] Angular Validators: Can I add styling to form elements based on their validators?

查看:19
本文介绍了Angular Validators:我可以根据验证器为表单元素添加样式吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 Angular 与 Forms 版本 4.1.0 和 Material 版本 2.0.0-beta.8 一起使用.我有一些字段需要根据存储在数据库表中的配置标记为必填字段,因此所需的特定字段可能会根据该配置而更改,并且在开发时是未知的.我正在根据该配置在我的表单控件上动态设置 Validators.required,这一切正常(即,如果您在访问它们后将它们留空,则相应的字段将变为红色).

但是,我还要求在标签后用星号标记所有必填字段.我有基于 HTML必需"属性的 CSS 来执行此操作,但不幸的是,Angular 并没有将此属性(或我能看到的任何类)应用到仅基于它应用了 Validator.required 的字段.当它无效时,验证器会在其上放置一个 ng-invalid 类,但当它有效或未触及时,任何东西都不会持续存在.

有没有办法让验证器自动应用属性或类?也许通过扩展 Validators.required 或以其他方式创建自定义验证器?出于绝望,我求助于在我的控制器中创建一个 isRequired(fieldName) 方法,并用 [required]="isRequired('fieldName') 标记每个字段以防万一它在未来的配置中成为必需,并且它可以工作,但是随着新屏幕的继续开发,它真的很笨拙并且容易被遗忘.

我对 Angular 还很陌生,所以我以前从未创建过自定义验证器.事实上,我怀疑这很常见,以至于在 Angular 的样式中包含 ::after CSS 是一些简单的调整.任何指导将不胜感激!

编辑以提供我所拥有的示例:

<form [formGroup]="formGroup"><md-输入-容器><input mdInput type="text" placeholder="name" formControlName="name"><md-输入-容器><!-- 这里有更多输入--></表单>

在我的控制器中:

generateValidators(formGroup: FormGroup) {//去获取哪些字段应该有的数据库配置//验证器,然后应用适当的验证器Object.keys(this.formGroup.controls).forEach(fieldName) =>{让验证器 = [];if(数据库配置表明此字段是必需的){validators.push(Validators.required);}if(数据库配置表明这个字段有一个最大长度) {validators.push(Validators.maxLength(length));}//等等.formGroup.controls[fieldName].setValidators(validators);}}

所有这些都成功地将 Validators.required 应用于数据库中标记为必需的字段,并且当用户未能填写它们时,它们会按预期运行.但这并没有添加 HTMLrequired"属性,即我如何使用 CSS 将星号添加到标签中.我需要以某种方式标记附加了 Validators.required 的字段,以便我可以使用 CSS 来应用星号,方法是添加required"属性或添加可以在我的 CSS 中使用的已知类.像这样:

.required:after { content:" *";}

作为一种解决方法,我在我的控制器中创建了一个 isRequired(string) 方法来按字段名称查找数据库配置,并像这样更新我的 HTML:

它有效,但不是很干净,需要所有其他开发人员遵守;而添加验证器的代码位于所有组件已经看到并使用它的公共位置.我还可以更新 generateValidators() 方法以添加类或属性,同时将 Validators.required 推送到验证器列表中,如果有人知道怎么做的话.我愿意接受建议.

解决方案

建议您创建一个了解您的逻辑并将其应用于标签的指令.该指令可以添加或删除星号.我在我的项目中做了同样类型的事情,而且效果很好.

 private addRequiredIndicator(): void {//<span id="xxx">//<sup class="requiredIndicator">*</sup>//</span>const sup = this.renderer.createElement('sup') 作为 HTMLElementsup.className = "requiredIndicator";const star = this.renderer.createText('*')this.renderer.appendChild(sup, star)const span = this.renderer.createElement('span') as HTMLSpanElementspan.id = this.idconst nbsp = this.renderer.createText(' ')this.renderer.appendChild(span, nbsp)this.renderer.appendChild(span, sup)const me = this.el.nativeElement 作为 HTMLElementthis.renderer.insertBefore(this.el.nativeElement,span,me.firstChild)}私有 removeRequiredIndicator(): void {const me = this.el.nativeElement 作为 HTMLElement如果(!我){返回}const elem = me.querySelector(`[id='${this.id}']`)如果(元素){me.removeChild(elem)}}

I'm using Angular with Forms version 4.1.0 and Material version 2.0.0-beta.8. I have fields that need to be marked as required based on a configuration stored in a database table, so the specific fields that are required can change depending on that configuration and are not known at development time. I am dynamically setting Validators.required on my form controls based on that configuration, and that is all working fine (i.e. the appropriate fields are turning red if you leave them blank after visiting them).

However, I also have a requirement to mark all required fields with an asterisk after their labels. I have the CSS to do this based on the HTML "required" attribute, but unfortunately, Angular does not apply this attribute (or any class that I can see) to a field simply based on it having Validator.required applied to it. The validator puts an ng-invalid class on it while it's invalid, but nothing that persists when it's either valid or untouched.

Is there any way to have the validator apply an attribute or class automatically? Maybe by extending Validators.required or otherwise creating a custom validator? Out of desperation, I've resorted to creating an isRequired(fieldName) method in my controller and marking every single field with [required]="isRequired('fieldName') just in case it becomes required in a future configuration, and it works, but it's really unwieldy and prone to being forgotten as development of new screens continues.

I'm fairly new to Angular, so I've never created a custom validator before. In fact I suspect that this is common enough that it's some simple tweak to include the ::after CSS in Angular's styling. Any guidance would be greatly appreciated!

Edited to provide an example of what I have:

<div>
  <form [formGroup]="formGroup">
    <md-input-container>
      <input mdInput type="text" placeholder="name" formControlName="name">
    <md-input-container>
    <!-- more inputs here -->
  </form>
</div>

In my controller:

generateValidators(formGroup: FormGroup) {
  // Go get the database configuration for which fields should have
  // validators, then apply appropriate validators
  Object.keys(this.formGroup.controls).forEach(fieldName) => {
    let validators = [];
    if(database configuration indicates this field is required) {
      validators.push(Validators.required);
    }
    if(database configuration indicates this field has a max length) {
      validators.push(Validators.maxLength(length));
    }
    // etc.
    formGroup.controls[fieldName].setValidators(validators);
  }
}

All of this successfully applies Validators.required to the fields marked as required in the database, and they behave as expected when the user fails to fill them in. But that doesn't add the HTML "required" attribute, which is how I'm adding the asterisk to the label with CSS. I need to somehow mark the fields that get a Validators.required attached to them so that I can use the CSS to apply the asterisk, either by adding the "required" attribute or by adding a known class that I can use in my CSS. Something like this:

.required:after { content:" *"; }

As a workaround, I've created an isRequired(string) method in my controller to go look up the database configuration by field name, and updated my HTML like this:

<input mdInput type="text" placeholder="name" formControlName="name" 
       [required]="isRequired('name')">

It works, but it's not very clean and requires all the other developers to adhere to this; whereas the code that adds the validators is in a common location where all components already see and use it. I could also update the generateValidators() method to add a class or attribute at the same time it pushes Validators.required onto the validators list, if someone knows how to do that. I'm open to suggestions.

解决方案

Suggest you create a directive that knows your logic and apply that to the label. That directive can add or remove the asterisk. I did the same type of thing in my project and it works well.

    private addRequiredIndicator(): void {
        // <span id="xxx">
        //     <sup class="requiredIndicator">*</sup>
        // </span>

        const sup = this.renderer.createElement('sup') as HTMLElement
        sup.className = "requiredIndicator"

        const star = this.renderer.createText('*')
        this.renderer.appendChild(sup, star)

        const span = this.renderer.createElement('span') as HTMLSpanElement
        span.id = this.id

        const nbsp = this.renderer.createText(' ')
        this.renderer.appendChild(span, nbsp)

        this.renderer.appendChild(span, sup)

        const me = this.el.nativeElement as HTMLElement

        this.renderer.insertBefore(this.el.nativeElement, span, me.firstChild)
    }

    private removeRequiredIndicator(): void {
        const me = this.el.nativeElement as HTMLElement
        if (!me) {
            return
        }

        const elem = me.querySelector(`[id='${this.id}']`)
        if (elem) {
            me.removeChild(elem)
        }
    }

这篇关于Angular Validators:我可以根据验证器为表单元素添加样式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆