<!DOCTYPE html>
<html ng-app='exampleModule'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<form name="form">
<p>The two inputs below have <strong>ng-maxlength="5"</strong></p>
<hr/>
<p>With the <strong>validity-bind-fix</strong> directive <input type="text" ng-model="bar" validity-bind-fix ng-maxlength="5" /></p>
<p>Model value: {{bar}}</p>
<hr/>
<p>Without the directive: <input type="text" ng-model="foo" ng-maxlength="5" /></p>
<p>Model value: {{foo}}</p>
<hr/>
<p>Click this button to set invalid model values <button ng-click="invalidate()">"1234567890"</button></p>
</form>
</body>
</html>
angular.module('exampleModule', ['cxForm'])
.controller('MainCtrl', ['$scope', function ($scope) {
$scope.foo = 'abcdef';
$scope.bar = 'abcdef';
$scope.invalidate = function() {
$scope.foo = '1234567890';
$scope.bar = '1234567890';
};
}]);
/**
* @ngdoc cxForm
* @name cxForm
* @description
* Form add-ons and fixes
*/
angular.module('cxForm', [])
/**
* @ngdoc directive
* @name validityBindFix
* @module cxForm
*
* @description
* Prevents ngModelController from nulling the model value when it's set invalid by some rule.
* Works in both directions, making sure an invalid model value is copied into the view value and making sure an invalid
* model value is copied into the model. **Warning:** totally bypasses formatters/parsers when invalid, but probably good
* enough to use in most cases, like maxlength or pattern.
*
* See angular issue: https://github.com/angular/angular.js/issues/1412
*
* Inspired by the strategy provided by Emil van Galen here:
* http://blog.jdriven.com/2013/09/how-angularjs-directives-renders-model-value-and-parses-user-input/
*
* @restrict A
* @scope
*
* @param {object} ngModel Required `ng-model` value. If not present in the same element an error occurs.
*/
.directive('validityBindFix', function () {
'use strict';
return {
require: '?ngModel',
priority: 9999,
restrict: 'A',
link: function ($scope, $element, $attrs, ngModelController) {
ngModelController.$formatters.unshift(function (value) {
if (ngModelController.$invalid && angular.isUndefined(value)) {
return ngModelController.$modelValue;
} else {
return value;
}
});
ngModelController.$parsers.push(function (value) {
if (ngModelController.$invalid && angular.isUndefined(value)) {
return ngModelController.$viewValue;
} else {
return value;
}
});
}
};
});
/* Styles go here */
form {
padding: 10px;
border: 1px solid black;
}
input.ng-invalid {
border: 1px solid red;
}