或是某個欄位AngularJS並沒有實作Validation時(例如input type="file"),
就需要自訂有客製化驗證能力的directive
在這邊的需求如下:
- 製作一個directive,名稱為file-validator
- 配合input type="file"使用
- 可以設定file size(大小,單位Byte)和file type(副檔名), 用法範例:
- 如果fileSize沒指定或小於等於0,則不對fileSize做限制驗證。
- 如果fileType沒指定或為空字串,則不對fileType做限制驗證。
說明:
- 當我們在ng-form裡面的input設置name及ng-model (及ngModelController)後,如果AngularJS有實作此種input type類型的話,Angular會在View中的值或對應model的
值改變時,進行View及model的雙向挷定、同時變更。
ngModelController裡面會存放model的值,即ngModel.$modelValue。
也會存放view(通常為input type中顯示的值),即ngModel.$viewValue。
並且也會管理此input的valid狀態。
但因為AngularJS並沒有對input type="file"進行實作,也就是,不管User在input中選了什麼檔案,皆不會存值到ngModel.$modelValue及ngModel.$viewValue中,當然雙向挷定的model中也不會有值。
所以為們要帶自制的directive中,指定
required : ngModel
來得到管理這個input的ngModel,並且手動的設定model的值。
(!!不要手動用ngModel.$setViewValue()設定viewValue的值,會導致model value 會被蓋掉) - 因為要設定model的值,所以我們要引入$parse,$parse(code)可以代入一串程式碼,有點
像eval,$parse(code)會返回一個函式,並且此函式有一個函式,assign(scope, value),
可以在scope中執行程式碼,並將value賦值給程式碼執行得到的變數。
例如:
$parse("myCtrl.fileUpload").assign(scope, file);
代表在scope中執行 : myCtrl.fileUpload = file; - 在ngModel中,可以使用
ngModel.$setValidity( validType, isValid)
來設定此input的validType是valid還是invalid。 - 在解析如以下字串時,
file-validator="fileType:'png'; fileSize:333;"
我們使用了兩個正規表達式:
fileSize\s*:\s*(\d+)\s;
fileType\s*:\s*(["'])(\w+)\1\s*;
其中第二個正規達式中的 \1 的意思是跟第一個Group相匹配,而第一個Group就是(["']),
也就是fileType:"png"; 或 fileType: 'png';可以匹配,但
fileType:'png"; 或 fileType:"png'; 不可以匹配,
雙引號及單引號要成對使用。
原碼紀錄(怕jsFiddle出問題):
使用angular.js
html:
javascript:
請選擇size小於3MB的PNG檔案
file valid: {{myForm.fileUpload.$valid}}file size (Byte): {{myCtrl.fileUpload.size}}副檔名錯誤檔案過大
javascript:
var myApp = angular.module("myApp", []); myApp.controller("myController", [function() { // }]); //自製的file validator myApp.directive('fileValidator', ["$parse", function($parse) { return { restrict: 'A', scope: true, require: 'ngModel', //代表管理input type="file"這個input的ngModelController,例如此例 //ngModel.name = "fileUpload", //可以連結ng-model裡指定的變數值(ngModel.modelValue) 和 //input view欄位中顯示的值(ngModel.viewValue) link: function(scope, elm, attrs, ngModel) { var expression = attrs.fileValidator; var fileSizeReg = /fileSize:\s*(\d+)\s*;/; var fileTypeReg = /fileType\s*:\s*(["'])(\w+)\1\s*;/; //規定file的size,單位Byte var fileSizeLimit = fileSizeReg.exec(expression)[1] || 0; //規定副檔名 var fileTypeLimit = fileTypeReg.exec(expression)[2] || ""; elm.bind('change', function() { //發現input type file值改變時 scope.$apply(function() { var file = elm[0].files[0]; //取得file資料 var fileType = /.+\.(.+)/.exec(file.name)[1]; //$parse("程式碼")可以返回一個function,之後可以用這個function的 //assign(scope, value)來在scope中進行賦值(value)動作, //例如: 在scope中墸行: 程式碼 = value (有點像eval()) $parse(attrs.ngModel).assign(scope, file); //檢查file副檔名及size //用ngModel設置fileSize的valid if (fileTypeLimit === "" || fileType === fileTypeLimit) { ngModel.$setValidity("fileType", true); } else { ngModel.$setValidity("fileType", false); } //用ngModel設置fileSize的invalid if (fileSizeLimit <= 0 || file.size < fileSizeLimit) { ngModel.$setValidity("fileSize", true); } else { ngModel.$setValidity("fileSize", false); } }); }); } }; }]);
沒有留言 :
張貼留言