延續昨天的介紹,今天來討論 ng-model controller 的兩個 Properties: $viewValue 跟 $modelValue 。
$viewValue: String type,顯示給使用者的值
$modelValue: model controller 綁定的值。不一定是 string type,而是我們指定的格式。
ex: Date 格式的 input 在畫面上,顯示的是 “Sep 10 , 2014”。
$viewValue: String type,“Sep 10 , 2014”
$modelValue: Date type,”new Date()"。
範例:
使用 $formatters 跟 $parsers 就可操作 model 跟使用者 input 的 directive.
範例:輸入的數字都會轉成中文的數字
http://plnkr.co/edit/4rwWNTp1qgJ5ZoutaSoc?p=preview
angular.module('myExample')
.directive('chineseNumber', function () {
return {
restrict: 'A',
// 必須使用 ngModel 取得 input value
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
// 假如沒有 ngModel 就 gg 了...
if (!ngModel) return;
var numbers = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
// $parsers 是檢查使用者輸入的 value
ngModel.$parsers.push(changeFormat);
// $formatter 是檢查來自程式的改變
ngModel.$formatters.push(changeFormat);
function changeFormat (value) {
console.log('value', value);
if ('string' === (typeof value)) {
var temp = [];
// 把 Number 換成中文
for (var i = 0, len = value.length; i < len; i++ ) {
var num = value[i];
if (isNumber(num)) {
var cn = numbers[parseFloat(num)];
temp.push(cn);
} else {
temp.push(num)
}
}
var result = temp.join('');
// update input value after format, 會改變 $viewValue
// 可以使用 element set value 的方式
// element.val(result);
// 或 再次跑 $parses 確認一次
if (result != value) {
ngModel.$setViewValue(result);
ngModel.$render();
}
// return format result, 改變 $modelValue
return result;
} else {
return value;
}
}
// 檢查 input string 是不是 number string
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
}
}
});
結合昨天跟今天的範例,可以製作出有使用者體驗比較好的 input.
範例:只能輸入英文並會自動把英文小寫轉成英文大寫
http://plnkr.co/edit/uTpNzsj2biAC9qkxsn0K?p=preview
angular.module('myExample')
.directive('upperValidation', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) return;
// uppercase and number only
var regex = new RegExp('^[A-Z0-9\s]*$');
// check user input
ngModelCtrl.$formatters.unshift(function (value) {
return checker(value);
});
// check model change by code
ngModelCtrl.$parsers.unshift(function (value) {
var upperValue = checker(value);
element.val(upperValue);
// 檢查是否 viewValue 已經變成 uppercase 了,如沒有,重新 render 一次
if(upperValue !== value) {
ngModelCtrl.$setViewValue(upperValue);
ngModelCtrl.$render();
}
return upperValue;
});
function checker (value) {
var valid = regex.test(value);
ngModelCtrl.$setValidity('upperMatch', valid);
return value ? value.toUpperCase() : '';
}
}
}
}).directive('match', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
match: '=match'
},
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.unshift(function(value) {
return checker(value);
});
scope.$watch('match', function () {
// check match value with current value in input
checker(ngModelCtrl.$viewValue);
});
function checker (value) {
var valid = scope.match === value;
ngModelCtrl.$setValidity('match', valid);
// return value anyway, make sure valid is true/not true
return value;
}
}
}
});
;
總結一下:
ngModelController 提供的 Methods:
$formatters: 檢查當 model 值被程式的改變時候
$parsers: 檢查使用者輸入的 value
$setValidity: 設定 input 是否 valid
Properties:
$viewValue: String type,顯示給使用者的值
$modelValue: model controller 綁定的值。不一定是 string type,而是我們指定的格式。
ngModelController 呼叫 Methods 的順序:
$formatters: (當程式改變 model)
$modelValue -> $formatters -> $viewValue -> $render
$parsers: (當使用者改變 value)
$modelValue <- $parsers <- $viewValue <- $setViewValue
注意:在 $parsers 中 $setValidity set false 的時候, $modelValue 變成 undefined. (註一)
我覺得 validation 還有更多可以發掘的用法,如果有任何想法的,歡迎留言一起討論喔!
(*註一) 當我在研究過程中,發現 AngularJS 1.3.x 有新增 $$invalidModelValue Property 跟 $validators Method。
$$invalidModelValue 是當 ngModelController validity false 的時候,會把 invalid 的值儲存在 $$invalidModelValue property,並把$modelValue 設成 undefined。
$validators: object ,取代原本的 $setValidity method
我還沒有詳細的研究,有興趣的朋友可以看看這篇範例。
[http://stackoverflow.com/a/25488071](http://stackoverflow.com/a/25488071" style="font-family: sans-serif, Arial, Verdana, 'Trebuchet MS'; line-height: 1.6;)
AngularJS Forms Validation 介紹系列文:
AngularJS Forms Validation 介紹
自己的 input 自己 validation
自己的 input 自己 format (本篇)