简体   繁体   English

Angular:用于呈现服务器端验证消息的正确方法

[英]Angular: Correct approach for rendering server side validation messages

Let's say I have this form in Angular: 假设我在Angular中有这个表单:

<form [formGroup]="form">
    <md-input-container>
        <input mdInput formControlName="name" [(ngModel)]="dummy.name" name="name">
        <md-error *ngIf="form.controls.name.hasError('required')">This is required</md-error>
    </md-input-container>
    <md-input-container>
        <input mdInput formControlName="email" [(ngModel)]="dummy.email" name="email">
        <md-error *ngIf="form.controls.email.hasError('invalid_format')">The email is not valid</md-error>
    </md-input-container>
</form>

Which is submitted to a web service for saving, updating, etc. The web service of course has to check that the inputs are correct and return some validation messages in case there is any problem. 提交给Web服务进行保存,更新等。当然,Web服务必须检查输入是否正确,并在出现任何问题时返回一些验证消息。 Let's say I POST the form and get these validation errors in a JSON dictionary: 假设我在表单中发布并在JSON字典中获取这些验证错误:

{
    "name": [
        "Middle names are not allowed."
    ],
    "email": [
        "The email already exists."
    ]
}

It's unclear to me how angular should process this situation. 我不清楚角度应如何处理这种情况。 Most of the information around suggest to write a custom validator that would do a asynchronous validation against the server, for example: 大多数信息建议编写一个自定义验证器,对服务器进行异步验证,例如:

uniqueEmailValidator(control: Control): {[key: string]: any} {
    return new Promise (resolve => {
        let headers = new Headers();
        headers.append('Content-Type', 'application/json');
        this.http.get('http://webservice.com/email/unique/', {headers:headers})
            .map(res => res.json())
            .subscribe(data => {
                if(data != null) {
                    resolve({"duplicate": true})
                }
                else resolve(null);      
            })
        });
    });
}

Now, this means that I should have a specific web service for every single piece of data that might exist in my form. 现在,这意味着我应该为表单中可能存在的每一条数据提供特定的Web服务。 While this might make sense in some specific cases (like unique email/username validation), I don't like the idea of filling my web API with lots of services that will only do validation tasks, plus then having to write the validators in my angular project. 虽然这在某些特定情况下可能有意义(例如唯一的电子邮件/用户名验证),但我不喜欢用大量服务来填充我的Web API,这些服务只会执行验证任务,而且必须在我的网站上编写验证器。角度项目。

A possible solution I figured out, is to save the server error object in my component as an attribute, then have an Angular validator to check wether a specific field has an error message: 我想到的一个可能的解决方案是将服务器错误对象保存在我的组件中作为属性,然后使用Angular验证器来检查特定字段是否有错误消息:

public checkServerErrorMessage(control: FormControl):{[key: string]: boolean}{
    if("name" in this.serverErrors){
        return { serverValidationError: true };
    }
    return {};
}

Then force the validators to refresh using updateValueAndValidity or some sort of thing. 然后使用updateValueAndValidity或某种东西强制验证器刷新。 But I don't feel this right. 但我觉得这不对。 Is there an "angularish" approach to resolve this situation? 是否有一种“棱角分明”的方法来解决这种情况?

Since I have been getting some upvotes, and just in case anyone is struggling through this, here is the solution I made up. 因为我已经获得了一些赞成,并且万一有人正在努力解决这个问题,这就是我编写的解决方案。

Instead of using validators, I ended up using the setError method to trigger validation errors manually on controls (which in my understanding, is basically what a validator would do). 我没有使用验证器,而是最终使用setError方法在控件上手动触发验证错误(在我的理解中,基本上是验证器会做什么)。

So, in my component, I will iterate over the server's response to determine if there is an error on each field. 因此,在我的组件中,我将迭代服务器的响应以确定每个字段是否存在错误。 I guess you can determine this in many ways and it depends on how your web service was designed. 我猜您可以通过多种方式确定这一点,具体取决于您的Web服务的设计方式。 In my case, there is an error if the name of the control is present in the dictionary of errors returned by the server. 在我的情况下,如果控件的名称存在于服务器返回的错误字典中,则会出错。 If so, i flag the matching form control as a 'serverValidationError' (or however you want to call it): 如果是这样,我将匹配的表单控件标记为'serverValidationError'(或者你想要调用它):

for(var key in serverResponse["errors"]) { 

    this.serverErrors[key] = serverResponse["errors"][key]
    this.form.controls[key].setErrors({serverValidationError: true});

}

"serverErrors" will store the messages from the server to display them on the template. “serverErrors”将存储来自服务器的消息,以在模板上显示它们。

Then in the template, i check for that error: 然后在模板中,我检查该错误:

<form [formGroup]="form">
    <md-input-container>
        <input mdInput formControlName="name" [(ngModel)]="dummy.name" name="name">
        <md-error *ngIf="form.controls.name.hasError('serverValidationError')">{{ serverErrors["name"] }}</md-error>
    </md-input-container>
    <md-input-container>
        <input mdInput formControlName="email" [(ngModel)]="dummy.email" name="email">
        <md-error *ngIf="form.controls.email.hasError('serverValidationError')">{{ serverErrors["email"] }}</md-error>
    </md-input-container>
</form>

Don't know if this is the best solution, but at least is the best I could think of. 不知道这是否是最好的解决方案,但至少是我能想到的最好的解决方案。

PS: I'm writing all this from memory, so the code is probably not 100% correct. PS:我是从内存中写的所有这些,所以代码可能不是100%正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM