Huỳnh Minh Tân Bài viết hướng dẫn sử dụng thư viện Knockout-Validation để kiểm tra dữ liệu nhập vào form của người dùng. Từ cách thêm thư viện vào project, cách thiết lặp sự phụ thuộc giữa các file, cách tạo điều kiện để kiểm tra đúng định dạng như số điện thoại, định dạng mail, xác nhận mật khẩu,.. cho đến thao tác với các thuộc tính nâng cao như có thể dịch ra nhiều ngôn ngữ khác nhau và tùy chỉnh hiển thị thông báo đến người dùng.
Nội dung bài viết

Giới thiệu

Bài viết hướng dẫn sử dụng thư viện Knockout-Validation để kiểm tra dữ liệu nhập vào form của người dùng. Từ cách thêm thư viện vào project, cách thiết lặp sự phụ thuộc giữa các file, cách tạo điều kiện để kiểm tra đúng định dạng như số điện thoại, định dạng mail, xác nhận mật khẩu,.. cho đến thao tác với các thuộc tính nâng cao như có thể dịch ra nhiều ngôn ngữ khác nhau và tùy chỉnh hiển thị thông báo đến người dùng.

Knockout-Validation là plugin của thư viện KnockoutJS, nó dùng để kiểm tra / xác thực dữ liệu mà người dùng nhập vào (validation form), trong bài viết này chúng ta tạm gọi nó là thư viện và sử dụng tên viết tắt là KV (Knockout-Validation). Trang chủ https://github.com/Knockout-Contrib/Knockout-Validation/

Trong các ví dụ bên dưới tôi sử dụng framework Durandaljs mà DurandalJS sử dụng RequireJS để quản lý module và dùng KnockoutJS để binding dữ liệu, vì vậy trên cơ bản thao tác với thư viện RequireJS và KnockoutJS là chủ yếu. Tôi có đính kèm souce code demo ở cuối bài viết, các bạn có thể tải về tham khảo.

Tiền đề bài viết

Trong quá trình tìm hiểu về framework DurandalJS để xây dựng Single-page app. Với mục đích tiếp kiệm thời gian xử lý và có thể tạo ra một kiến trúc chương trình dễ dàng cho việc phát triển sau này. Thư viện Knockout-Validation là một sự lựa chọn hợp lý, giúp cho người mới (newbie) có thể tiếp cận các kiến thức liên quan một cách nhanh chống trên con đường trở thành Frontend Developer.

Điều kiện bắt buộc

Chỉ dành cho các lập trình viên đã có kiến thức về RequireJS và KnockoutJS. Có thể đọc thêm bài viết RequireJS Cho Người Mới Bắt Đầu để có kiến thức cơ bản.

Thêm thư viện Knockout-Validation vào dự án

Để có thể thao tác với thư viện Knockout-Validation chúng ta chỉ cần thêm tập tin knockout.validation.js vào dự án đang làm việc. Các bạn vào trang chủ https://github.com/Knockout-Contrib/Knockout-Validation để tải về.

Bước đầu tiên, vào requirejs.config() để cấu hình:

  • Sử dụng thuộc tính path để khai báo tên đại diện, tên này sử dụng trong việc gọi và thực thi thư viện KV (Knockout-Validation) khi định nghĩa module nào đó. 
  • Và sử dụng thuộc tính shim để chắc chắn rằng thư viện KnockoutJS phải được thực thi trước thư viện KV.

Có thể tải thư viện về máy hoặc sử dụng CDN nhưng phải lưu ý là không có đuôi ở rộng .js ở cuối, xem code mẫu bên dưới.

// main.js

requirejs.config({
    paths: {
        // khai báo thư viện để sử dụng DurandalJS
        'text': '../lib/require/text',
        'durandal': '../lib/durandal/js',
        'plugins': '../lib/durandal/js/plugins',
        'transitions': '../lib/durandal/js/transitions',
        'knockout': '../lib/knockout/knockout-3.1.0',
        'bootstrap': '../lib/bootstrap/js/bootstrap',
        'jquery': '../lib/jquery/jquery-1.9.1',

        // Thêm thư viện KV
        'knockout.validation': '../lib/knockout/knockout.validation'
        // có thể sử dụng CDN, không có đuôi .js
        // 'knockout.validation': 'https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation'

    },
    shim: {
        'bootstrap': {
            deps: ['jquery'],
            exports: 'jQuery'
        },

        // thiết lặp sự phụ thuộc
        // KnockoutJS phải thực thi trước Knockout Validation
        'knockout.validation': {
            deps: ["knockout"]
        }
    }
});

