Chia sẽ anh em hàm validate mình viết

Chia sẽ anh em hàm validate mình viết cái này được cái  cái này gọn nhẹ sài được cho div không cần gắn vào form, có thể validate những nhóm đối tượng tách biệt nhau, theo class, id , attributes....

Để xử dụng cần gán thuộc tính required vào và các loại class int, date, datetim, dec , email..

var ThuY = {};
ThuY.Form = function (formId) {
    this.hasError = false;
    this.$element = $(formId);

    this.focusError = function () {
        var $input = this.$element.find(".has-error:first :input");
        if ($input.length === 0) return;
        $("html, body").animate({ scrollTop: $input.offset().top - 100 }, 250);
        $input.focus();
    };
     function getValue($el) {
        return $el.is('[type="checkbox"]')
            ? $el.prop("checked")
            : $el.is('[type="radio"]') ? !!$('[name="' + $el.attr("name") + '"]:checked').length : $el.val();
    }
    this.getError = function () {
        var formError = {};

        this.$element.find('input[required],textarea[required],select[required]').each(function (i, requiredField) {
            var $el = $(requiredField);
            var $type = $el.attr('type');

            var $message = $el.attr('reqired-message');
            if (isNotSet($message)) {
                $message = "Giá trị này phải nhập";
            }

            var $maxLength = $el.attr('data-max');
            var $minLength = $el.attr('data-min');
            var $pattern = $el.attr('data-pattern');
            var $value = getValue($el);

            if ($el.hasClass('int')) {
                $value = $value.replace(/[^\d\.\-]/g, "");
                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (typeof n == 'number' && /^-?\d+$/.test($value) === false) {
                    formError[$el.attr('name')] = "Vui lòng nhập vào chuỗi số";
                } else if (isSet($minLength)) {
                    if (parseInt($value) < $minLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải lớn hơn " + $minLength;
                    }
                } else if (isSet($maxLength)) {
                    if (parseInt($value) > $maxLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải nhỏ hơn hơn " + $maxLength;
                    }
                }
            } else if ($el.hasClass('dec')) {
                $value = $value.replace(/[^\d\.\-]/g, "");
                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (/^\d+.?\d*$/.test($value) === false) {
                    formError[$el.attr('name')] = "Vui lòng nhập vào chuỗi số";
                } else if (isSet($minLength)) {
                    if (parseFloat($value) < $minLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải lớn hơn " + $minLength;
                    }
                } else if (isSet($maxLength)) {
                    if (parseFloat($value) > $maxLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải nhỏ hơn hơn " + $maxLength;
                    }
                }

            } else if ($el.hasClass('email') || $type === 'email') {
                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/.test($value) === false) {
                    formError[$el.attr('name')] = "Email không đúng định dạng";
                }

            } else if ($el.hasClass('url') || $type === 'url') {

                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test($value) === false) {
                    formError[$el.attr('name')] = "Website không đúng định dạng";
                }
            } else if ($el.hasClass('date')) {

                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (/^(\d{2})[\/](\d{2})[\/](\d{4})$/.test($value) === false) {
                    //Check date 99/99/9999
                    formError[$el.attr('name')] = "Ngày tháng không đúng định dạng";
                }
            } else if ($el.hasClass('time')) {

                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                    //Check time 99:99
                } else if (/([01]\d|2[0-3]):([0-5]\d)/.test($value) === false) {
                    formError[$el.attr('name')] = "Thời gian không đúng định dạng";
                }
            } else if ($el.hasClass('datetime')) {

                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (/^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2})$/.test($value) === false) {
                    //Check date time 99/99/9999 99:99
                    formError[$el.attr('name')] = "Thời gian không đúng định dạng";
                }
            } else if (isSet($pattern)) {

                if ($pattern.test($value) === false) {
                    formError[$el.attr('name')] = "Giá trị nhập vào không đúng định dạng";
                }
            } else {
                if ($value === '') {
                    formError[$el.attr('name')] = $message;
                } else if (isSet($minLength)) {
                    if ($el.val().length < $minLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải có số ký tự lớn hơn " + $minLength;
                    }
                } else if (isSet($maxLength)) {
                    if ($el.val().length > $maxLength) {
                        formError[$el.attr('name')] = "Giá trị nhập vào phải có số ký tự nhỏ hơn " + $maxLength;
                    }
                }
            }
            $el.bind('change', function () {
                formError[$(this).attr('name')] = null;
            });


        });

        if (!$.isEmptyObject(formError)) { this.hasError = true; }
        return formError;

    }
    this.isFloat = function (val) {
        var floatRegex = /^-?\d+(?:[.,]\d*?)?$/;
        if (!floatRegex.test(val)) return false;
        val = parseFloat(val);
        if (isNaN(val)) return false;
        return true;
    }

    this.isInt = function (val) {
        var intRegex = /^-?\d+$/;
        if (!intRegex.test(val))return false;
        var intVal = parseInt(val, 10);
        return parseFloat(val) === intVal && !isNaN(intVal);
    }
    this.resetForm = function () {
        this.$element.find("input, textarea, select").val("");
    }

    this.isEmpty = function (value, allowEmptyString) {
        function countProperty(obj) {
            var count = 0;
            for (var k in obj)
                obj.hasOwnProperty(k) && ++count;
            return count;
        }

        return value === false ||
            null === value ||
            isNaN(value) === false && 0 === parseInt(value, 10) ||
            "null" === value ||
            void 0 === value ||
            "undefined" === value ||
            (allowEmptyString ? false : "" === value) ||
            "object" == typeof value && 0 === countProperty(value) ||
            "object" == typeof value && 1 === countProperty(value) && "" === value[0] ||
            value instanceof jQuery && 0 === value.length;
    }
    this.loadItem = function () {
        var $item = {};
        this.$element.find('input,textarea,select')
            .each(function (i, item) {
                $item[$(item).attr('name')] = getValue($(item));
            });

        return $item;
    }
    this.item =  this.loadItem();
}

để xử dụng trong controller mình làm như sau

var form = new ThuY.Form("#formAddKhach");
$scope.formErrorAddKhach = form.getError();
if (form.hasError) {
    form.focusError();
    return;
}

html

<div class="col-md-3">
    <div class="form-group" data-ng-class="{'has-error' : formAddKhach.Ten.$invalid && formAddKhach.Ten.$dirty || formErrorAddKhach.Ten}">
        <label class="control-label" for="Ten">{{L('Ten')}} <span class="require">*</span></label>
        <div class="">
            <input class="form-control" id="Ten" name="Ten" ng-model="itemAddKhach.Ten" required reqired-message="Tên bắt buộc nhập." />
            <span class="help-block" ng-show="formAddKhach.Ten.$invalid  && formAddKhach.Ten.$dirty">Nhập {{L('Ten')}}</span>
            <span class="help-block" ng-if="formErrorAddKhach.Ten">{{formErrorAddKhach.Ten}}</span>
        </div>
    </div>
</div>