0

Form Validation trong ứng dụng NativeScript Angular

Ở bài viết trước, tôi đã tạo một ứng dụng demo để giới thiệu về NativeScript. Trong bài này, chúng ta sẽ đi sâu vào cách xây dựng ứng dụng NativeScript, cụ thể là sử dụng Angular để xác thực dữ liệu phía client. Mặc dù NativeScript có hỗ trợ Angular, sẽ có một số khác biệt nhỏ giữa cách triển khai ứng dụng trên web với trên mobile bởi vì NativeScript sử dụng các tùy chỉnh XML so với tiêu chuẩn HTML trên web.

Tải về source code đầy đủ tại đây .

Tạo project NativeScript với Angular

Mục đích của hướng dẫn là xác minh tính hợp lệ của dữ liệu đầu vào trên form input require như ví dụ dưới đây:

Mặc định là bạn đã cài đặt NativeScript CLI và cấu hình đầy đủ. Trên CLI, chạy lệnh sau: tns create ns-validation-project --ng Flag --ng xác định xây dựng một ứng dụng Angular chứ không phải ứng dụng NativeScript thuần.

Cần dọn dẹp một chút trước khi tiếp tục vì ứng dụng NativeScript Angular mẫu tạo ra nhiều thứ không cần thiết.

Mở app/app.routing.ts và xóa mảng routes . Ứng dụng trang đơn của chúng ta không cần định tuyến nào. Tệp sau khi dọn dẹp giống thế này:

import { NgModule } from "@angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { Routes } from "@angular/router";

const routes: Routes = [];

@NgModule({
    imports: [NativeScriptRouterModule.forRoot(routes)],
    exports: [NativeScriptRouterModule]
})
export class AppRoutingModule { }

Các componentservice cũng cần bỏ khỏi app/app.module.ts:

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        NativeScriptModule,
        AppRoutingModule,
        NativeScriptFormsModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [],
    schemas: [
        NO_ERRORS_SCHEMA
    ]
})
export class AppModule { }

Bắt đầu được rồi, mặc dù không nhất thiết phải sửa đổi những file trên, nhưng tôi thích sự gọn gàng và để tránh nhầm lẫn.

Sử dụng Angular Validators

Angular, giống như AngularJS, có một bộ các validator. Những validator này dùng được trong cả web và NativeScript.

Ví dụ với field email. Field này có các trạng thái dirty, pristine, touched, validinvalid. Trạng thái là dirty khi đã được sử dụng và ngược lại là pristine nếu chưa được sử dụng, touched khi trường bị blur. Nếu thỏa mãn tất cả các quy tắc, trạng thái là valid và ngược lại là invalid.

Mở app/app.component.html thêm vào HTML sau:

<ActionBar title="{N} Form Validation"></ActionBar>
<StackLayout class="form">
    <StackLayout class="input-field">
        <Label text="Email" class="label font-weight-bold m-b-5"></Label>
        <TextField #email="ngModel" [(ngModel)]="input.email" class="input" required></TextField>
        <StackLayout class="hr-light"></StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <Label text="Password" class="label font-weight-bold m-b-5"></Label>
        <TextField #password="ngModel" secure="true" [(ngModel)]="input.password" class="input" required></TextField>
        <StackLayout class="hr-light"></StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <StackLayout *ngIf="email.errors && (email.dirty || email.touched)">
            <Label *ngIf="email.errors.required" text="- An email is required -"></Label>
        </StackLayout>
        <StackLayout *ngIf="password.errors && (password.dirty || password.touched)">
            <Label *ngIf="password.errors.required" text="- A password is required -"></Label>
        </StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <Button *ngIf="email.valid && password.valid" text="Login" class="btn btn-primary"></Button>
    </StackLayout>
</StackLayout>

Giao diện gồm hai field (email, password) và một button (login). Các field là bắt buộc nhập (require). Nếu field đã được sử dụng hoặc bị mờ, sẽ hiển thị lỗi và ẩn nút login. Nếu validate ok, hiện nút và không hiển thị lỗi. Điều này được thực hiện thông qua ngModel trên mỗi TextField. Ví dụ #email="ngModel"#password="ngModel". Để các biến này hoạt động, phải có một ràng buộc hai chiều sử dụng thuộc tính [(ngModel)].

Xây dựng Directive xác thực

Nhiều khi những validator cơ bản không đáp ứng được yêu cầu của bạn, ví dụ khi bạn muốn đặt độ dài tối thiểu cho TextField, khi đó cần phải tự xây dựng một validator riêng. Ngoài ra bạn có thể thêm bất cứ luật nào mà bạn nghĩ ra 😄

Tạo file app/input.directive.ts giống như sau:

import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';

@Directive({
    selector: '[minlength]',
    providers: [{provide: NG_VALIDATORS, useExisting: MinLengthDirective, multi: true}]
})
export class MinLengthDirective implements Validator {

    @Input() minlength: string;

    public constructor() {}

