Reputation: 1879
I'm writing a directive to enforce maxlength on a textarea field (HTML version < 5). I'm using AngularJS. As such, I want to get it done in a correct AngularJS manner. However, when I do it "Angularesque" as I perceive it, I can't quite get it to work completely.
(function () {
'use strict';
var myAppModule = angular.module('myApp', []);
myAppModule.controller('MyController', function($scope) {
$scope.textareaText = "";
});
myAppModule.directive('myMaxlength', ['$compile', '$log', function($compile, $log) {
return {
priority: 10000,
restrict: 'A',
require: 'ngModel',
compile: function (elem, attrs) {
elem.attr("ng-trim", "false");
return function(scope, linkElem, linkAttrs, ctrl) {
var maxlength = parseInt(linkAttrs.myMaxlength, 10);
ctrl.$parsers.push(function (value) {
$log.info("In parser function value = [" + value + "].");
if (value.length > maxlength)
{
$log.info("The value [" + value + "] is too long!");
value = value.substr(0, maxlength);
ctrl.$setViewValue(value);
ctrl.$render();
$log.info("The value is now truncated as [" + value + "].");
}
return value;
});
};
}
};
}]);
})();
This nearly works (see the JSFIDDLE here Note: This fiddle has since been updated with the chosen solution below, but the code above still exhibits the problem noted here.). It correctly limits characters going to the model, and renders that back to the display. However, you can continue to enter spaces to exceed the specified maxlength. The extra spaces don't get into the model, but they clutter the display. I believe this has something to do with ng-trim. As you can see (in the code snippet) I'm setting the attribute in the compile function, but it's too late by then. Some suggest manually calling compile within your compile function to force AngularJS to recognize the dynamically-added attribute, but that "appears" to create another copy and doesn't fix the display problem. Putting ng-trim="false"
on the textarea element works, but I want a clean solution where all the user needs to do is add one attribute specifying the max length.
Here is another example (see the JSFIDDLE here) that is not quite as "Angularesque" in my opinion but get's the job done.
(function () {
'use strict';
var myAppModule = angular.module('myApp', []);
myAppModule.controller('MyController', function($scope) {
$scope.textareaText = true;
});
myAppModule.directive('myMaxlength', ['$log', function($log) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var maxlength = parseInt(attrs.myMaxlength, 10);
$log.info("maxlength=[" + maxlength + "]");
elem.bind('keydown', function (event) {
$log.info("elem.val().length=[" + elem.val().length + "]");
if (elem.val().length >= maxlength)
{
// Void event Except backspace
if (event.keyCode != 8){
event.preventDefault();
}
}
});
}
};
}]);
})();
So, what's a truly "Angularesque" way to implement maxlength on a textarea field? Thank you in advance!
Upvotes: 3
Views: 821
Reputation: 11547
You could use $attr.$set()
(see doc) to add the ng-trim
attribute in a way that ngModel
would recognize.
Change this line of your code in the compile function:
elem.attr("ng-trim", "false");
to this:
attrs.$set("ngTrim", "false");
Note: Remember to change the attribute value to camelCase!
You can also do it in a link function (no need for the compile function):
linkAttrs.$set("ngTrim", "false");
jsfiddle: http://jsfiddle.net/J7MJF/7/
Upvotes: 2
Reputation: 260
You can use ngMaxlength argument on an input field in your html file (documentation here: https://docs.angularjs.org/api/ng/directive/input)
For example
<input type="text" ng-model="myRestrictedText" ng-maxlength="10"/>
Upvotes: 3