2

I am creating a directive that adds a template with text type input to the view. In this directive, I am trying to add the span class for error notification if the text field input is more than max length setting provided. I have a code something like this:

<div ng-app="app">
<form name="userForm" ng-submit="processForm()" novalidate>
    <div use-text-box name="xyz" ng-maxlength="10" required> </div>

    <button type="submit" class="btn btn-success">Submit</button>
</form>
</div>   

My Directive like this:

var app = angular.module('app', []);

app.directive('useTextBox', function() {

              return {
                  replace:true,
                  compile: function(element,attrs) {

                        var name =  attrs.name;

                        var maxLengthError = attrs.hasOwnProperty('ngMaxlength') ? '<span ng-show="userForm.' + attrs.name + '.$error.maxlength" class="help-block">Text is too long. The limit is ' + attrs.ngMaxlength + ' characters.</span>' : '';

                        var htmlText = '<input type="text" name="' + name + '" ng-maxlength="' + attrs.ngMaxlength + '" required />' + 
                                            maxLengthError;

                        element.replaceWith(htmlText);

                }
              };
});

But in the above code, the directive is generating the input text field etc.. without a problem. However, it is not showing the error message if the max length is more than 10. What am I doing wrong?

Here is the link to the jsfiddle for the above example: http://jsfiddle.net/fB45J/3/

6
  • jsFiddle says invalidError is not defined. did you test it? Commented Mar 24, 2014 at 13:13
  • sorry... I had another variable invalidError before and I forgot to delete that from htmlText when I removed it. I have updated jsfiddle now. But that wasnt the reason why the error validation is not showing. I havent figured out why the validation aint working yet. Commented Mar 24, 2014 at 13:17
  • There's all sorts of problems with this directive. First off if you're going to insert HTML code into the DOM using element.replaceWith or element.html you need to compile it first with $compile and the correct scope. Second, there's no need to use the directive's compile property and the compile property should return an object with two function for pre and post directive linking. Commented Mar 24, 2014 at 13:40
  • I actually got this idea from @Misko Hevery post here: stackoverflow.com/a/10646761/1050957 Commented Mar 24, 2014 at 13:47
  • @m.e.conroy Would you be able to show an example of how to do it right please? As a newbie I hugely rely on Visual example. :( Commented Mar 24, 2014 at 13:47

1 Answer 1

5

I don't know if you're just learning and trying to understand directives, but you don't even need a directive to accomplish what you want.

Here's a Fiddle without the directive: http://jsfiddle.net/mikeeconroy/fB45J/7/

<div ng-app="app">
    <ng-form name="userForm" novalidate role="form" ng-controller="myFormCtrl">
        <div>
            <p class="text-muted">Enter in some text then remove it.  You need to make it such that Angular sees the form as "dirty" and then tries validate the form.</p><br>
        </div>
        <div>
            <input type="text" name="xyz" ng-model="xyz" maxlength="10" required>
            <span ng-show="userForm.xyz.$dirty && userForm.xyz.$error.required && userForm.xyz.$invalid" style="color: #900;">This field is required!</span>
        </div>

        <br />   <br />  
        <button type="button" ng-click="processForm()" class="btn btn-success">Submit</button>
    </ng-form>
</div>

Here's the Angular. Its not doing anything much just showing how '$dirty' on a form element works.

var app = angular.module('app', []);
app.controller('myFormCtrl',function($scope,$element){
    $scope.form = $element.controller('form');
    $scope.processForm = function(){
        // set form to dirty
        $scope.form.xyz.$dirty = true;
        console.log('Processing!');
    };
});

EDIT: Here's the fix using your directive approach

http://jsfiddle.net/mikeeconroy/fB45J/8/

app.directive('useTextBox', function($compile,$timeout) {

          return {
              replace:true,
              scope: false,
              link: function(scope,element,attrs) {

                    var name =  attrs.name;

                    var maxLengthError = attrs.hasOwnProperty('ngMaxlength') ? '<span ng-show="userForm.' + attrs.name + '.$error.maxlength" class="help-block">The limit is ' + attrs.ngMaxlength + ' characters.</span>' : '';

                  var htmlText = '<div><input type="text" id="' + name + '" name="' + name + '" ng-maxlength="' + attrs.ngMaxlength + '" ng-model="test_' + attrs.name + '" required>' +   maxLengthError + '</div>';

                  $compile(htmlText)(scope,function(_element,_scope){
                    element.replaceWith(_element);
                  });

            } // end link
          };
});

You need to inject $compile into your directive and then use it to compile your HTML and insert it with the correct scope. _element will be the compiled new element.

$compile(htmlText)(scope,function(_element,_scope){
    element.replaceWith(_element);
});

EDIT: Here's another example using just the compile property of a directive

http://jsfiddle.net/mikeeconroy/dzP9L/1/

I guess it seems that the difference between your example and this one is the introduction of the form's controller.

Sign up to request clarification or add additional context in comments.

7 Comments

Reason for creating directive is, I am going to have similar fields in many different kind of forms. The only thing that changes are like the label, ng-model, maxlength, etc.. To avoid repetition of the same code, I find creating a directive with attributes to generate the template respectively seem like a better approach. The example I've shown in my post is a simplified one. The main issue I am having is $error.maxlength doesnt work when its from directive. But it works when I use in the form directly without using a directive. I cant understand why the directive validation is not working.
Yeah, i went back and tried to make your directive work, but it seems that the validation doesn't work on elements inserted into a form after the form controller has been created. I can't even get $dirty to work.
I figured it out, you have to get the form controller to recognize newly added elements after the form has been created. I'll post the fix in a minute.
@blackops_programmer editted this post with your directive fix.
You are right.. seems like a slow journey for me but once I understand how Angular separates the structure and the way they communicate with each other, its becoming so much more interesting and fun. I just checked out your blog and you have some awesome information and demos on angular. Love it!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.