Bước cuối cùng, thực thi thư viện KV trong lúc định nghĩa module bằng cách gọi trong hàm define() hoặc require(). Để sử dụng KV ta chỉ việc gọi nó để thực thi là xong mà không cần tạo biến đại diện giống như app, system, ko để thao tác. Sử dụng cách 1 dùng tên đại diện sẽ linh hoạt hơn nếu muốn thay đổi đường dẫn thư viện sau này. Có 2 cách để gọi thực thi như bên dưới.

// Cách 1
// sử dụng tên 'knockout.validation' để gọi thư viện KV
define(['durandal/app', 'durandal/system', 'knockout', 'knockout.validation'], function (app, system, ko) {
    // code some thing
});

// Cách 2
// nếu không sử dụng tên đại diện (không khai báo ở thuộc tính path) thì
// sử dụng đường dẫn trực tiếp, có thể dùng CDN
define(['durandal/app', 'durandal/system', 'knockout', '../lib/knockout/knockout.validation'], function (app, system, ko) {
    // code some thing
});

Như vậy, chỉ cần qua 2 bước là có thể sử dụng được thư viện KV, còn sử dụng như thế nào thì chúng ta sẽ theo dõi những nội dung kế tiếp.

Làm việc với Knockout-Validation

Sử dụng các thuộc tính cơ bản

Để trực quan hơn chúng ta sẽ thực hiện một ví dụ, tạo một form đăng ký sau đó kiểm tra (validate) dữ liệu của người dùng nhập vào, có giao diện như bên dưới.

12

Kết quả validate sẽ như sau.

222_a_b

Yêu cầu, dùng thư viện Knockout-Validation để kiểm tra các thông tin nhập vào từ người dùng, chúng ta sẽ đi qua từng thuộc tính. Để có được giao diện như bên trên ta định nghĩa giao diện bằng HTML, đoạn code bên dưới dùng thư viện KnockoutJS để binding dữ liệu.

// signup.ko.validation.html

<div class="container">
    <div class="row">
        <div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3">
            <form role="form">
                <h2>Please Sign Up
                    <small>It's free and always will be.</small>
                </h2>
                <hr class="colorg`ph">
                <div class="row">
                    <div class="col-xs-12 col-sm-6 col-md-6">
                        <div class="form-group">

                            <input data-bind="value: first_name, valueUpdate: 'afterkeydown' " type="text" name="first_name" id="first_name" class="form-control input-lg"
                                placeholder="First Name" tabindex="1">
                            <p class="validationMessage" data-bind="validationMessage: first_name" style="color: red"></p>

                        </div>
                        <div class="col-xs-12 col-sm-6 col-md-6">
                            <div class="form-group">
                                <input data-bind="value: last_name, valueUpdate: 'afterkeydown'" type="text" name="last_name" id="last_name" class="form-control input-lg"
                                    placeholder="Last Name" tabindex="2">
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <input data-bind="value: phone, valueUpdate: 'afterkeydown' " type="text" name="phone" id="phone" class="form-control input-lg"
                            placeholder="Phone Number" tabindex="3">
                    </div>
                    <div class="form-group">
                        <input data-bind="value: email, valueUpdate: 'afterkeydown' " type="email" name="email" id="email" class="form-control input-lg"
                            placeholder="Email Address" tabindex="4">
                    </div>
                    <div class="row">
                        <div class="col-xs-12 col-sm-6 col-md-6">
                            <div class="form-group">
                                <input data-bind="value: password, valueUpdate: 'afterkeydown' " type="password" name="password" id="password" class="form-control input-lg"
                                    placeholder="Password" tabindex="5">
                            </div>
                        </div>
                        <div class="col-xs-12 col-sm-6 col-md-6">
                            <div class="form-group">
                                <input data-bind="value: password_confirmation, valueUpdate: 'afterkeydown' " type="password" name="password_confirmation"
                                    id="password_confirmation" class="form-control input-lg" placeholder="Confirm Password" tabindex="6">
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-xs-12 col-sm-12 col-md-12">
                            <input data-bind="checked: agree, valueUpdate: 'afterkeydown'" type="checkbox" style="margin-right: 10px" name="t_and_c"
                                id="t_and_c" value="1">I Agree, By clicking Register, you agree to
                            the Terms and Conditions.
                        </div>
                    </div>

                    <div class="row" style="margin-top: 15px">
                        <div class="col-xs-12 col-md-6">
                            <input data-bind="click: displayInfo, enable: canRegister" type="submit" value="Register" class="btn btn-primary btn-block btn-lg"
                                tabindex="7">
                        </div>
                        <div class="col-xs-12 col-md-6">
                            <a href="#" class="btn btn-success btn-block btn-lg">Sign In</a>
                        </div>
                    </div>
            </form>
            </div>
        </div>

        <div class="row">
            <span data-bind="text: merror"></span>
            <span data-bind="text: first_name"></span>
            <span data-bind="text: last_name"></span>
            <span data-bind="text: phone"></span>
            <span data-bind="text: email"></span>
            <span data-bind="text: password"></span>
            <span data-bind="text: password_confirmation"></span>
        </div>
    </div>

Làm quen với Rule (Validation Rules)

Rule dùng để quy định một điều kiện bắt buộc cho biến sử dụng nó phải tuân thủ theo. Ở ví dụ dưới, biến myVariable phải thỏa điều kiện của Rule 1, Rule 2..

Cú pháp tổng quát:

var myVariable = ko.observable().extend({ 
    tên Rule 1 : giá trị thuộc tính,
    tên Rule 2 : giá trị thuộc tính,
    // ...
});

Mặc định thư viện Knockout-Validation đã giúp ta định nghĩa sẵn những điều kiện thường hay sử dụng như:

  • min / max: quy định giá trị nhỏ nhất / lớn nhất
  • minLength / maxLength: quy định số lượng ký tự ít nhất / nhiều nhất
  • pattern: kiểm tra dữ liệu có phù hợp, sử dụng regex
  • email: kiểm tra có đúng format mail hay không
  • number: nhập vào phải là số
  • phoneUS: kiểm tra số điện thoại có đúng format nước Mỹ không
  • equal: kiểm tra hai giá trị có bằng nhau không

Các Rule đó được gọi là Rule mặc định (Native Rules) được KV định nghĩa từ dòng 852 trong knockout.validation.js (version 2.0.3)

// knockout.validation.js
// ………………

kv.rules['min'] = {
    validator: minMaxValidatorFactory("min"),
    message: 'Please enter a value greater than or equal to {0}.'
};

kv.rules['max'] = {
    validator: minMaxValidatorFactory("max"),
    message: 'Please enter a value less than or equal to {0}.'
};

kv.rules['minLength'] = {
    validator: function (val, minLength) {
        if (kv.utils.isEmptyVal(val)) { return true; }
        var normalizedVal = kv.utils.isNumber(val) ? ('' + val) : val;
        return normalizedVal.length >= minLength;
    },
    message: 'Please enter at least {0} characters.'
};

kv.rules['maxLength'] = {
    validator: function (val, maxLength) {
        if (kv.utils.isEmptyVal(val)) { return true; }
        var normalizedVal = kv.utils.isNumber(val) ? ('' + val) : val;
        return normalizedVal.length <= maxLength;
    },
    message: 'Please enter no more than {0} characters.'
};

kv.rules['pattern'] = {
    validator: function (val, regex) {
        return kv.utils.isEmptyVal(val) || val.toString().match(regex) !== null;
    },
    message: 'Please check this value.'
};

// ………………

Chúng ta cũng có thể tự định nghĩa Rule tùy theo mục đính sử dụng, định nghĩa nó như thế nào sẽ được tôi trình bày ở nội dung kế tiếp trong bài viết này. Bây giờ chúng ta sẽ thực hiện việc kiểm ra dữ liệu của người dùng dựa vào ví dụ bên trên.

  • Tham khảo các Rule mặc định tại https://github.com/Knockout-Contrib/Knockout-Validation/wiki/Native-Rules
  • Tham khảo các Rule do cộng đồng đóng góp tại https://github.com/Knockout-Contrib/Knockout-Validation/wiki/User-Contributed-Rules

Áp dụng các Rule mặc định của Knockout-Validation để validate form

Thiết lặp quy định trường dữ liệu FirstName và LastName, điều kiện là tên có ít nhất là 2 ký tự, nhiều nhất là 17 ký tự, hai trường này bắt buộc người dùng phải nhập và tên không chứa số. Ta có đoạn code bên dưới, xem thêm chú thích ở comment. 