    public validate(control: AbstractControl): {[key: string]: any} {
        return !control.value || control.value.length >= this.minlength ? null : { "minlength": true };
    }

}

@Directive({
    selector: '[email]',
    providers: [{provide: NG_VALIDATORS, useExisting: IsEmailDirective, multi: true}]
})
export class IsEmailDirective implements Validator {

    public constructor() {}

    public validate(control: AbstractControl): {[key: string]: any} {
        let emailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i;
        let valid = emailRegEx.test(control.value);
        return control.value < 1 || valid ? null : {'email': true};
    }

}

Bắt đầu với MinLengthDirective:

@Directive({
    selector: '[minlength]',
    providers: [{provide: NG_VALIDATORS, useExisting: MinLengthDirective, multi: true}]
})
export class MinLengthDirective implements Validator {

    @Input() minlength: string;

    public constructor() {}

    public validate(control: AbstractControl): {[key: string]: any} {
        return !control.value || control.value.length >= this.minlength ? null : { "minlength": true };
    }

}

Bằng cách thêm một @Input() trùng tên, nếu một giá trị trên form dài hơn chiều dài được xác định sẽ trả về null. Giá trị null chỉ ra rằng nội dung là hợp lệ. Nếu không, sẽ trả ra bất kì đối tượng nào và xử lý nó.

Điều này đưa chúng ta đến IsEmailDirective, dùng xác nhận biểu thức chính quy:

@Directive({
    selector: '[email]',
    providers: [{provide: NG_VALIDATORS, useExisting: IsEmailDirective, multi: true}]
})
export class IsEmailDirective implements Validator {

    public constructor() {}

    public validate(control: AbstractControl): {[key: string]: any} {
        let emailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i;
        let valid = emailRegEx.test(control.value);
        return control.value < 1 || valid ? null : {'email': true};
    }

}

Sử dụng Email RegEx để kiểm tra xem giá trị đầu vào có hợp lệ hay không.

Trước khi sử dụng, cần thêm các Directive này vào @NgModule. Mở app/app.module.ts thêm các Directive và các mảng declarations:

import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { NativeScriptModule } from "nativescript-angular/nativescript.module";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { AppRoutingModule } from "./app.routing";
import { AppComponent } from "./app.component";

import { MinLengthDirective, IsEmailDirective } from "./input.directive";

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        NativeScriptModule,
        AppRoutingModule,
        NativeScriptFormsModule
    ],
    declarations: [
        AppComponent,
        MinLengthDirective,
        IsEmailDirective
    ],
    providers: [],
    schemas: [
        NO_ERRORS_SCHEMA
    ]
})
export class AppModule { }

Vậy là đủ. Sửa app/app.component.html như sau:

<ActionBar title="{N} Form Validation"></ActionBar>
<StackLayout class="form">
    <StackLayout class="input-field">
        <Label text="Email" class="label font-weight-bold m-b-5"></Label>
        <TextField #email="ngModel" [(ngModel)]="input.email" class="input" required email></TextField>
        <StackLayout class="hr-light"></StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <Label text="Password" class="label font-weight-bold m-b-5"></Label>
        <TextField #password="ngModel" secure="true" minlength="5" [(ngModel)]="input.password" class="input" required></TextField>
        <StackLayout class="hr-light"></StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <StackLayout *ngIf="email.errors && (email.dirty || email.touched)">
            <Label *ngIf="email.errors.required" text="- An email is required -"></Label>
            <Label *ngIf="email.errors.email" text="- Email must be valid -"></Label>
        </StackLayout>
        <StackLayout *ngIf="password.errors && (password.dirty || password.touched)">
            <Label *ngIf="password.errors.required" text="- A password is required -"></Label>
            <Label *ngIf="password.errors.minlength" text="- Password must be longer than 5 characters"></Label>
        </StackLayout>
    </StackLayout>
    <StackLayout class="input-field">
        <Button *ngIf="email.valid && password.valid" text="Login" class="btn btn-primary"></Button>
    </StackLayout>
</StackLayout>

Có những thay đổi nào? Trong TextField cho email, thêm một thuộc tính email. Tương ứng với Directive đã định nghĩa. Nó không có giá trị vì chỉ muốn xác nhận dữ liệu thường. Trong khối lỗi, cũng chỉ kiểm tra các lỗi xác nhận hợp lệ liên quan đến email. Trong TextField cho password, thêm thuộc tính minlength chứa một giá trị số. Hãy nhớ rằng, giá trị đó là những gì chúng ta đang kiểm tra bên trong Directive. Tôi cũng thêm in lỗi cho Directive này.

Kết luận

Bạn đã biết cách để thêm form validate cho một ứng dụng NativeScript Angular chưa?. Đơn giản nó là những gì đã có sẵn trong Angular thông qua Angular Directive. Validating form giúp trải nghiệm người dùng thêm tinh tế. Tuy nhiên, không nên dùng nó thay cho việc xác thực phía Backend.

Nguồn: developer.telerik.com


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí