نمایش خطاهای اعتبارسنجی سمت سرور ASP.NET Core در برنامههای Angular
نویسنده: وحید نصیری
تاریخ: ۱۳۹۶/۰۸/۲۹ ۱۰:۴۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
using System;
using System.ComponentModel.DataAnnotations;
namespace AngularTemplateDrivenFormsLab.Models
{
public class Movie
{
public int Id { get; set; }
[Required(ErrorMessage = "Movie Title is Required")]
[MinLength(3, ErrorMessage = "Movie Title must be at least 3 characters")]
public string Title { get; set; }
[Required(ErrorMessage = "Movie Director is Required.")]
public string Director { get; set; }
[Range(0, 100, ErrorMessage = "Ticket price must be between 0 and 100.")]
public decimal TicketPrice { get; set; }
[Required(ErrorMessage = "Movie Release Date is required")]
public DateTime ReleaseDate { get; set; }
}
} using AngularTemplateDrivenFormsLab.Models;
using Microsoft.AspNetCore.Mvc;
namespace AngularTemplateDrivenFormsLab.Controllers
{
[Route("api/[controller]")]
public class MoviesController : Controller
{
[HttpPost]
public IActionResult Post([FromBody]Movie movie)
{
if (ModelState.IsValid)
{
// TODO: save ...
return Ok(movie);
}
ModelState.AddModelError("", "This record already exists."); // a cross field validation
return BadRequest(ModelState);
}
}
} {"":["This record already exists."],"TicketPrice":["Ticket price must be between 0 and 100."]}
errors: string[] = [];
processModelStateErrors(form: NgForm, responseError: HttpErrorResponse) {
if (responseError.status === 400) {
const modelStateErrors = responseError.error;
for (const fieldName in modelStateErrors) {
if (modelStateErrors.hasOwnProperty(fieldName)) {
const modelStateError = modelStateErrors[fieldName];
const control = form.controls[fieldName] || form.controls[this.lowerCaseFirstLetter(fieldName)];
if (control) {
// integrate into Angular's validation
control.setErrors({
modelStateError: { error: modelStateError }
});
} else {
// for cross field validations -> show the validation error at the top of the screen
this.errors.push(modelStateError);
}
}
}
} else {
this.errors.push("something went wrong!");
}
}
lowerCaseFirstLetter(data: string): string {
return data.charAt(0).toLowerCase() + data.slice(1);
} const control = form.controls[fieldName] || form.controls[this.lowerCaseFirstLetter(fieldName)];
model = new Movie("", "", 0, "");
successfulSave: boolean;
errors: string[] = [];
constructor(private movieService: MovieService) { }
ngOnInit() {
}
submitForm(form: NgForm) {
console.log(form);
this.errors = [];
this.movieService.postMovieForm(this.model).subscribe(
(data: Movie) => {
console.log("Saved data", data);
this.successfulSave = true;
},
(responseError: HttpErrorResponse) => {
this.successfulSave = false;
console.log("Response Error", responseError);
this.processModelStateErrors(form, responseError);
});
} <form #form="ngForm" (submit)="submitForm(form)" novalidate>
<div class="alert alert-danger" role="alert" *ngIf="errors.length > 0">
<ul>
<li *ngFor="let error of errors">
{{ error }}
</li>
</ul>
</div>
<div class="alert alert-success" role="alert" *ngIf="successfulSave">
Movie saved successfully!
</div>
control.setErrors({
modelStateError: { error: modelStateError }
});
<ng-template #validationErrorsTemplate let-ctrl="control">
<div *ngIf="ctrl.invalid && ctrl.touched">
<div class="alert alert-danger" *ngIf="ctrl.errors.required">
This field is required.
</div>
<div class="alert alert-danger" *ngIf="ctrl.errors.minlength">
This field should be minimum {{ctrl.errors.minlength.requiredLength}} characters.
</div>
<div class="alert alert-danger" *ngIf="ctrl.errors.maxlength">
This field should be max {{ctrl.errors.maxlength.requiredLength}} characters.
</div>
<div class="alert alert-danger" *ngIf="ctrl.errors.pattern">
This field's pattern: {{ctrl.errors.pattern.requiredPattern}}
</div>
<div class="alert alert-danger" *ngIf="ctrl.errors.modelStateError">
{{ctrl.errors.modelStateError.error}}
</div>
</div>
</ng-template> <div class="form-group" [class.has-error]="releaseDate.invalid && releaseDate.touched">
<label class="control-label" for="releaseDate">Release Date</label>
<input type="text" name="releaseDate" #releaseDate="ngModel" class="form-control"
required [(ngModel)]="model.releaseDate" />
<ng-container *ngTemplateOutlet="validationErrorsTemplate; context:{ control: releaseDate }"></ng-container>
</div> import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl } from '@angular/forms';
@Component({
selector: 'validation-message',
template: `
<ng-container *ngIf="control.invalid && control.touched">
{{ message }}
</ng-container>
`
})
export class ValidationMessageComponent implements OnInit {
@Input() control: AbstractControl;
@Input() fieldDisplayName: string;
@Input() rules: { [key: string]: string };
get message(): string {
return this.control.hasError('required')
? `${this.fieldDisplayName} را وارد نمائید.`
: this.control.hasError('pattern')
? `${this.fieldDisplayName} را به شکل صحیح وارد نمائید.`
: this.control.hasError('email')
? `${this.fieldDisplayName} را به شکل صحیح وارد نمائید.`
: this.control.hasError('minlength')
? `${this.fieldDisplayName} باید بیشتر از ${
this.control.errors.minlength.requiredLength
} کاراکتر باشد.`
: this.control.hasError('maxlength')
? `${this.fieldDisplayName} باید کمتر از ${
this.control.errors.maxlength.requiredLength
} کاراکتر باشد.`
: this.control.hasError('min')
? `${this.fieldDisplayName} باید بیشتر از ${
this.control.errors.min.requiredLength
} باشد.`
: this.control.hasError('max')
? `${this.fieldDisplayName} باید کمتر از ${
this.control.errors.max.requiredLength
} باشد.`
: this.hasRule()
? this.findRule()
: this.control.hasError('model')
? `${this.control.errors.model.messages[0]}`
: '';
}
constructor() {}
private hasRule() {
return (
this.rules &&
Object.keys(this.control.errors).some(ruleKey =>
this.rules[ruleKey] ? true : false
)
);
}
private findRule(): string {
let message = '';
Object.keys(this.control.errors).forEach(ruleKey => {
if (this.rules[ruleKey]) {
message += `${this.rules[ruleKey]} `;
}
});
return message;
}
ngOnInit(): void {}
} <mat-error *ngIf="form.controls['userName'].invalid && form.controls['userName'].touched"
class="mat-text-warn">
<validation-message
[control]="form.controls['userName']"
fieldDisplayName="نام کاربری"
[rules]="{rule1:'پیغام متناظر با rule1'}">
</validation-message>
</mat-error> this.form = this.formBuilder.group({
userName: [
'',
[Validators.required, UserNameValidators.rule1)]
],
password: ['', Validators.required],
rememberMe: [false]
});
export class UserNameValidators{
static rule1(control: AbstractControl) {
if (control.value.indexOf(' ') >= 0) {
return { rule1: true };
}
return null;
}
} {
'detail[0].title':['message'],
'detail[0].detail[0].title':['message']
} private findFieldControl(fieldName: string): AbstractControl {
const path = fieldName.replace('[', '.').replace(']', '');
return (
this.form.get(path) || this.form.get(this.lowerCaseFirstLetter(path))
);
} 'detail.0.title' 'detail.0.detail.0.title'
protected handleSubmitError(response: HttpErrorResponse) {
this.messages = [];
if (response.status === 400) {
// handle validation errors
const validationDictionary = response.error;
for (const fieldName in validationDictionary) {
if (validationDictionary.hasOwnProperty(fieldName)) {
const messages = validationDictionary[fieldName];
const control = this.findFieldControl(fieldName);
if (control) {
// integrate into angular's validation if we have field validation
control.setErrors({
model: { messages: messages }
});
} else {
// if we have cross field validation, then show the validation error at the top of the screen
this.messages.push(...messages);
}
}
}
} else {
this.messages.push('something went wrong!');
}
}