var first_name = ko.observable().extend({
    minLength: 2, // ít nhất 2 ký tự
    maxLength: 17, // nhiều nhất 17 ký tự
    required: true, // bắt buộc phải được nhập
    pattern: { // thao tác với regex để so sánh điều gì đó từ tham số params
        message: 'Tên sẽ không bao gồm số.', // tạo thông báo in ra giao diện
        params: '^[^0-9]+$'   // lệnh regex không thể chứa số, điều kiện đúng để in ra thông báo
       // vào regex101.com để kiểm tra độ chính xác của câu lệnh regex
    }
});

var last_name = ko.observable().extend({
    minLength: 2,
    maxLength: 17,
    required: true,
    pattern: {
        message: 'Tên sẽ không bao gồm số.', 
        params: '^[^0-9]+$'  
    }
});

Nếu người dùng nhập đúng điều kiện thì không có gì xảy ra, còn nhập sai thì KV sẽ tự động chèn một message dưới thẻ input dùng để binding (chèn dưới thẻ input fist_name hoặc last_name trong ví dụ này) để hiển thị thông báo đến cho người dùng. Mặc định message được KV tạo có classname là validationMessage, có cấu trúc như bên dưới.

<span class="validationMessage" style=""> [nội dung message cần thông báo] </span>

Kết quả người dùng nhập sai.

oki_b

Ở kết quả trên, khi người dùng nhập sai ở trường First Name thì KV sẽ tự động hiển thị message có nội dung “Tên sẽ không bao gồm số.” đã được định nghĩa ở Rule pattern. Còn ở trường Last Name không đúng điều kiện Rule minLenght nên nó được KV hiển thị tự động với nội dung message "Please enter at least 2 characters" do đã được định nghĩa trong knockout.validation.js (version 2.0.3)

// knockout.validation.js (version 2.0.3)
// line 862
// ...
kv.rules['minLength'] = {
    validator: function (val, minLength) {
        if(kv.utils.isEmptyVal(val)) { return true; }
        var normalizedVal = kv.utils.isNumber(val) ? ('' + val) : val;
        return normalizedVal.length >= minLength;
    },
    message: 'Please enter at least {0} characters.'
};
// ...

Muốn thay đổi nội dung message thông báo đến người dùng ta không nên sửa trực tiếp trong thư viện knockout.validation.js, thay vào đó sẽ áp dụng cách gọi là Localization (chi tiết ở phần Thay đổi nội dung Message và dịch ra nhiều ngôn ngữ khác nhau (Localization) trong bài viết này).

Tương tự như vậy, chúng ta sẽ kiểm tra các trường còn lại. Đây là source code đầy đủ để thực hiện việc validate form bằng thư viện KV, trong đó tôi áp dụng kiến trúc framework DurandalJS.

// signup.ko.validation.js

define(['durandal/app', 'durandal/system', 'knockout', 'knockout.validation'], function (app, system, ko) {

    var first_name = ko.observable().extend({
        minLength: 2, // ít nhất 2 ký tự
        maxLength: 17, // nhiều nhất 17 ký tự
        required: true, // bắt buộc phải được nhập
        pattern: { // thao tác với regex để so sánh điều gì đó từ tham số params
            message: 'Tên sẽ không bao gồm số.', // tạo thông báo in ra giao diện
            params: '^[^0-9]+$'   // lệnh regex không thể chứa số, điều kiện đúng để in ra thông báo
            // vào regex101.com để kiểm tra độ chính xác của câu lệnh regex
        }
    });

    var last_name = ko.observable().extend({
        minLength: 2,
        maxLength: 17,
        required: true,
        pattern: {
            message: 'Tên sẽ không bao gồm số.',
            params: '^[^0-9]+$'
        }
    });

    var phone = ko.observable().extend({ phoneUS: true }); // bắt đầu bắng số 1, có 11 chữ số
    // phoneUS là một Rule đã được thư viện KV định nghĩa, ở dòng 945 (ver 2.0.3) 
    // có thể dùng thuộc tính pattern để đổi thành format phoneVN
    // chúng ta có thể tự định nhĩa mới một Rule theo đúng nhu cầu của ta

    // khi tự định nghĩa thì biến message sẽ đảm nhận in ra nội dung mà chúng ta cần hiển thị
    // còn khi sử dụng Rule mặc định thì sẽ in ra nội dung mặc định tương ứng với rule đó, có thể đổi nội dung hoặc đổi ngôn ngữ hiển thị của message 

    var email = ko.observable().extend({ email: true }); // kiểm tra tính hợp lệ mail nhập vào sử dụng Rule email
    var password = ko.observable(); // không xét
    var password_confirmation = ko.observable().extend({ equal: password }); // password confirmation phải bằng với password nhập trước đó
    var agree = ko.observable(false); // radio điều khoản sử dụng, không xét


    // dùng phương thức .isVail() để kiểm tra giá trị của các trường có thỏa điều kiện không
    var canRegister = ko.computed(function () {
        if (first_name.isValid() &&
            last_name.isValid() &&
            phone.isValid() &&
            email.isValid() &&
            password_confirmation.isValid() &&
            agree()
        )
            return true;
        return false;
    });

    return {
        // khai báo thuộc tính để dùng để binding
        first_name: first_name,
        last_name: last_name,
        phone: phone,
        email: email,
        password: password,
        password_confirmation: password_confirmation,
        agree: agree,

        displayInfo: function () {

            // dùng thư viện Durandaljs để in ra một popup gồm các thông tin đã nhập
            app.showMessage(first_name() + '  <hr>' + this.last_name() + ' <hr>' +
                phone() + '  <hr>' + email() + '  <hr>' + password() + '  <hr>' + password_confirmation(), 'Greetings');
        },

        canRegister: canRegister,
    };
});

