[Guide] 9_Angular Form
input, select, textarea는 사용자의 데이터의 입력을 위한 엘리먼트입니다. Angular는 이 핵심기능을 한곳에 모아서 다양한 기능을 제공하고 있습니다.
사용자가 입력하는 데이터의 검증을 프레임워크에서 제공해줘서 조금 더 좋은 사용자 환경은 물론 개발자에게도 개발의 편의를 제공하고 있습니다.
Simple form
ngModel을 통해 directive의 핵심인 양방향 데이터 바인딩을 이해할수있습니다. ngModel의 경우에는 양방향 데이터 바인딩을 통해서 view와 모델간의 데이터의 일관성을 유지하고 있습니다.
index.html Name: E-mail: Gender: male female form = {{user | json}} master = {{master | json}}
$scope.update = function(user) { $scope.master = angular.copy(user); };
$scope.reset = function() { $scope.user = angular.copy($scope.master); };
$scope.reset(); }]);
novalidate를 통해서 브라우저 자체의 검증기능을 제거했습니다. 위의 폼에서 이메일의 경우에는 이메일의 폼에 어긋날경우 실제 데이터로 인식을 하지않습니다.
Using CSS classes
css 클래스를 ngModel에 추가하여 form을 꾸미는것을 허용합니다.
ng-valid: 모델이 유효한 경우
ng-invalid: 모델이 유요하지 않은 경우
ng-valid-[key]: 유효한 key값은 $setValidity 를 통해 설정됩니다.
ng-invalid-[key]: 유효하지 않은 key값은 $setValidity 를 통해 설정됩니다.
ng-pristine: 사용자의 입력이 받기전의 상태
ng-dirty: 사용자의 입력이 들오왔던 경우
ng-touched: 사용자의 입력이 막 마친경우
ng-untouched: 사용자의 입력이 아직 마치지 않은 상태
ng-pending: 어떠한 $asyncValidators 가 만족되지 않은 경우
index.html Name: E-mail: Gender: male female
.css-form input.ng-valid.ng-touched { background-color: #78FA89; }
$scope.update = function(user) { $scope.master = angular.copy(user); };
$scope.reset = function() { $scope.user = angular.copy($scope.master); };
$scope.reset(); }]);
위의 코드는 해당폼의 값을 검증하는데 있어서 CSS를 통해 더욱 풍부하게 정보를 전달하게끔 하고 있습니다.
Binding to form and control state
form은 FormController의 인스턴스 입니다. form 인스턴스는 선택적으로 scope상의 name속성을 통해서 보이게끔 할수가 있습니다.
이와 유사하게 input의 경우에는 ngModel directive를 통해 NgModelController의 인스턴스를 가지고 있습니다. 그래서 input은 name 속성을 사용해서 input을 컨트롤할 수 가 있습니다.
코드를 통해서 더 이해를 쉽게 해보겠습니다.
index.html
Name: Tell us your name.
E-mail: Tell us your email. This is not a valid email.
Gender: male female
I agree: Please agree and sign.
app.js
angular.module('formExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.master = {};
$scope.update = function(user) { $scope.master = angular.copy(user); };
$scope.reset = function(form) { if (form) { form.$setPristine(); form.$setUntouched(); } $scope.user = angular.copy($scope.master); }; $scope.reset(); }]);
코드상의 input들의 name속성을 이용해서 폼안에서 다양한 표현들이 가능합니다. 당연히 해당 scope내에서입니다.
Custom model update triggers
ngModelOptions를 통해서 우리는 특정 행동에 우리가 원하는 기능들을 추가 할수가 있습니다.
예를들면 ng-model-options = "{updateOn : 'blur'}" 를 통해서 보통을 입력시 곧장 변경사항이 적용이 되지만 이경우에는 사용자의 포커스가 아웃이 되면 그때 변경된 내용이 적용이 됩니다.
Name: Other data: username = "{{user.name}}" userdata = "{{user.data}}"
angular.module('customTriggerExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.user = {}; }]);
Non-immediate (debounced) model updates
모델의 update/validation에 대해서 ngModelOptions의 debounce 키를 통해 딜레이를 줄수가 있습니다.
ndex.html Name: username = "{{user.name}}"
app.js angular.module('debounceExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.user = {}; }]);
조금 더 복잡하게 설정이 가능합니다.
ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"
Custom Validation
기본적으로 Angular는 대부분의 HTML5의 input타입(text, number, url, email, date, radio, checkbox)을 적용하고 있고 몇몇 directive(required, pattern, minlength, maxlength, min, max)를 통해서도 값 검증기능을 제공하고 있습니다.
물론 ngModelController의 $validators 객체를 통해서 우리가 원하는 값을 검체증하는 함수를 만들수도 있습니다. 예제를 가지고 이야기 해보도록 하갰습니다.
index.html Size (integer 0 - 10): {{size}} The value is not a valid integer! The value must be in range 0 to 10!
Username: {{name}} Checking if this name is available... This username is already taken!
app.js var app = angular.module('form-example1', []);
var INTEGER_REGEXP = /^\-?\d+$/; app.directive('integer', function() { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { ctrl.$validators.integer = function(modelValue, viewValue) { if (ctrl.$isEmpty(modelValue)) { // consider empty models to be valid return true; }
if (INTEGER_REGEXP.test(viewValue)) { // it is valid return true; }
// it is invalid return false; }; } }; });
app.directive('username', function($q, $timeout) { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
ctrl.$asyncValidators.username = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) { // consider empty model valid return $q.when(); }
var def = $q.defer();
$timeout(function() { // Mock a delayed response if (usernames.indexOf(modelValue) === -1) { // The username is available def.resolve(); } else { def.reject(); }
}, 2000);
return def.promise; }; } }; });
위의 예제는 integer와 username을 검증하는 directive를 만들었습니다.
우선 각각의 함수는 인자로 modelValue와 viewValue를 받았습니다. 그리고 Angular는 내부에서 $setValidity를 호출하고 함수는 (true : valid, false : invalid)식으로 값을 리턴할것입니다.
값을 검증하는 이 함수들은 input창의 값들이 변하면, 다른 말로 $setValidity가 호출이 될때마다 실행이 될것입니다. 아니면 모델이 변경되는 것을 보고 확인할수도 있습니다.
각각의 검증은 $parse와 $formatters가 성공적으로 동작을 하면 검증을 무사히 진행을 한 경우입니다. 만약에 실패를 한다믄 ngModelController.$error에 실패한 키 값이 저장이 될것입니다.
추가적으로 $asyncValidators객채가 있는데 이는 비동기적으로 값을 체크를 합니다. 아마 우리는 $http를 사용하는 시점에 매우 용이하게 사용할수가 있겠지요? 검증을 하고 promise를 통해 성공적으로 검증이 이뤄졌다면 resolved, 만약 실패를 했다면 rejected를 리턴할것입니다. 이때 우리가 검증에 필요한 키는 ngModelController.$pending에 저장을 해두고 있습니다.
Modifying build-in validators
Angular는 자체적으로 $validators를 사용하고 있으므로 우리는 손쉽게 내부적으로 이미 구현된 validators 를 대체하거나 제거할수 있습니다. 이번의 예제는 Angualr가 기본적으로 제공을 해주는 email검증 기능을 다르게 정의 해보겠습니다.
index.html Overwritten Email: This email format is invalid! Model: {{myEmail}}
app.js var app = angular.module('form-example-modify-validators', []);
app.directive('overwriteEmail', function() { var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;
return { require: 'ngModel', restrict: '', link: function(scope, elm, attrs, ctrl) { // only apply the validator if ngModel is present and Angular has added the email validator if (ctrl && ctrl.$validators.email) {
// this will overwrite the default Angular email validator ctrl.$validators.email = function(modelValue) { return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue); }; } } }; });
오직 XXX#example.com 이라는 이름의 메일만이 우리의 검증과정에서 통과가 가능할것입니다.
Implementing custom from controls(Using ngModel)
Angular는 기본적으로 HTML기본 form(input, select, textarea)를 통한 검증으로 대부분의 경우를 효과적으로 컨트롤 하합니다. 그리고 당연히 우리가 원하는 방식으로 해당 기능의 변경도 얼마든지 가능합니다.
이번에는 우리가 ngModel과 양방향 데이터 바인딩을 이용해 새로운 입력형태를 만들어 보겠습니다.
index,html Some model = {{content}}
div[contentEditable] { cursor: pointer; background-color: #D0D0D0; }
app.js angular.module('form-example2', []).directive('contenteditable', function() { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { // view -> model elm.on('blur', function() { scope.$apply(function() { ctrl.$setViewValue(elm.html()); }); });
// model -> view ctrl.$render = function() { elm.html(ctrl.$viewValue); };
// load init value from DOM ctrl.$setViewValue(elm.html()); }영 }; });
사용자 지정 컨트롤러가 동작하기 위해서는 ng-model과 함께 동작을 해야하고 양방향 데이터 바인딩이 이뤄저야 합니다. 이를 위해서
$render메서드를 통해 NgModelController.$formatters 가 전달하는 데이터를 렌더링 시켜줘야합니다.
$setviewValue 메서드를 통해서 언제든지 사용자의 인터렉션을 모델에 반영시켜 줘야합니다.
좀더 자세한 내용은 https://docs.angularjs.org/guide/directive 을 통해서 확인 가능합니다.
from http://yubylab.tistory.com/74 by ccl(A) rewrite - 2020-03-06 15:20:42
댓글
댓글 쓰기