2014年10月13日 星期一

Angularjs Form Validation

CRUD的網站中常具有登入、註冊的場景,頁面中可能會輸入一些值來做為登入與註冊的依據,但有些欄位可能需要一些智能的限制與提示,可以在前端先完成,而不用將整筆資料傳送到後端後再將驗證結果回傳,一來節省頻寬的浪費,二來可以即時將提示的樣板顯示於頁面,如email格式的檢查、密碼強度的限制等,而Angularjs也提供一些簡單的技巧來達成此功能,只要運用form搭配$valid、$error、$dirty等屬性即可,而於此也搭配ui-router來進行頁面的切換。


   一、首先設計index.html搭配bootstrap.css中的panel及ui-router的ui-view呈現register.html及register.message.html

<html ng-app="registerAppModule">
<head lang="en">
    <title></title>
    <link href="../../includes/bootstrap/css/bootstrap.css" rel="stylesheet">

    <script src="../../includes/jquery/jquery-2.1.1.min.js"></script>
    <script src="../../includes/angular/angular.min.js"></script>
    <script src="../../includes/angular/angular-ui-router.js"></script>

    <script src="../controller/registerApp.js"></script>
    <script src="../controller/registerController.js"></script>
    <script src="../../services/cacheMethod.js"></script>
</head>
<body>
<div class="panel panel-primary" align="center" style="width: 50% ;margin-left: auto;margin-right: auto;">
    <div class="panel-heading">Register</div>
    <div class="panel-body bg-warning" align="center" ui-view></div>
</div>
</body>
</html>

二、registerApp.js,用來設定ui-router狀態的設定與切換

(function () {
    angular.module('registerAppModule', ['ui.router','registerControllerModule'])
        .config(function($stateProvider,$urlRouterProvider,$locationProvider){
            $urlRouterProvider.otherwise("/register");
            $stateProvider.state('register',{
                url: '/register',
                templateUrl: 'register.html',
                controller: 'registerController'
            }).state('message',{
                url: '/message',
                templateUrl: 'register.message.html',
                controller: 'messageController'
            })
        })

})();

三、register.html,以ng-class、ng-show來切換驗證錯誤與驗證成功的樣板,而方法都置於registerController.js

<form name="registerForm" class="form-inline" ng-submit="submit(registerForm.$valid)" novalidate>
    <div class="form-group"  ng-class="getFormGroupClass(registerForm.idText)">
        <label  class="control-label" for='passwordText'>User Name:</label>
        <input type="text" class="form-control" id="idText" name="idText" placeholder="Enter your User Name..."  ng-model="idText" required>
        <span ng-show="registerForm.idText.$dirty" ng-class="getGlyphIconClass(registerForm.idText)"></span>
        <br />
        <label class="control-label" ng-show="isRequired(registerForm.idText)">*Required</label>
    </div>
    <p />

    <div class="form-group"  ng-class="getFormGroupClass(registerForm.passwordText)">
        <label class="control-label" for='passwordText'>Password:</label>
        <input type="password" class="form-control" id="passwordText" name="passwordText" placeholder="Enter your password..."  ng-model="passwordText" ng-pattern="passwordPattern" required>
        <span ng-show="registerForm.passwordText.$dirty" ng-class="getGlyphIconClass(registerForm.passwordText)"></span>
        <br />
        <label class="control-label" ng-show="isRequired(registerForm.passwordText)">*Required</label>
        <label class="control-label" ng-show="registerForm.passwordText.$error.pattern">*Required 8-12 characters with a-z and 0-9</label>
    </div>
    <p />
    <div   ng-class="getFormGroupClass(registerForm.emailText)">
        <label class="control-label" for='emailText'>Email:</label>
        <input type="email" class="form-control" id="emailText" name="emailText" placeholder="Enter your email..." ng-model="emailText" required/>
        <span ng-show="registerForm.emailText.$dirty" ng-class="getGlyphIconClass(registerForm.emailText)"></span>
        <br />
        <label class="control-label left" ng-show="isRequired(registerForm.emailText)">*Required</label>
        <label class="control-label left" ng-show="registerForm.emailText.$error.email">*Invalid email</label>
    </div>
    <p />
    <button type="submit" class="btn btn-info" ng-disabled="registerForm.$invalid">Submit</button>
