4
\$\begingroup\$

I am trying to implement an AngularJS directive that would count the number of characters entered into a textarea and display it to the user.

Note: it will actually become much more complex later on and will become a full-fledged component that will be similar to the js component used by Stack Overflow for user comments: users will be notified how many more characters they may or must enter with different font colors.

Here is how the markup would look for the initial version:

<div ng-app>
    <div ng-controller="myController">
       <cmp>
         <enhanced-textarea ng-model="name"></enhanced-textarea>
         <h3>{{name}}</h3>
         <notice></notice>           
       <cmp>
     </div>
</div>

My js code is as follows:

var myModule = angular.module('myModule', []);
myModule.directive('cmp', function(){
    return {
        restrict: 'E',
        controller: 'cmpCtrl',
        replace: true,
        transclude: true,
        scope: {
            name: '='
        },
        template: '<div ng-transclude></div>'
    };
})
.controller('cmpCtrl', function ($scope, $element, $attrs) {
   $scope.$parent.$watch('name', function(newVal){
       if(newVal){
            $scope.$parent.updatedSize = newVal.length;
            console.log(newVal.length);  
       }
   }, true);
})
.directive('enhancedTextarea', function () {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<textarea ng-transclude></textarea>'
    };
})
.directive('notice', function () {
    return {
        restrict: 'E',
        require: '^cmp',
        replace: true,
        scope: {
            updatedSize: '='
        },
        template: '<div>{{size}}</div>',
        link: function($scope, $element, $attrs, cmpCtrl){
            console.log(cmpCtrl);
            $scope.$parent.$watch('updatedSize', function(newVal){
               if(newVal){
                  $scope.size = newVal;
               }
           }, true);
        }
    };
});

function myController($scope) {
    $scope.name = 'test';
};

I find it overly complex and I am sure it can be simplified.

Can anyone please advise and help perhaps by providing alternatives together with explanations?

Here is the fiddle

\$\endgroup\$
1
\$\begingroup\$

Massive overkill indeed,

<span>{{name.length}}</span>

will do the trick.

On the whole, I am not sure why you would use Angular to write an editor if you are not an expert in Angular. It adds a layer of complexity and eats into performance.

\$\endgroup\$
6
  • \$\begingroup\$ Thanks. Please take into account my note in italics. The directive will become much more complex with business logic in it... \$\endgroup\$ – balteo Feb 24 '14 at 20:40
  • \$\begingroup\$ @balteo We can only review what you submit, I would invite you to come back once the functionality is more complex. \$\endgroup\$ – konijn Feb 24 '14 at 20:43
  • \$\begingroup\$ Of course. No worries. I will do so. \$\endgroup\$ – balteo Feb 24 '14 at 20:51
  • 1
    \$\begingroup\$ "I am not sure why you would use Angular to write an editor if you are not an expert in Angular." I agree the solution is overkill, but the quoted sentiment is against the spirit of this site. He's posting it here because he's trying to learn angular and get better at it. \$\endgroup\$ – Jonah Feb 25 '14 at 8:05
  • \$\begingroup\$ @Jonah He is trying to write a complex editor, that's hard enough without throwing Angular in the mix. \$\endgroup\$ – konijn Feb 25 '14 at 13:19
0
\$\begingroup\$

You are using isolated scope, whose purpose is to encapsulate it from outside world, so best $scope.$parent is to be avoided, see here.

In your case, you two-way-bind with parent scope, so this should work just fine without breaking your encapsulation:

$scope.$watch('updatedSize', function(){});
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.