Issue
I wish to create a custom directive, which renders as an input type element. The directive should reuse the angularjs validation framework. Following is the custom-input
directive in action which I have created:
<!doctype html>
<html ng-app="validationApp">
<body>
<div class="container" ng-controller="ValidationController as validationController">
<form name="myForm">
{{employee | json}}
<custom-input ng-required="true" ng-model="employee.name" name="employee.name" id="employeeName" ng-pattern="/^[0-9]{1,7}$/"/></custom-input>
<span ng-show="myForm['employee.name'].$error.required">This is a required field</span>
<span ng-show="myForm['employee.name'].$error.pattern">This is a invalid field</span>
</form>
</div>
<script type="text/ng-template" id="/templates/customInput.html">
<div>
<input type="text" name="{{name}}" ng-model="newInput" id="{{id}}">
</div>
</script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script>
</body>
</html>
The javascript corresponding to this is:
angular.module('validationApp', [])
.controller("ValidationController", function(){
})
.directive("customInput", function(){
return {
restrict: "E",
require : "ngModel",
replace: "true",
templateUrl : "/templates/customInput.html",
scope : {
id : "@", //bind id to scope
name : "@" //bind name to scope
},
link: function(scope, element, attrs, ngModelCtrl){
//When newInput is updated, update the model of original input
scope.$watch('newInput', function(newValue){
ngModelCtrl.$setViewValue(newValue);
});
//On first load, get the initial value of original input's model and assign it to new input's model
ngModelCtrl.$render = function(){
var viewValue = ngModelCtrl.$viewValue;
if(viewValue){
scope.newInput = viewValue;
}
}
}
}
});
I am trying to apply ng-required
and ng-pattern
validation on this custom-input. I am running into two problems:
- In angularjs 1.2.6, I am able to fire
ng-required
validation in thecustom-input
but in 1.3.0, the validation is not getting fired. - I am unable to fire
ng-pattern
validation in both versions.
My understanding is that $setViewValue
of ngModelController
will fire all the validations. The above is a contrived example, my actual use case is to create a custom directive which renders three input boxes for SSN.
Following is the plunker link for 1.2.6 and 1.3.0 respectively:
Angularjs 1.2.6
Angularjs 1.3.0
Solution
-
To get the
ng-required
to work, don’t have the same name on the input of the inner input form. I appears that in Angular 1.3, this overrides the registeredngModelController
attached to yourcustom-input
.So the template for the directive can be
<div> <input type="text" ng-model="newInput" id="{{id}}"> </div>
This can be seen working at http://plnkr.co/edit/TqMkxV?p=preview.
(Also, not sure why you need id here…)
-
I think (but I’m not sure) in 1.2.6
ngPattern
only works oninput
elements, while in 1.3 it’s a separate directive that integrates with ngModel. Also, to get it to work in 1.3- Use
pattern
instead ofng-pattern
, even though the docs suggestng-pattern
should work. -
If you’re writing the pattern directly in the template, don’t wrap it in
/
…/
. So a correct use of it looking for exactly 5 digits would bepattern="^\d{5}$"
. The docs are misleading in this.Your modified 1.3 example, with a working example of
pattern
can be seen at http://plnkr.co/edit/1zSiJI?p=preview
- Use
Edit after comments:
-
If you do want the name to appear on the inner directive, and be the same as the parent elements name (e.g. for submitting using standard full page POST to server), you can wrap it in a named
ngForm
. This will ensure that its controller won’t override the parent one in the scope.<div> <div ng-form name="customInput"> <input type="text" ng-model="newInput" id="{{id}}" name="{{name}}"> </div> </div>
This can be seen at http://plnkr.co/edit/Jrk63A?p=preview
Answered By – Michal Charemza
Answer Checked By – Terry (AngularFixing Volunteer)