[Angularjs]directive ngModelController的應用

[Angularjs]directive ngModelController

前言

 

最近在寫directive的時候,發現對ngModel掌握度較低,導致一些不明就理的問題,所以決心挖一下官網Api,然後較徹底的研究一下,所以就筆記一下。

 

$render

 

$viewValue是畫面上的值,$modelValue則是controller繫結的值,如果用了$render則不會自動binding,必須要自己指定值

 

    <div ng-controller="mainCtrl as ctrl">
        <form name="ctrl.form" ng-submit="ctrl.submit()" novalidate ng-model-options="{updateOn:'blur'}">
            <input type="text" name="name" ng-model="ctrl.name" is-test required />
            {{ctrl.name}}
            <div ng-messages="ctrl.form.name.$error" ng-show="ctrl.form.name.$dirty" style="color:red">
                <p ng-message="required">input is value</p>
            </div>
        </form>
    </div>
</div>
<script src="~/Scripts/angular.js"></script>
<script src="~/Scripts/angular-messages.js"></script>
<script>
    angular.module('app', ['ngMessages'])
        .controller('mainCtrl', mainCtrl)
        .directive('isTest', isTest);

    function mainCtrl($http) {
        var vm = this;
        $http.get('http://localhost:51597/Api/Values').success(function (data) {
            vm.name = data;
        })
    }

    function isTest() {
        return {
            restrict: 'A',
            require: '?ngModel',
            link: function (scope, elem, attrs, ctrl) {
                ctrl.$render = function () {
                    elem.val("I am" + ctrl.$viewValue);
                }
            }
        }
    }
</script>

 

$parsers and $setValidity

 

$parsers.unshift可以在每次異動的時候觸發,$setValidity則可以自訂錯誤的訊息,裡面的needTwo則代表著自訂的ng-message裡面的錯誤名稱,如果回傳的是undefined的話,就是代表如果不符合的話,只會回傳空值。

 

 function isTest() {
            return {
                restrict: 'A',
                require: '?ngModel',
                link: function (scope, elem, attrs, ctrl) {
                    ctrl.$parsers.unshift(function (viewValue) {  
                        if (viewValue == 2) {
                            ctrl.$setValidity('needTwo', true); //這個needTwo是代表自訂的錯誤名稱
                            return viewValue;
                        } else {
                            ctrl.$setValidity('needTwo', false);
                            return undefined;
                        }
                    })
                   
                }
            }
        }

 

接著我們的ng-message就可以如下寫法,就可以驗証數字不是2的話,就驗證錯誤

 

     <p ng-message="required">必填</p>
     <p ng-message="needTwo">必須為2</p>
</div>

 

$validators

 

1.3之後支援更簡潔的方式,不過不能影響如果錯誤的話,要回傳的是什麼樣的值,預設就是空白值。

 

            return {
                restrict: 'A',
                require: '?ngModel',
                link: function (scope, elem, attrs, ctrl) {
                    ctrl.$validators.needTwo = function (modelValue, viewValue) {
                        if (viewValue == 2) {
                            return true;
                        }
                        return false;
                    };
                   
                }
            }
        }

 

 

$asyncValidators

 

1.3之後同時支援$q的驗證錯誤,效能也更好,beOne代表的是自訂ng-message的名稱,只要是錯誤的話,model預設的就是空白值,像我這個例子只是在伺服器端判斷,必須為1才正確,否則回傳錯誤

 

            return {
                restrict: 'A',
                require: '?ngModel',
                link: function (scope, elem, attrs, ctrl) {
                    ctrl.$asyncValidators.beOne = function (modelValue, viewValue) {
                        return $q(function (resolve, reject) {
                            $http.get('http://localhost:51597/Api/Values/' + viewValue).success(function () {
                                resolve();
                            }).error(function () {
                                reject();
                            })
                        })
                    }
                }
            }
        }

 

$formatters

 

如果我們打算在一開始就要format要binding的值的話,也可以使用ngModel.$formatters.push的方式,比如說從api傳回來的日期,會是字串,這時候如果想要binding到html5的date,就會出現錯誤訊息(Error: [ngModel:datefmt] Expected `2015-10-17T17:11:23.2240502+08:00` to be a date),這時候就可以自訂directive如下例子

 

            return {
                restrict: 'A',
                require: 'ngModel',
                link: function (scope, elem, attrs, ctrl) {
                    ctrl.$formatters.push(function (value) {
                        return new Date(value);
                    })
                }
                
            }
        }

 

改變控制項的狀態

 

代表著移除drity

ctrl.$setPristine();

代表設定為drity

ctrl.$setDirty();

設定為未碰觸過

Ctrl. $setUntouched();

設定為已碰觸過

Ctrl. $setTouched();

 

總結

 

希望對各位有幫助,如果有任何錯誤的話,再請多多指教