Angular 验证器被忽略或不工作

Angular validators are ignored or not working

提问人:AntoBoy 提问时间:10/30/2023 最后编辑:AntoBoy 更新时间:10/30/2023 访问量:68

问:

我使用ReactiveForms。我有一个登录组件,我使用两个输入字段(电子邮件和密码)。此输入字段都来自同一个自定义组件“TextFieldComponent”。我尝试在我的电子邮件输入上添加一个特定的正则表达式验证器,在我的密码输入上添加一个 minLength 验证器(仅用于测试)。当我输入有效的电子邮件地址时,我收到自定义错误消息“无效的电子邮件地址”,但事实并非如此。此外,对于密码输入,不考虑 minLength 验证器。

LoginComponent TS中:

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../auth.service';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { LoginRequest } from 'src/app/shared/models/login-request';
import { Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  loginForm: FormGroup;

  ngOnInit(): void {
    this.createLoginForm();
  }

  createLoginForm(): void {
    this.loginForm = new FormGroup({
      email: new FormControl(null, [Validators.required, Validators.pattern(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/)]),
      password: new FormControl(null, [Validators.required, Validators.minLength(4)])
    });
  }
}

LoginComponent 模板

<form (ngSubmit)="onSubmit()" [formGroup]="loginForm" class="form-signin">
    <h1 class="h3 mb-3 font-weight-normal text-center">Please sign in</h1>

    <app-text-input
        [formControlName]="'email'"
        [label]="'Email address'">
    </app-text-input>

    <app-text-input
        [formControlName]="'password'"
        [label]="'Password'"
        [type]="'password'">
    </app-text-input>

    <app-button [disabled]="loginForm.invalid" type="submit" label="Sign in" className="btn btn-primary w-100" class="w-100"></app-button>
</form>

TextFieldComponent TS

import { Component, ElementRef, Input, Self, ViewChild } from '@angular/core';
import { AbstractControl, NgControl } from '@angular/forms';

@Component({
  selector: 'app-text-input',
  templateUrl: './text-input.component.html',
  styleUrls: ['./text-input.component.scss']
})
export class TextInputComponent {
  @ViewChild('input', {static : true}) input: ElementRef; // reference to the input field
  @Input() type : 'email' | 'text' | 'password' = 'text'; // input type (password, text, date, button, ...)
  @Input() label: string; // Label that describes the input field

  constructor(
    @Self() public controlDir: NgControl
  ) {
    // Bind the valueAccessor to this particular class, which lets us access the control directive inside our component + template
    this.controlDir.valueAccessor = this;
  }

  ngOnInit(): void {
    const control = this.controlDir.control as AbstractControl;
    control.updateValueAndValidity();
  }

  onChange(event? : any) { }

  onTouched(event? : any) {}

  writeValue(obj: any): void {
    this.input.nativeElement.value = obj || '';
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
}

TextFieldComponent 模板

<div class="form-label-group">

<label for="{{label}}">{{label}}</label>
<input #input [ngClass]="(controlDir && controlDir.control && controlDir.control.touched) 
        ? !controlDir.control.valid 
        ? 'is-invalid' 
        : 'is-valid' 
        : null" [type]="type" (input)="onChange($event)" (blur)="onTouched()" id="{{label}}"
    class="form-control" placeholder="{{label}}" autocomplete="off" >

<!-- Synchornous Error Messages -->

<!-- Invalid control check -->
<div *ngIf="(
    controlDir && 
    controlDir.control &&
    !controlDir.control.valid &&
    controlDir.control.touched
    )" class="invalid-feedback">

    <!-- Required control check -->
    <span *ngIf="controlDir.control.errors?.['required']">{{label}} is required</span>

    <!-- Pattern control check -->
    <div *ngIf="controlDir.control.errors?.['pattern']">Invalid Email Format</div>


</div>

有人知道我的验证器出了什么问题以及为什么它们没有按预期工作吗?

角度 反应形式

评论

0赞 Misha Mashina 10/30/2023
在我看来,你正在逃避你不应该逃避它的\字符。尝试或(区别在于,在第一个示例中,我从电子邮件地址末尾的点之后删除了允许的字符,而第二个示例允许它(尽管您的原始正则表达式确实允许它)。^[\w\-\.]+@([\w-]+\.)+[\w]{2,4}$^[\w\-\.]+@([\w-]+\.)+[\w-]{2,4}$-
0赞 AntoBoy 10/30/2023
@MishaMashina我不认为正则表达式是这里的问题。我单独测试了我以确保它是正确的,如上所述。在尝试您的建议时,它在控制台中为两个正则表达式提供了以下错误消息: 错误语法错误:无效的正则表达式:/^[w-.]+@([w-]+.)+[w-]{2,4}$/: 字符类中的范围乱序
0赞 Eliseo 10/30/2023
请参阅文档,模式验证器参数可以是 regExpr(然后就像)或字符串(然后第一个字符将是 b 和最后一个 -我建议你直接使用 RegExpr-Validators.pattern(/...../)^$
0赞 AntoBoy 10/30/2023
@Eliseo我编辑了我的代码。错误/行为仍然存在,所以我认为正则表达式不是这里的问题。
0赞 Eliseo 10/30/2023
@AntoBoy,是的,你是对的,你的组件中有一个错误

答:

1赞 Eliseo 10/30/2023 #1

问题出在自定义窗体控件上。

你有:

<input #input ... (input)="OnChange($event)">

$event是输入事件,则应使用

<input #input ... (input)="onChange(input.value)">

或创建函数

  change(event:any)
  {
    this.onChange(event.target.value)
  }
  //and use
   <input #input ... (input)="change($event)">

提示:有时,要检查FormGroup是util write in .html(在本例中为loginComponent)

<pre>
  {{loginForm.value|json}}
</pre>

注意:通常是一个自定义窗体控件,用于制作“复杂 UI”。您可以创建带有标签、错误...使用 viewProvider,例如 this SO

评论

0赞 AntoBoy 10/30/2023
多谢。我确实遵循了上面的解决方案:它有效。也感谢您的提示。标记为已接受<input #input ... (input)="onChange(input.value)">