Trong đoạn code trên tôi có hàm canRegister(), hàm này trả về true nếu tất cả các trường được nhập chính xác từ người dùng, trả về false nếu có một trường không thỏa điều kiện. Do hàm myVariable.isVaild() sẽ trả về true nếu thỏa tất cả các Rule được định nghĩa ở biến myVariable, trả về false nếu tồn tại một Rule không thỏa.
Về cơ bản bấy nhiêu đó đã đủ validate một form đơn giản, nếu bạn muốn tự định nghĩa một Rule, thay đổi nội dung hoặc việt hóa message thì có thể xem ở phần kế tiếp.

Thiết lặp các thuộc tính nâng cao

Tự định nghĩa một Rule (Custom Validation Rules)

Cú pháp tổng quát tạo Rule:

var myVariable = ko.observable().extend({
    validation: {
        validator: <function điều kiện kiểm tra>,// kiểu trả về boolean, hàm trả về true sẽ hiển thị thông báo cho người dùng
        message:  <nội dung hiển thị thông báo>,
        params: <giá trị so sánh>  // có thể có hoặc không tùy function điều kiện
    }
});

Không sử dụng Rule mặc định, chúng ta sẽ tự định nghĩa Rule để kiểm tra trường password comfirmation có giống với trường password đã nhập không. Có 2 cách để thực hiện:

  • Định nghĩa ẩn danh (Anonymous Custom Rules)
// signup.ko.validation.js

// tách fuction ra riêng 
var isEqual = function (valInput, himself) {
    return valInput === himself;
};

// định nghĩa Rule dạng anonymous
var password_confirmation = ko.observable().extend({
    validation: {
        validator: function (valInput, himself) {  // có thể dùng biến isEqual để định nghĩa hàm gián tiếp, tách fuction ra riêng
            // valInput là giá trị người dùng nhập vào
            // himseft là giá trị ở thuộc tính params
            return valInput === himself;
        },
        message: 'Vui lòng xác nhận đúng password.',
        params: password  // giá trị của biến himself là giá trị của biến params
        // password là biến dùng binding để lấy giá trị nhập vào ở thẻ input password
    }
});
  • Định nghĩa tường minh (Custom Rules)
// signup.ko.validation.js

// định nghĩa mới một Rule có tên là mustEqual
ko.validation.rules['mustEqual'] = {
    validator: function (valInput, himself) {
        return valInput === himself;
    },
    message: 'Vui lòng xác nhận đúng password.'
};

// đăng ký sử dụng
ko.validation.registerExtenders();

// gọi thực thi như bình thường, với Rule là mustEqual
var password_confirmation = ko.observable().extend({ mustEqual: password });

Tùy theo mục đính sử dụng để chọn cách định nghĩa Rule cho phù hợp, với cách tường minh tạo ra hẳng một tên đại diện cho Rule điều này có vẽ phù hợp với việc tái sử dụng lại Rule này ở nhiều nơi. Còn cách ẩn danh sẽ hiện thực một cách nhanh chóng không cần gọi hàm ko.validation.registerExtenders() để đăng ký sử dụng.