</form>

四、registerController.js自訂filter為密碼增加mask,裡面具有兩個controller,分別為registerController來驗證資料的限制條件及設計submit function當驗證成功就將傳參的值存入cache並跳轉頁面,另外為messageController運用$viewContentLoaded的事件監聽來載入傳參資料並顯示。

(function(){
    angular.module('registerControllerModule',['ui.router','cacheMethodModule'])
        .filter('passwordFilter',function(){
            return function(str,symbol){//保留密碼的頭跟尾,中間字串取代成自訂符號
                if (!symbol) symbol = '*';
                if (!str) return;
                var fixShowLength = 2;
                var maskLength,replaceSourceStr,replaceTargetStr;
                if (str.length <= fixShowLength){
                    maskLength = str.length;
                    replaceSourceStr = str;
                }else{
                    maskLength = str.length - fixShowLength;
                    replaceSourceStr = str.substr(1,maskLength);
                }
               replaceTargetStr = '';
                for (var i = 0;i < maskLength;i++) replaceTargetStr += symbol;
                str = str.replace(replaceSourceStr,replaceTargetStr);
                return str;
            }
        })
        .controller('registerController',function($scope,$state,cacheMethodService){
            $scope.passwordPattern = /(?=^.{8,12}$)(?=.*\d)(?![.\n])(?=.*[a-z]).*$/;//配對8-12個英數混和字元
            $scope.submit = function(isValid){
                if (!isValid) return;
                cacheMethodService.saveCache('tmpParameter',{//傳參用
                    'username': $scope.idText,
                    'password': $scope.passwordText,
                    'email': $scope.emailText
                });
                $state.go('message');
            };
            $scope.getFormGroupClass = function(groupControls){
                if (!groupControls.$dirty) return;//若該Controls未修過值則不動作
                return groupControls.$invalid?'form-group has-error has-feedback':'form-group has-success has-feedback';//回傳驗證過與未驗證過的樣板
            }
            $scope.getGlyphIconClass = function(groupControls){
                return groupControls.$valid?'glyphicon glyphicon-ok form-control-feedback':'glyphicon glyphicon-remove form-control-feedback';//回傳驗證過與未驗證過的小圖示
            }
            $scope.isRequired = function(groupControls){
                return groupControls.$error.required && groupControls.$dirty;//判斷是否符合必填限制
            }
        })
        .controller('messageController',function($scope,cacheMethodService){
            $scope.$on('$viewContentLoaded', function () {//當頁面載入時讀取cache中傳參的值
                $scope.onLoad()
            });
            $scope.onLoad = function () {
                var cacheDatas = cacheMethodService.getCache('tmpParameter');
                $scope.userNameMessage = cacheDatas['username'];
                $scope.passwordMessage = cacheDatas['password'];
                $scope.emailMessage = cacheDatas['email'];

            }
        })
})();

五、cacheMethod.js存取快取資料

(function(){
    angular.module('cacheMethodModule',[])
        .service('cacheMethodService',function($cacheFactory){
            var cache = $cacheFactory('myCache');
            var saveCache = function(key,values){
                cache.put( key, values );
            }
            var getCache = function(key){
                var result =  cache.get(key);
                return !result?"":result;
            }
            return{
                saveCache: saveCache,
                getCache: getCache
            }
        })
})();

六、register.message.html

Your name is:{{userNameMessage}}
<br />
Your password is:{{passwordMessage|passwordFilter}}
<br />
Your email is :{{emailMessage}}
<p />
<a ui-sref="register" class="btn btn-info">go back</a>

沒有留言:

張貼留言