【问题标题】:Cannot read property '...' of null - Angular 2无法读取 null 的属性“...” - Angular 2
【发布时间】:2018-09-02 00:16:02
【问题描述】:

我正在尝试制作一个自定义异步验证器,用于检查所提供的电子邮件是否已存在于数据库中。当出现错误时它可以正常工作,但是当错误解决时(输入有效数据)它显示Cannot read property 'emailIsTaken' of null

我正在使用模板驱动方法。这是我的使用方法。

<input type="email" name="email" [(ngModel)]='email' #mail='ngModel' required [pattern]='emailPattern' validateEmail>

使用错误代码

<div *ngIf='mail.errors["emailIsTaken"]'>Email already Registered!</div>

这是我的验证器文件

import { Validator, AbstractControl, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { Directive, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
@Directive({
    selector: '[validateEmail]',
    providers: [{
        provide: NG_ASYNC_VALIDATORS,
        useExisting: EmailValidator,
        multi: true
    }]
})

@Injectable()
export class EmailValidator implements Validator {
    constructor(private http: HttpClient){}
    validate(control: AbstractControl): Promise<any> | Observable<any> {
        return new Promise(resolve => {
            this.http.get('http://surjit.com/email.php?q=' + control.value).subscribe((success)=>{
            if(success === true){
                    resolve(null);
                }
                else{
                    resolve({'emailIsTaken': true});
                }
            });
        });
    }
}

当我使用内置的email验证器时也会出现同样的错误

ScreenShot

【问题讨论】:

  • 你真的不应该发布错误文本的截图,将文本复制/粘贴到你的问题中更容易更好。也就是说,向我们展示错误源自的SignupComponent.html 的代码。

标签: angular


【解决方案1】:

这是你的问题:

if(success === true){
     resolve(null);
}

如果验证成功,则返回 null 而不是带有字段“emailIsTaken”的对象。

怎么样

if(success === true){
    resolve({'emailIsTaken': false});
}

这是否适合您的代码?

【讨论】:

  • 我相信这个语法,我们应该返回 null 以防测试成功
  • @user9416413 我认为你不对。您想验证电子邮件是否免费,最好的做法是返回相同类型的数据。您应该在两种情况下都返回emailIsTake,一种为假,另一种为真,具体取决于它是否被采用。正是@DiabolicWords 建议的方式。这样你就不会遇到你写的错误了。
  • 我根据你的建议试过了,但这并不能解决我的问题。它仍然打印相同的错误
  • stackoverflow.com/questions/35521583/…这里他用null表示测试成功
【解决方案2】:

如果你想执行这个异步,那么你需要实现AsyncValidator

您还需要从 observable 返回结果而不是订阅它。这里最简单的做法是使用 Observable 而不是 Promise,但您也可以在 .map() 之后链接 .toPromise()。你不想在这里订阅你想返回可观察对象本身(或承诺),但你确实希望承诺返回预期结果,这就是为什么你应该使用map

附带说明,如果您还没有这样做,我建议您切换到使用 pipable 操作符。另见In Angular rxjs when should I use pipe vs map

import { AsyncValidator } from '@angular/forms';
import { map } from 'rxjs/operators/map';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class EmailValidator implements AsyncValidator {
    constructor(private http: HttpClient){}

    validate(control: AbstractControl): Promise<any> | Observable<any> {
        return this.http.get('http://surjit.com/email.php?q=' + control.value)
                .pipe(map((success)=> success ? null : {'emailIsTaken': true}));
        }
}

以上只是修改后的EmailValidator类。


查看我基于上述创建的StackBlitz


编辑

根据您的错误屏幕截图,最可能的原因是您在 HTML 中检查了应该根据结果验证显示哪个错误,这没有考虑到验证结果为 null 的事实(如果有)没有错误。最简单的解决方法是使用safe navigation operator ( ?. ) and null property paths?。示例:

<element *ngIf="errResult?.emailIsTaken">Email is in use</element>

【讨论】:

  • @user9416413 - 你需要实现AsyncValidator,而不是Validator。这与我之前所说的使用 map 一样。
  • @user9416413 - 我的上述解决方案有效。如果您遇到错误,则它在您未显示的代码中。看到这个stackblitz
  • @user9416413 - 您让我们猜测是因为您没有发布 HTML,但最可能的原因是尝试访问错误结果但没有考虑到它为空。请参阅上面我的最新编辑。
  • @user9416413 - 如果这解决了您的问题,请考虑使用答案左侧的复选标记来标记答案。
  • 对不起,我的问题仍然没有解决。我正在使用&lt;div *ngIf='mail.errors["emailIsTaken"]'&gt;Email already Registered!&lt;/div&gt; 之类的错误代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 2017-07-16
  • 1970-01-01
相关资源
最近更新 更多