Thay đổi nội dung Message và dịch ra nhiều ngôn ngữ khác nhau (Localization)

Xem ví dụ sau.

vvc_a

Các bạn đã biết, khi sử dụng các Rule mặc định thì sẽ thông báo cho người dùng message có nội dung được thư viện định nghĩa sẵn và sử dụng ngôn ngữ tiếng Anh để thể hiện như một cách mặc định. Muốn vừa thay đổi nội dung vừa dịch sang các ngôn ngữ khác thì ta sẽ cần một file để định nghĩa, thông thường tên file này có dạng vi-VN.js, en-US.js, fr-FR.js,..

Tham khảo các ngôn ngữ đã dịch sẵn ở thư mục localization https://github.com/Knockout-Contrib/Knockout-Validation/tree/master/localization

Bây giờ mình sẽ đi việt hóa message thông báo cho người dùng, đầu tiên tạo file để định nghĩa có tên là vi-VN.js nên copy từ en-US.js rồi sửa lại cho chính xác. Sửa bằng cách thay đổi tất cả “en-US” thành “vi-VN” và dịch sang tiếng Việt những message nào cần thiết, cuối cùng ta được.

// vi-VN.js

/**
 * Localization file for Greek - Greece (vi-VN)
 */
(function(factory) {
    // Module systems magic dance.
    /*global require,ko.validation,define,module*/
    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
        // CommonJS or Node
        module.exports = factory(require('../'));
    } else if (typeof define === 'function' && define['amd']) {
        // AMD anonymous module
        define(['knockout.validation'], factory);
    } else {
        // <script> tag: use the global `ko.validation` object
        factory(ko.validation);
    }
}(function(kv) {
    if (!kv || typeof kv.defineLocale !== 'function') {
        throw new Error('Knockout-Validation is required, please ensure it is loaded before this localization file');
    }
    return kv.defineLocale('vi-VN', {
        // required: 'This field is required.',
        required: 'Trường này là bắt buộc.',
        min: 'Please enter a value greater than or equal to {0}.',
        max: 'Please enter a value less than or equal to {0}.',
        // minLength: 'Please enter at least {0} characters.',
        minLength: 'Nhập ít nhất {0} ký tự.',
        // maxLength: 'Please enter no more than {0} characters.',
        maxLength: 'Không nhập hơn {0} ký tự.',
        pattern: 'Please check this value.',
        step: 'The value must increment by {0}.',
        // email: 'Please enter a proper email address.',
        email: 'Vui lòng nhập đúng định dạng mail, [email protected]',
        date: 'Please enter a proper date.',
        dateISO: 'Please enter a proper date.',
        number: 'Please enter a number.',
        digit: 'Please enter a digit.',
        // phoneUS: 'Please specify a valid phone number.',
        phoneUS: 'Vui lòng nhập đúng định dạng US, bắt đầu bằng 1 và gồm 11 số.',
        equal: 'Values must equal.',
        notEqual: 'Please choose another value.',
        unique: 'Please make sure the value is unique.'
    });
}));

Tiếp theo, thêm file mới tạo (vi-VN.js) vào project. Làm tương tự như cách thêm thư viện Knockout-Validation, tôi sử dụng RequireJS để load module bằng việc thiết lặp thuộc tính path requirejs.config().

// main.js

requirejs.config({
    paths: {
        'text': '../lib/require/text',
        'durandal':'../lib/durandal/js',
        'plugins' : '../lib/durandal/js/plugins',
        'transitions' : '../lib/durandal/js/transitions',
        'knockout': '../lib/knockout/knockout-3.1.0',
        'bootstrap': '../lib/bootstrap/js/bootstrap',
        'jquery': '../lib/jquery/jquery-1.9.1',

        'knockout.validation.vi-VN': 'vi-VN', // khai báo tên đại diện 'knockout.validation.vi-VN' cho file mới vừa tạo vi-VN.js
        'knockout.validation': '../lib/knockout/knockout.validation' // chú ý đặt đúng tên 'knockout.validation' để file vi-VN.js thực thi chính xác
    },
    shim: {
        'bootstrap': {
            deps: ['jquery'],
            exports: 'jQuery'
        },
        'knockout.validation': {
            deps: ["knockout"]
        },
        // dependency
        // chắc chắn rằng thư viện knockout.validation thực thi trước file vi-VN.js     
        'knockout.validation.vi-VN': {
            deps: ["knockout.validation"]
        }
    }
});

