Angular – Theo dõi trạng thái form với ngModel


Được đăng vào ngày 17/03/2017 | 0 bình luận
Angular – Theo dõi trạng thái form với ngModel
1 (20%) 20 votes

Trong bài trước chúng ta đã tìm hiểu qua cách liên kết dữ liệu hai chiều với ngModel, ngModel không những thực hiện chức năng đó mà còn có khả năng kiểm tra trạng thái của các phần tử control trong form, chẳng hạn như nội dung textbox thay đổi, người dùng click vào…v.v

Mỗi khi có sự thay đổi trên các phần tử trong form, ngModel sẽ đổi tên class của các phần tử đó, cụ thể:

Trạng thái

TRẠNG THÁI TÊN CLASS (TRUE) TÊN CLASS (FALSE)
Người dùng click vào control ng-touched ng-untouched
Người dùng thay đổi dữ liệu của control ng-dirty ng-pristine
Dữ liệu của control không hợp lệ ng-valid ng-invalid

Chúng ta có thể lấy tên các lớp này thông qua biến trong template.

Bây giờ chúng ta sẽ dùng form customer đã làm trong bài trước để ví dụ, sửa lại file customer-form.component.html như sau:

<div class="container">
    <h1>Customer</h1>
    <form>
        <div class="form-group">
            <label for="name">Name</label>
            <input type="text" 
                class="form-control"  
                id="name" 
                [(ngModel)]="customer1.name" 
                name="cus1_name" 
                required 
                #cus_class>           
                <p>Classes: {{cus_class.className}}</p>
        </div>
    ....     
    </form>
</div>

Chúng ta khai báo biến template cho thẻ <input> là #cus_class, sau đó lấy thuộc tính className của biến này ra và hiển thị.

Lưu file lại, Angular sẽ reload lại trình duyệt, chúng ta có thể thấy tên các lớp của control này, ngay cả các control khác cũng thế, nếu muốn rõ hơn bạn có thể dùng chức năng insect của Google Chrome để xem.

Bạn thử click vào một ô textbox, sau đó click ra ngoài, gõ thêm kí tự vào ô, xóa nội dung trong ô đó… thì sẽ thấy tên các class này thay đổi tùy theo từng trạng thái.

Chúng ta có thể dùng các lớp này để thay đổi màu sắc, hiển thị text để thông báo cho người dùng, ví dụ chúng ta tạo file CSS có tên customer-form.css trong thư mục src như sau:

.ng-valid:required, .ng-valid.required {
    border-left: 5px solid #42A948;
}

.ng-invalid:not(form) {
    border-left: 5px solid #a94442;
}

Ở đây chúng ta thay đổi màu sắc viền bên trái (border-left) cho 2 lớp ng-invalidng-valid. Khi người dùng xóa trống ô textbox có yêu cầu required thì viền trái sẽ chuyển thành màu đỏ.

Tiếp theo chúng ta phải thêm dòng code <link> tới file này trong file index.html:

<!DOCTYPE html>
<html>
    <head>
    <title>Angular QuickStart</title>
        <base href="/">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="styles.css">
        <link rel="stylesheet" href="customer-form.css">
 
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> 
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"> 
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
 
        <!-- Polyfill(s) for older browsers -->
        <script src="node_modules/core-js/client/shim.min.js"></script> 

        <script src="node_modules/zone.js/dist/zone.js"></script> 
        <script src="node_modules/systemjs/dist/system.src.js"></script> 

        <script src="systemjs.config.js"></script> 
        <script>            
            System.import('main.js').catch(function(err){ console.error(err); })
        </script> 
    </head>
<body>
    <my-app>Loading AppComponent content here ...</my-app>
</body>
</html>

Chúng ta có thể hiển thị thêm dòng chữ thông báo lỗi cho người dùng thay vì chỉ thay đổi màu sắc một cách đơn độc, như thế người dùng sẽ không biết rõ sai sót chỗ nào, chúng ta sửa lại file template như sau:

<div class="container">
    <h1>Customer</h1>
    <form>
        <div class="form-group">
            <label for="name">Name</label>
            <input type="text" 
                   class="form-control" 
                   id="name" 
                   [(ngModel)]="customer1.name" 
                   name="cus1_name" 
                   required 
                   #cus_class="ngModel">        
            <div [hidden]="cus_class.valid || cus_class.pristine" 
                 class="alert alert-danger">
                Name is required
            </div>
        </div>
    ...
    </form>
</div>

Chúng ta gán giá trị cho biến template #cus_classngModel, sau đó viết thêm một đoạn <div></div> nữa để hiển thị thông báo ‘Name is required’ nếu người dùng bỏ trống ô <input>.

Lý do ở đây chúng ta gán #cus_classngModel là vì mỗi chỉ thị trong Angular có một thuộc tính là exportAs, thuộc tính này chẳng qua là một đối tượng của chỉ thị đó nhưng chúng ta có thể sử dụng ở bất cứ đâu, và giá trị của thuộc tính này trong chỉ thị ngModel cũng là “ngModel" luôn.

Ở đoạn code trên chúng ta quy định thẻ <div></div> mới có được hiển thị hay không thông qua thuộc tính hidden, và chúng ta gắn giá trị của biến template vào thuộc tính hidden này.

Submit form

Form hiện tại của chúng ta chưa thực hiện chức năng submit, để có thể submit được thì chúng ta sử dụng chỉ thị ngSubmit, chúng ta sửa lại file customer-form.component.html như sau:

<div class="container">
    <h1>Customer</h1>
    <form (ngSubmit)="onSubmit()" #customerForm="ngForm"> 
        ...
    </form>
</div>

Chúng ta gán thuộc tính (ngSubmit) là phương thức onSubmit(), trong lớp CustomerFormComponent chúng ta khai báo thêm onSubmit().

import { Component } from '@angular/core';
import { Customer } from './customer';

@Component({
    moduleId: module.id,
    selector: 'customer', 
    templateUrl: './customer-form.component.html'
})
export class CustomerFormComponent {
 
    jobList = ['Software Developer', 'Tester', 'Project Manager', 'Business Analyst']; 
    customer1 = new Customer(1, 'Pho Coder', 24, this.jobList[0]);  
    onSubmit() { }
}

Ở đây chúng ta chưa xử lý gì nhiều.

Ngoài ra ở trên form chúng ta còn khai báo biến template là #customerForm với giá trị là ngForm, và đây là giá trị của thuộc tính exportAs trong chỉ thị ngForm, tuy nhiên ở đây khác với ngModel là chúng ta chưa khai báo dòng nào tương tự như [(ngForm)]="..." cả, lý do chúng ta vẫn dùng được exportAs của ngForm là vì mỗi khi chúng ta khai bào một thẻ <form> thì Angular sẽ tự động khai báo thuộc tính ngForm cho thẻ <form> luôn.

Chúng ta có thể dùng biến template này để điều khiển nhiều thứ trong form, chẳng hạn như vô hiệu hóa nút Submit khi form không hợp lệ, form không hợp lệ khi có một phần tử trong form không hợp lệ. Ví dụ:

<div class="container">
    <h1>Customer</h1>
    <form (ngSubmit)="onSubmit()" #customerForm="ngForm">
        ....
        <button type="submit" 
                class="btn btn-success" 
                [disabled]="!customerForm.form.valid">
            Submit
        </button>
     </form>
</div>

Chúng ta gán thuộc tính disabled là biểu thức !customerForm.form.valid, và nút "Submit" sẽ không thể click được khi có một phần tử trong form không hợp lệ, chẳng hạn như ô input bỏ trống.

Được đăng vào ngày 17/03/2017