KSev
KSev

Reputation: 1879

What's a truly "Angularesque" way to implement maxlength on a textarea field?

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

Answers (2)

runTarm
runTarm

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

emiidee
emiidee

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

Related Questions