简体   繁体   English

Angular 来自 Laravel 后端的 Formbuilder 验证

[英]Angular Formbuilder validation from Laravel Backend

I'm fairly new to Angular and I'm currently struggeling to display errors on my form fields that originate from my API backend.我是 Angular 的新手,目前我正在努力在我的表单字段上显示源自我的 API 后端的错误。 My frontend validation works without any problem.我的前端验证工作没有任何问题。

I've setup my frontend validation according to this link.我已经根据链接设置了前端验证。

This is my form HTML:这是我的表格 HTML:

<form [formGroup]="createDetailsForm" (ngSubmit)="onCreate()" autocomplete="off" *ngIf="!created_customer">
    <div class="modal-header">
        <h5 class="modal-title">
            {{'create_customer' | transloco | ucfirst}}
        </h5>
        <button type="button" class="close" (click)="d('Cross click')">&times;</button>
    </div>
    <div class="modal-body">
        <div class="form-row">
            <div class="form-group col">
                <label class="form-label">{{'name' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" formControlName="name">
                <app-control-messages [control]="createDetailsForm.get('name')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col mb-0">
                <label class="form-label">{{'vatnumber_prefix' | transloco | ucfirst}}</label>
                <app-countries controlName="vatnumber_prefix"></app-countries>
                <app-control-messages [control]="createDetailsForm.get('vatnumber_prefix')"></app-control-messages>
            </div>
            <div class="form-group col mb-0">
                <label class="form-label">{{'vatnumber' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="xxxxxxxxxx" formControlName="vatnumber"
                    pattern="[0-9]*">
                <app-control-messages [control]="createDetailsForm.get('vatnumber')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col mb-0">
                <label class="form-label">{{'street' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="" formControlName="street">
                <app-control-messages [control]="createDetailsForm.get('street')"></app-control-messages>
            </div>
            <div class="form-group col mb-0">
                <label class="form-label">{{'number' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="" formControlName="number">
                <app-control-messages [control]="createDetailsForm.get('number')"></app-control-messages>
            </div>
            <div class="form-group col mb-0">
                <label class="form-label">{{'suffix' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="" formControlName="suffix">
                <app-control-messages [control]="createDetailsForm.get('suffix')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col mb-0">
                <label class="form-label">{{'zipcode' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="" formControlName="zipcode">
                <app-control-messages [control]="createDetailsForm.get('zipcode')"></app-control-messages>
            </div>
            <div class="form-group col mb-0">
                <label class="form-label">{{'city' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" placeholder="" formControlName="city">
                <app-control-messages [control]="createDetailsForm.get('city')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col">
                <label class="form-label">{{'country' | transloco | ucfirst}}</label>
                <app-countries controlName="country"></app-countries>
                <app-control-messages [control]="createDetailsForm.get('country')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col">
                <label class="form-label">{{'email' | transloco | ucfirst}}</label>
                <input type="email" class="form-control" formControlName="email">
                <app-control-messages [control]="createDetailsForm.get('email')"></app-control-messages>
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col">
                <label class="form-label">{{'phone' | transloco | ucfirst}}</label>
                <input type="text" class="form-control" formControlName="phone">
                <app-control-messages [control]="createDetailsForm.get('phone')"></app-control-messages>
            </div>
        </div>

    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default"
            (click)="c('Close click')">{{'close' | transloco | ucfirst}}</button>
        <button type="submit" class="btn btn-primary">{{'save' | transloco | ucfirst}}</button>

    </div>
</form>

So the messages are displayed with the app-control-messages component.因此,消息与 app-control-messages 组件一起显示。 This is setup exactly like in the previous link.这与上一个链接中的设置完全相同。 his works with the default validators and a custom validation service.他使用默认验证器和自定义验证服务。 The formgroup is setup like this:表单组设置如下:

this.createDetailsForm = this.fb.group({
  name: ['', Validators.required],
  vatnumber_prefix: ['BE', Validators.required],
  vatnumber: ['', Validators.compose([Validators.required, ValidationService.numeric])],
  street: ['', Validators.required],
  number: ['', Validators.required],
  suffix: [''],
  zipcode: ['', Validators.required],
  city: ['', Validators.required],
  country: ['BE', Validators.required],
  email: ['', Validators.compose([Validators.required, ValidationService.emailValidator])],
  phone: ['', Validators.required],
  full_vatnumber: [],
});

Now the problem lies in the following.现在问题出在下面。 I've created a service which I can call from every error that comes from a http post to the backend.我创建了一个服务,我可以从 http 发布到后端的每个错误中调用该服务。 Here's an example of a httpclient error response:以下是 httpclient 错误响应的示例:

    this.subs.sink = this.custService.createCustomer(value).subscribe((res) => {
  this.custService.add(res);
},
  (error) => {
    this.serverValidation.validate(error, this.createDetailsForm);
  })

Here is the errorbag I'm receiving and sending to the validate function.这是我接收并发送到验证 function 的错误包。

The validate function:验证 function:

@Input() form: FormGroup;
@Input() error: HttpErrorResponse;
constructor(private notificationService: NotificationsService) {
}

validate(error, form) {
 if (error.status === 422) {
   form.markAsUntouched();
   form.markAsPristine();
   for (var e in error.error.errors) {
     let control = form.get(e);
     if (control) {
       control.markAsTouched();
       control.markAsDirty();
       control.setErrors({ 'test': true });
       control.updateValueAndValidity();
     } else {
       return undefined;
     }
   }

   form.updateValueAndValidity();
 }

 this.notificationService.error(error.statusText, error.error.message);
}

So I'm trying to set the content of the errorbag to the specific formcontrol but it isn't displaying the message.所以我试图将错误包的内容设置为特定的表单控件,但它没有显示消息。 Does someone know what I'm doing wrong?有人知道我做错了什么吗?

EDIT:编辑:

As suggested by Ausiàs Armesto I've put the code in the error function in the frontend component:正如 Ausiàs Armesto 所建议的,我将代码放在前端组件的错误 function 中:

(error) => {
    console.log(error);
    /* TODO Translate Backend validation errors  to form fields */
    this.createDetailsForm.markAsUntouched();
    this.createDetailsForm.markAsPristine();
    for (var e in error.error.errors) {
      let control = this.createDetailsForm.get(e);
      if (control) {
        control.markAsTouched();
        control.markAsDirty();
        for (var message in error.error.errors[e]) {
          control.setErrors({ 'error': { message: message } })
        }
      } else {
        return undefined;
      }
    }

and altered my validation service to show the message of the 'error' key.并更改了我的验证服务以显示“错误”键的消息。 Now the messages show.现在消息显示。 So my next question would be: How can i refactor this to a external service?所以我的下一个问题是:如何将其重构为外部服务?

SOLUTION解决方案

In the error callback I call my service:在错误回调中,我调用了我的服务:

      (error) => {
    this.serverValidation.validate(error, this.createDetailsForm);
  })

Validation Service:验证服务:

export class ServersideFormValidationService {
@Input() form: FormGroup;
@Input() error: HttpErrorResponse;
constructor(private notificationService: NotificationsService) {

}

  validate(error, form) {

    if (error.status === 422) {
      form.markAsUntouched();
      form.markAsPristine();
      for (var e in error.error.errors) {
        let control = form.get(e);
        if (control) {
          control.markAsTouched();
          control.markAsDirty();
          control.setErrors({ 'error': { message: error.error.errors[e][0] } })
        } else {
          return undefined;
        }
      }
    }

    this.notificationService.error(error.statusText, error.error.message);
    }
  }

I would try to debug the Form controls properties when they are in the frontend Component (when it is named ' createDetailsForm ') and when they are in the validate function (when it is named ' form ').当表单控件属性位于前端组件(名为“ createDetailsForm ”时)以及位于验证 function 中(名为“ form ”时)时,我会尝试调试它们。 Without testing throughtly it seems that the form object is duplicated and then the changes made in the validate function are not propagated to the form defined in the visual component.如果不进行彻底测试,表单 object 似乎是重复的,然后在验证function 中所做的更改不会传播到可视组件中定义的表单。 I would also try to change the signature of the validate function so it returns the incorrect fields, something like that:我还会尝试更改验证function 的签名,以便它返回不正确的字段,如下所示:

return ['field1', 'field2']

And in the error handler try to update the original form control:并在错误处理程序中尝试更新原始表单控件:

(error) => {
    this.serverValidation.validate(error, this.createDetailsForm).forEach(errorControl => {
    this.createDetailsForm.get(errorControl).setErrors = ({ 'test': true })
    })
  }

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

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