【问题标题】:status of observable never completes. When subscribing to it, getting a type errorobservable 的状态永远不会完成。订阅时出现类型错误
【发布时间】:2020-04-07 19:58:03
【问题描述】:

我正在使用自定义异步验证器构建反应式表单。 验证器使用 Angular 的 HTTP 客户端向我的服务器(在 node.js 上运行)发出请求,并使用接收表单控件值的回调函数。 这个想法是检查表单中输入的提交的ID是否已经存在于数据库中。 服务器调用正常工作。调用,返回值(如果存在)返回一个长度为1的对象,不存在时返回null。

问题是,调用的状态保持为未决状态并阻止表单变为有效状态(我将提交按钮链接到表单底部,就像 [disabled]="!newUser.valid" 一样,因为异步验证器的状态保持等待状态,并且 observable 永远不会完成,按钮保持禁用状态。

我已尝试订阅 observable,但随后出现以下错误?: ((c: FormControl) => Subscription | Observable)[]' 不可分配给'AsyncValidatorFn | AsyncValidatorFn[]

Register.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { matchOtherValidator } from '../match-other-validator';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs';
import { map} from 'rxjs/operators';

const tzAsyncValidator = (http: HttpClient) => (c: FormControl) => {
  console.log(c.parent);
  if (!c || String(c.value).length === 0) {
    console.log("!c|| String (c.value).length ===0")
    return of(null);

  }
  return http.get('http://localhost:4000/userIds/' + String(c.value))
    .pipe(
      map((ids: any[]) => {
        console.log(ids);
        if (ids.length === 1) {
          console.log(c.parent.status);
          console.log(c.status);
          return { exists: true }
        }
        if (ids.length === 0) {
          console.log(c.parent.status);
          console.log(c.status);
          return { exists: null};

        }

      }
      )


    )
    .subscribe()
    ;
}






@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.css']
})

export class RegisterComponent implements OnInit {
  public newUser;
  public verification;
  constructor(private http: HttpClient) { }



  ngOnInit() {
    this.newUser = new FormGroup({
      Tz: new FormControl('', [Validators.required, Validators.minLength(4), Validators.maxLength(9)], [tzAsyncValidator(this.http)]),
      Email: new FormControl('', [Validators.required, Validators.email]),
      PW: new FormControl('', [Validators.required, Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$')]),
      PWVerification: new FormControl('', [Validators.required, Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'), matchOtherValidator('PW')])
    })
  }

}

Register.component.html

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#staticBackdrop">
    Sign up!
  </button>

  <!-- Modal -->
  <div class="modal fade" id="staticBackdrop" data-backdrop="static" tabindex="-1" role="dialog"
    aria-labelledby="staticBackdropLabel" aria-hidden="true">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="staticBackdropLabel">Sign Up!</h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            <span aria-hidden="true">&times;</span>
          </button>
        </div>
        <div class="modal-body">
                <form [formGroup]="newUser" (ngSubmit)='onSubmit()' >
                        <label>ID</label>
                        <br>
                        <input type="text" placeholder="Please Enter Your ID" formControlName="Tz">
                        <br>
                        <label>Email</label>
                        <br>
                        <input type="email" placeholder="Please Enter Your Email" formControlName="Email">
                        <br>
                        <label>Password</label>
                        <br>
                        <input type="text" name="password" placeholder="Please Choose A Password" formControlName="PW" size="25">
                        <br>
                        <label>Resubmit Your Password</label>
                        <br>
                        <input type="text" name="confirmPassword" placeholder="Please Resubmit Your Password" formControlName="PWVerification" validateEqual="password" size="30" >
                        <br>
                        <input type="submit" class="btn btn-success" [disabled]="!newUser.valid" >
                        <br>
                        <span *ngIf="newUser.get('Email').invalid &&!newUser.get('Email').pristine">Your email does not look right</span>
                        <br>
                        <span *ngIf="newUser.get('Tz').errors?.minlength">Your ID must be at least 4 digits long</span>
                        <br>
                        <span *ngIf="newUser.get('Tz').errors?.maxlength">The maximum ID length is 9 digits</span>
                        <br>
                        <span *ngIf="newUser.get('PW').invalid&&!newUser.get('PW').pristine">Password must include at least one letter and one digit</span>
                        <br>
                        <span *ngIf="newUser.get('PWVerification').errors?.matchOther">Your submitted passwords don't match</span>
                        <br>
                        <span *ngIf="newUser.get('Tz').errors?.exists">This ID already exists</span>
                      </form>
        </div>
        <div class="modal-footer">
        </div>
      </div>
    </div>
  </div>

【问题讨论】:

    标签: angular observable angular-reactive-forms


    【解决方案1】:

    https://stackoverflow.com/a/59282265/7122286

    您可以使用例如 take(1) 来标记 Observable 已完成

    const tzAsyncValidator = (http: HttpClient) => (c: FormControl) => {
      console.log(c.parent);
      if (!c || String(c.value).length === 0) {
        console.log("!c|| String (c.value).length ===0")
        return of(null);
    
      }
    
      return c.valueChanges.pipe(
        take(1),
        switchMap(_ =>
          http.get('http://localhost:4000/userIds/' + String(c.value))
            .pipe(
              map((ids: any[]) => {
                console.log(ids);
                if (ids.length === 1) {
                  console.log(c.parent.status);
                  console.log(c.status);
                  return { exists: true }
                }
                if (ids.length === 0) {
                  console.log(c.parent.status);
                  console.log(c.status);
                  return null;
                }
              }))
        ))
    
    }
    

    【讨论】:

      【解决方案2】:

      如果该值不存在,API 返回 null 是我从上面得到的。

      http:HttpClient 的默认响应类型是 json,null 不是有效的 json。

      要接受其他响应类型,请将{responseType: 'text'} 添加到http.get(url, {responseType: 'text'})

      即: return http.get('http://localhost:4000/userIds/' + String(c.value),{responseType: 'text'})

      然后您将被要求按照您的意愿处理响应。

      有关更多信息,请参阅以下指南:https://angular.io/api/common/http/HttpRequest#responseType

      【讨论】:

      • 我添加了 responsetype 但现在我得到了这个:Argument of type 'OperatorFunction' 不能分配给 'OperatorFunction'。类型 'any[]' 不能分配给类型 'string'。
      • 由于您更改了 responseType,map((ids: any[]) 不再适用,而是 map((ids: string) 并且您的 if 条件必须相应更改。
      • 我建议对后端进行更改并返回有效的 JSON。但是,如果您不能这样做,那么您将不得不更改执行签入 if 语句的方式。
      • 好的,修改好了。问题仍然存在。异步验证器状态卡在等待中
      猜你喜欢
      • 2019-02-27
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      • 2021-05-16
      • 2018-10-26
      • 2021-05-29
      • 1970-01-01
      • 2017-11-05
      相关资源
      最近更新 更多