I'm creating an input directive that encapsulates a label, and some error messaging but I'm getting stuck with ng-minlength and ng-maxlength. The issue is that they don't populate the model value until it's a valid value, so my parent scope can display a value while my directive doesn't, and vice versa. View this plunk for an example of what I mean.
Is the only way around this to define my own minlength and maxlength validators? Is there some way configure this behaviour so the model is always populated? I want to use all the built in validators in my directive, so no doubt this will be an issue with all of them and I'd rather not redefine them all.
HTML:
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="Controller">
<label>Outer scope 1</label>
<input name="input1" type="text" ng-model="model1" ng-minlength="4"/>
<br/>
<label>Directive scope 1</label>
<input-dir ng-model="model1" ng-minlength="0"></input-dir>
<br/>
<br/>
<br/>
<label>Outer scope 2</label>
<input name="input3" type="text" ng-model="model2"/>
<br/>
<label>Directive scope 2</label>
<input-dir ng-model="model2" ng-minlength="4"></input-dir>
</body>
</html>
Javascript:
var app = angular.module('app', []);
app.controller('Controller', function($scope){
$scope.model1 = "Model1";
$scope.model2 = "Model2";
});
app.directive('inputDir', function(){
return {
restrict: 'E',
template: '<input type="text" ng-model="model" ng-minlength="{{ minlength }}" />',
scope: {
model: '=ngModel',
minlength: '=ngMinlength'
}
};
});
For anyone else with the same issue, I solved this by redefining all the validators, except now they return the value when invalid so the model is populated. Just include the valuedValidators module. These validators are available on the $error object as vvminlength etc.
vv-validators.js
(function () {
'use strict';
var validators = {};
validators.vvUrl = function(value){
var urlRegex = new RegExp(/[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi);
return urlRegex.test(value);
}
validators.vvEmail = function(value){
var emailRegex = new RegExp(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
return emailRegex.test(value);
}
validators.vvMinlength = function(value, min){
var huh = value.length >= parseInt(min);
return min && value && huh;
}
validators.vvMaxlength = function(value, max){
return max && value && value.length <= parseInt(max);
}
validators.vvMin = function (value, min) {
return min && parseFloat(value) >= parseFloat(min);
}
validators.vvMax = function (value, max) {
return max && parseFloat(value) <= parseFloat(max);
}
validators.vvPattern = function (value, pattern) {
return pattern && new RegExp(pattern).test(value);
}
validators.vvFloat = function (value) {
var floatRegex = new RegExp(/^\-?\d+((\.|\,)\d+)?$/);
return floatRegex.test(value);
}
validators.vvInteger = function (value) {
var integerRegex = new RegExp(/^\-?\d+$/);
return integerRegex.test(value);
}
var app = angular.module('valuedValidators', []);
var names = Object.keys(validators);
names.forEach(function(name){
app.directive(name, function(){
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, controller) {
controller.$parsers.unshift(function (viewValue) {
var valid = true;
var attrValue = attrs[name];
var func = validators[name];
if (attrValue !== 'false') {
valid = func(viewValue, attrValue);
controller.$setValidity(name.toLowerCase(), valid);
}
return viewValue;
});
}
};
});
});
}());