اعتبارسنجی از راه دور در فرمهای مبتنی بر قالبهای Angular
نویسنده: وحید نصیری
تاریخ: ۱۳۹۶/۰۴/۲۰ ۱۳:۱۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
data-val-remote="کلمه عبور وارد شده را راحت می‌توان حدس زد!" data-val-remote-additionalfields="*.Password1" data-val-remote-type="POST" data-val-remote-url="/register/checkpassword"
export class EmailValidatorDirective implements Validator { export class RemoteValidatorDirective implements AsyncValidator { validate(c: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null>;
>ng g d CustomValidators/RemoteValidator -m custom-validators.module
import { Directive, Input } from "@angular/core";
import {
AsyncValidator,
AbstractControl,
NG_ASYNC_VALIDATORS
} from "@angular/forms";
import { Http, RequestOptions, Response, Headers } from "@angular/http";
import "rxjs/add/operator/map";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/takeUntil";
import "rxjs/add/operator/take";
import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
@Directive({
selector:
"[appRemoteValidator][formControlName],[appRemoteValidator][formControl],[appRemoteValidator][ngModel]",
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: RemoteValidatorDirective,
multi: true
}
]
})
export class RemoteValidatorDirective implements AsyncValidator {
@Input("remote-url") remoteUrl: string;
@Input("remote-field") remoteField: string;
@Input("remote-additional-fields") remoteAdditionalFields: string;
constructor(private http: Http) {}
validate(control: AbstractControl): Observable<{ [key: string]: any }> {
if (!this.remoteUrl || this.remoteUrl === undefined) {
return Observable.throw("`remoteUrl` is undefined.");
}
if (!this.remoteField || this.remoteField === undefined) {
return Observable.throw("`remoteField` is undefined.");
}
const dataObject = {};
if (
this.remoteAdditionalFields &&
this.remoteAdditionalFields !== undefined
) {
const otherFields = this.remoteAdditionalFields.split(",");
otherFields.forEach(field => {
const name = field.trim();
const otherControl = control.root.get(name);
if (otherControl) {
dataObject[name] = otherControl.value;
}
});
}
// This is used to signal the streams to terminate.
const changed$ = new Subject<any>();
changed$.next(); // This will signal the previous stream (if any) to terminate.
const debounceTime = 400;
return new Observable((obs: any) => {
control.valueChanges
.takeUntil(changed$)
.take(1)
.debounceTime(debounceTime)
.distinctUntilChanged()
.flatMap(term => {
dataObject[this.remoteField] = term;
return this.doRemoteValidation(dataObject);
})
.subscribe(
(result: IRemoteValidationResult) => {
if (result.result) {
obs.next(null);
} else {
obs.next({
remoteValidation: {
remoteValidationMessage: result.message
}
});
}
obs.complete();
},
error => {
obs.next(null);
obs.complete();
}
);
});
}
private doRemoteValidation(data: any): Observable<IRemoteValidationResult> {
const headers = new Headers({ "Content-Type": "application/json" }); // for ASP.NET MVC
const options = new RequestOptions({ headers: headers });
return this.http
.post(this.remoteUrl, JSON.stringify(data), options)
.map(this.extractData)
.do(result => console.log("remoteValidation result: ", result))
.catch(this.handleError);
}
private extractData(res: Response): IRemoteValidationResult {
const body = <IRemoteValidationResult>res.json();
return body || (<IRemoteValidationResult>{});
}
private handleError(error: Response): Observable<any> {
console.error("observable error: ", error);
return Observable.throw(error.statusText);
}
}
export interface IRemoteValidationResult {
result: boolean;
message: string;
} @Directive({
selector:
"[appRemoteValidator][formControlName],[appRemoteValidator][formControl],[appRemoteValidator][ngModel]",
providers: [
{
provide: NG_ASYNC_VALIDATORS,
useExisting: RemoteValidatorDirective,
multi: true
}
]
}) export class RemoteValidatorDirective implements AsyncValidator {
@Input("remote-url") remoteUrl: string;
@Input("remote-field") remoteField: string;
@Input("remote-additional-fields") remoteAdditionalFields: string; <input #username="ngModel" required maxlength="8" minlength="4" type="text"
appRemoteValidator [remote-url]="remoteUsernameValidationUrl" remote-field="FirstName"
remote-additional-fields="email,password" class="form-control" name="username"
[(ngModel)]="model.username"> export class UserRegisterComponent implements OnInit {
remoteUsernameValidationUrl = "api/Employee/CheckUser"; [remote-field]="'FirstName'"
export interface IRemoteValidationResult {
result: boolean;
message: string;
} namespace AngularTemplateDrivenFormsLab.Controllers
{
[Route("api/[controller]")]
public class EmployeeController : Controller
{
[HttpPost("[action]")]
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult CheckUser([FromBody] Employee model)
{
var remoteValidationResult = new { result = true, message = $"{model.FirstName} is fine!" };
if (model.FirstName?.Equals("Vahid", StringComparison.OrdinalIgnoreCase) ?? false)
{
remoteValidationResult = new { result = false, message = "username:`Vahid` is already taken." };
}
return Json(remoteValidationResult);
}
}
} <div class="form-group" [class.has-error]="username.invalid && username.touched">
<label class="control-label">User Name</label>
<input #username="ngModel" required maxlength="8" minlength="4" type="text"
appRemoteValidator [remote-url]="remoteUsernameValidationUrl" remote-field="FirstName"
remote-additional-fields="email,password" class="form-control" name="username"
[(ngModel)]="model.username">
<div *ngIf="username.pending" class="alert alert-warning">
Checking server, Please wait ...
</div>
<div *ngIf="username.invalid && username.touched">
<div class="alert alert-danger" *ngIf="username.errors.remoteValidation">
{{username.errors.remoteValidation.remoteValidationMessage}}
</div>
</div>
</div>
obs.next({
remoteValidation: {
remoteValidationMessage: result.message
}
});
// This is used to signal the streams to terminate.
const changed$ = new Subject<any>();
changed$.next(); // This will signal the previous stream (if any) to terminate.
const debounceTime = 400;
return new Observable((obs: any) => {
control.valueChanges
.takeUntil(changed$)
.take(1)
.debounceTime(debounceTime)
.distinctUntilChanged()