Search code examples
javascriptangularjsng-maxlength

Does AngularJS store a value in the $error.maxlength object?


I've got a UI page setup through Angular, and I'm trying to take advantage of the built in ng-maxlength validator on an input element. Long story short, I know about $scope.form.$error and how that object has a maxlength property in the case that the validation fails. But I want to display an error message specific to the character length that was violated, and I don't see anywhere that the length that I specified was stored on this object. Does anyone know if it's possible to access this, so I don't have to write out a separate error message for each input that has the max length violated?


Solution

  • EDIT: To answer your question, yes angular does store a boolean value in the $error object that is accessible to your via the key(s) that are set in the object. In the case of the code I provided below and in th jsFiddle, we are setting the key for angular, and the value of either true or false.

    Be mindful when setting the value as it is reversed. ex. $setValidity( true ), flips the $error to false.

    Ok, here is what I think you were looking for...

    In Angularjs v1.2.13 you will not have access to ng-message or the $validator pipeline, which is why are are using $formatters and $parsers.

    In this case, I am using named inputs, but perhaps in your case you need dynamic input names?

    Plus, if you are using inputs but no form, then getting the error message to display would have to be done with a separate custom directive.

    If so, then please look here for dynamically named input fields for some help.

    dynamic input name in Angularjs link

    Let me know if this works; I'll make changes as needed to HOOK YOU UP!

    In case you don't know, you can write over Angular's maxlength for each individual input.

    If you changed 'maxlength' in the updateValidity() function in the directive below, to something like 'butter', then $scope.form.inputname.$error would be something like

    $scope.formname.inputname.$error { butter: true }
    
    if you also used ng-maxlength="true", then it would be
    $scope.formname.inputname.$error { butter: true, maxlength: true }
    
    Another example if you used ng-maxlength, and capitalized the 'maxlength' in the directive to 'Maxlength'
    
    Then you would get 
    $scope.formname.inputname.$error { maxlength: true(angular maxlength), Maxlength: true(your maxlength)
    
    And of course if you name it the same, then yours writes over angulars
    $scope.formname.inputname.$error { maxlength: true };
    

    The point is YOU can add your own names to the angular $error object; you can write over Angular's; and you can just use what Angular gives you when you use Angular's directives: like ng-required="true", or ng-maxlength="true"

    Link to YOUR angularjs version on jsFiddle jsFiddle LInk

    <div ng-app="myApp">
      <form name="myForm">
        <div ng-controller="MyCtrl">
          <br>
          <label>Input #1</label>
          <br>
          <input ng-model="field.myName" name='myName' my-custom-length="8" />
          <span ng-show="myForm.myName.$error.maxlength">
            Max length exceeded by {{ myForm.myName.maxlength }}
          </span>
          <br>
          <br>
          <label>Input #2</label>
          <br>
          <input ng-model="field.myEmail" name='myEmail' my-custom-length="3" />
          <span ng-show="myForm.myEmail.$error.maxlength">
            Max length exceeded by {{ myForm.myEmail.maxlength }}
          </span>
        </div>
      </form>
    </div>
    
    
    var app = angular.module('myApp', []);
    
    app.controller('MyCtrl', function ($scope) {
      $scope.field = {};
    });
    
    app.directive("myCustomLength", function () {
    
      return {
        restrict: 'A',
        require: 'ngModel',
    
        link: function (scope, element, attrs, ctrl) {
          if (!ctrl) { return } // ignore if no ngModel controller
    
          ctrl.$formatters.push(validateInput);
          ctrl.$parsers.unshift(validateInput);
    
          function validateInput(value) {
            if (!value) {
              updateValidity(false);
              return;
            }
            inputLength(value);
            var state = value.length > attrs.myCustomLength;
            updateValidity(state);
          }
    
          function inputLength(value) {
            ctrl.maxlength = null;
            var length = value.length > attrs.myCustomLength;
            if (length) {
              ctrl.maxlength = (value.length - attrs.myCustomLength).toString();
            }
          }
    
          function updateValidity(state) {
            ctrl.$setValidity('maxlength', !state);
          }
        } // end link
      } // end return
    });
    

    CSS Here if you need it.

    input.ng-invalid {
      border: 3px solid red !important;
    }