代码之家  ›  专栏  ›  技术社区  ›  Preston

使用用户名参数和if else进行角度自定义验证-控件不工作

  •  0
  • Preston  · 技术社区  · 7 年前

    我一直在尝试让下面的自定义验证器工作。它检查数据库,看看用户是否输入了唯一的用户名,但总是有各种各样的错误。我已经移动了“control:abstractcontrol”代码行,包括HTTP服务调用上面的代码,但仍然有错误。该服务工作正常,并返回用户名对象,如用户名:“preston”。

    我怀疑问题在于我没有一个关于如何使用表单控件的心理图,而且大部分在线信息不包括先联系数据库,然后联系条件数据库。我还怀疑我将表单控件概念与一个简单的旧表单事件交互方法混合在一起,但这失败了。我该怎么处理这个烂摊子?

    模板的一部分:

    <form [formGroup]="addEditMemberForm"
            (ngSubmit)="onSubmit(addEditMemberForm.value)"
            [class.error]="!addEditMemberForm.valid && addEditMemberForm.touched">
    
        <mat-form-field class="inputBackground">
              <input matInput #userName maxlength="30" class="inputField"    
                  type="text" id="user_name"formControlName="user_name" 
                  [errorStateMatcher]="matcher" required
                  (blur)="validateUsername(userName.value)">
    
              <mat-hint align="end">{{userName.value?.length || 0}}/30</mat-hint>
    
              <div class="formError" 
                *ngIf "this.addEditMemberForm.controls['user_name']
                    .hasError('alreadyExist')">
                    This username already exists in our database</div>
    
              <mat-error>{{ errors.required }}</mat-error>
        </mat-form-field>
    </form>
    

    在组件上:

    private createForm() {
        this.addEditMemberForm = this.fb.group({
        ...
        user_name: ['', Validators.required, this.validateUsername()],
        ...
    }
    
     private validateUsername(userName) {
       this.httpService.validateUsername(userName)
        .subscribe(res => {
          const convertedName = res['user_name']; // Convert from object to string.
    
            if (convertedName === userName): ValidatorFn {
              console.log('res if: ', res);
              // return (control: AbstractControl): { [key: string]: boolean } => {
              return (control: AbstractControl): ValidationErrors | null => {
                return {'alreadyExist': true};
              };
            }
            return null;  // This result means that the user name isn't taken and do nothing.
          },
            (err: HttpErrorResponse) => {
              console.log(err.error);
              console.log(err.message);
            }
        );
     }
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   Antoniossss    7 年前

    尝试

    user_name: ['', Validators.required, this.validateUsername().bind(this)],\
    

      private validateUsername(control: AbstractControl) {
        const val = control.value;
        return this.httpService.validateUsername(val).pipe(
          map(res => {
            const convertedName = res['user_name'];
            return convertedName === val ? { alreadyExist: true } : null;
          }),
          catchError(err => {
            console.log(err.error);
            console.log(err.message);
            this.messagesService.openDialog('Error aef-2', 'Database not available.');
            return Observable.of({ "error": true })
          })
        );
    

    https://stackblitz.com/edit/angular-material-table-with-multi-queries-jgr5cj?file=app/members/add-edit-form/add-edit-form.component.ts

    显然,这可能不起作用,因为我不知道您的服务如何工作,也不知道我将提供什么样的响应。但服务是在用户输入时调用的,这很好。您只需要添加 catchError 到管道来处理异常,您就完成了。

        2
  •  0
  •   Preston    7 年前

    @安东尼奥斯斯对我最初的问题有一个可行的答案,他非常有助于指导我理解这是如何工作的。但是,如果使用.bind(this),则会有一个服务器调用,其中包含用户键入的每个字母,如增量搜索。如果您检查服务器和控制台日志,这可能会变得很难看。

    在发布本文时,Angular Form Control更新程序:“blur”有一个pull请求将其添加到FormGroup。截至2018年6月26日,它不起作用。这可能使@antoniosss的解决方案成为更好的选择。

    我重构了他的代码,经过多次实验,找到了一个解决方案。一个更优雅的解决方案是好的。

    Stackbliz with code

    HTML。注意简单的“ngif”。如果绑定变量为真,则显示消息。

        <li>
            <label class="label-pad">User name: </label>
            <mat-form-field class="inputBackground">
              <input matInput #userName maxlength="30" 
                     class="inputField" type="text" id="user_name"
                     formControlName="user_name" 
                     [errorStateMatcher]="matcher" required 
                     (blur)="validateUsername(userName.value)">
    
              <mat-hint align="end">{{userName.value?.length || 0}}/30</mat-hint>
    
              <div class="formError" *ngIf = "this.inDatabase === true">
                This username already exists in our database</div>
    
              <mat-error>{{ errors.required }}</mat-error>
    
            </mat-form-field>
        </li>
    

    组件。创建表单时,没有自定义验证器和绑定。绑定消除了HTML中的模糊。它必须消失。当用户离开字段并传递字段值时,blur调用函数。调用的函数从数据库中获取正确的对象,只有一个调用,并提取用户名字符串。然后它测试条件,如果有匹配项,则调用另一个函数来处理控件,用setTimeout显示和清除消息,并清除将其设置为无效的字段。然后用户再试一次。当然,这应该是一种服务,但我会在这里保持简单。stackbliz代码经常更改,因此有一天它可能会出现在服务中。

    ...
    
    public inDatabase = false; // Form validation - userName taken...
    
    ...
    
    constructor(
        private fb: FormBuilder,
        private httpService: HttpService,
        private messagesService: MessagesService,
      ) { }
    
      ngOnInit() {
        this.createForm();
      }
    
    
      // The reactive model that is bound to the form.
    
      private createForm() {
        this.addEditMemberForm = this.fb.group({
          id: [''],
          first_name: ['', Validators.required],
          last_name: ['', Validators.required],
          user_name: ['', Validators.required],
          country: ['', Validators.required],
        });
      }
    
      private validateUsername(userName) {
          return this.httpService.validateUsername(userName)
          .subscribe(res => {
    
            const extractedName = res.map(x => x.user_name); // array
    
            // Convert from array to string.
            const convertedName = extractedName.toString(); 
    
            // If the condition is met then call the isTaken function below.
            return convertedName === userName ? this.isTaken() : null;
          },
            (err: HttpErrorResponse) => {
              console.log(err.error);
              console.log(err.message);
              this.messagesService.openDialog('Error', 'Delete did not happen.');
            }
          );
      }
    
      public isTaken() {
        this.inDatabase = true;  // Var is bound to html conditional.
    
        // Remove the already in database message after some time.
        setTimeout (() => {
          this.inDatabase = false;
        }, 2000);
    
        // Clear the field to reset validation and prepare for next attempt.
        this.addEditMemberForm.controls['user_name']
          .setValue(null);
      }
    
    推荐文章