Chú ý, để file vi-VN.js thực thi chính xác thì ta cần phải khai báo thư viện knockout.validation.js có tên đại diện là 'knockout.validation', phải làm điều này bởi vì trong vi-VN.js có gọi thư viện KV để thực thi. Còn không các bạn có thể thiết lặp đường dẫn trực tiếp cho phù hợp, miễn sao có thể load được thư viện Knockout-Validation.

// vi-VN.js
// …  
} else if (typeof define === 'function' && define['amd']) {
    // AMD anonymous module
    define(['knockout.validation'], factory);     // <--------- dòng này sử dụng tên đại diện 'knockout.validation' để gọi thực thi thư viện KV
} else {
// …

Tiếp theo, gọi thực thi như cách thông thường khi định nghĩa module, sau đó phải phải kích hoạt bằng cách gọi hàm ko.validation.locale() truyền vào đúng tên file đã đặt ('vi-VN' trong ví dụ này).  

define(['durandal/app', 'durandal/system', 'knockout', 'knockout.validation', 'knockout.validation.vi-VN'], function (app, system, ko) {
    // code some thing

    // gọi hàm để kích hoạt localization với đúng tên đã tạo là 'vi-VN'
    ko.validation.locale('vi-VN');

});

Tùy chỉnh nơi hiển thị Message ở giao diện HTML (validationMessage)

Xem ví dụ

dfdf_a

Như đã nói, mặc định thư viện KV thông báo message ra giao diện bằng cách chèn nội dung trong cặp thẻ <span>, có classname là validationMessage và hiển thị bên dưới thẻ input dùng binding. Để muốn tùy chỉnh như thêm mới class name, thêm thuộc tính style=”” hoặc hiển thị ở bất kỳ vị trí nào. Thực hiện việc này bằng cách tạo thẻ tag (span, div, p, ..) bao quanh nơi cần tùy chỉnh và gán insertMessages = false.

<!-- signup.ko.validation.html -->

<!-- set thuộc tính  insertMessages: false-->
<div data-bind="validationOptions: {insertMessages: false}">
    <!-- thẻ input dùng binding -->
    <input data-bind="value: first_name, valueUpdate: 'afterkeydown' " type="text" name="first_name" id="first_name" class="form-control input-lg" placeholder="First Name" tabindex="1">
</div>

<!-- first_name là tên biến dùng binding, có thể đặt bất cứ đâu để hiển thị thông báo tùy thích -->
<p class="validationMessage" data-bind="validationMessage: first_name" style="color: red"></p>

Hoặc, dùng hàm ko.validation.init() để tắt tính năng tự động hiển thị message cho tất cả các biến.

// signup.ko.validation.js

ko.validation.init({
    insertMessages: false, // tắt tự động hiển thị áp dụng tất cả message
}, true);


// signup.ko.validation.html

// đặt ở bất kỳ vị trí nào cần hiển thị
// truyền vào tên biến cần hiển thị thông báo ở thuộc tính validationMessage, 
// ví dụ dưới hiển thị thông báo cho trường first name
<p class="validationMessage" data-bind="validationMessage: first_name" style="color: red"></p>

Các nguồn hữu ích

  • http://jsfiddle.net/KHFn8/5424/
  • http://jsfiddle.net/crissdev/pt6fay6d/
  • http://embed.plnkr.co/qCu23Cid0D4jlkndPvYy/preview
  • https://js.devexpress.com/Demos/WidgetsGallery/Demo/Validation/Overview/Knockout/Light/

Kết luận

Tải source code demo tại validate_form_knockout-validation_example.zip

Bài viết đã hướng dẫn cách kiểm tra dữ liệu của người dùng nhập vào form sử dụng thư viện Knockout-Validation, áp dụng mềm dẻo thư viện giúp chúng ta tiếp kiệm được khá nhiều thời gian xử lý và có được cấu trúc chương trình rất tường minh dễ dàng trong việc phát triển và bảo trì sau này. Các ví dụ được viết trên nền framework DurandalJS nhưng phần lớn thao tác với RequireJS và KnockoutJS. Tôi hy vọng qua bài viết này sẽ giúp ích cho tất cả các bạn đặc biệt đối với những lập trình viên mới tiếp cận khối kiến thức khổng lồ từ các thư viện các framework JavaScript trong việc phát triển website.

 

THẢO LUẬN
ĐÓNG