Compiling the element results in the position of the input position to move to the end

I have a directive problem. The goal of the directive is to easily add validation without having to manually add the ng class (by the way) to the elements to display the error state. I just want to put a "validation" directive on my element and create the appropriate classes (and error messages) when an error condition occurs.

As far as validation goes, it works great, but it has an odd side effect. Whenever I edit a value in an input field that has a validation directive on it, it moves the caret to the end of the text in the input field. It looks like I'm compiling an element (in this case, the parent that contains that element).

Here is a jsbin showing the problem. To reproduce, enter a value in the field, then place the carriage in the middle of the entered value and try another character. Note that it moves you to the end of the field. Note that if you delete the value, the field label turns red as expected to show a validation error (field required).

Here is the directive (from jsbin):

angular.module('app', [])
.directive('validation', function($compile) {
  return {
    require: 'ngModel',
    restrict: 'A',
    compile: function(compileElement, attrs) {
      var formName = compileElement[0].form.name;
      compileElement.removeAttr('validation');
      compileElement.parent().attr('ng-class', formName + "['" + attrs.name + "'].$invalid && " + formName + "['" + attrs.name + "'].$dirty ? 'error' : ''");

      return function(scope, element) {
        $compile(element.parent())(scope);
      }
    }
  };
});

      

And here is the html:

<html>
  <head>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
  </head>
  <body ng-app="app">
    <form name="subscribeForm">
    <label>
      First Name
      <input type="text" 
             id="firstName" 
             name="firstName" 
             ng-model="userInfo.FirstName" 
             required 
             validation/>
    </label>
    </form>
  </body>
</html>

      

+2


source to share


2 answers


Not sure if you figured this out, but I ran into a similar problem. found a solution on Preserving Cursor Position with Angular Values . for convenience, below is a snippet of a directive that would solve this problem.

app.directive('cleanInput', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      var el = element[0];

      function clean(x) {
        return x && x.toUpperCase().replace(/[^A-Z\d]/g, '');
      }

      ngModelController.$parsers.push(function(val) {
        var cleaned = clean(val);

        // Avoid infinite loop of $setViewValue <-> $parsers
        if (cleaned === val) return val;

        var start = el.selectionStart;
        var end = el.selectionEnd + cleaned.length - val.length;

        // element.val(cleaned) does not behave with
        // repeated invalid elements
        ngModelController.$setViewValue(cleaned);
        ngModelController.$render();

        el.setSelectionRange(start, end);
        return cleaned;
      });
    }
  }
});

      



The directive had a different purpose, although so change it to suit your requirements.

+1


source


If you are not using the inline model / validation process, you are doing it wrong. Check out the tutorial on the angular-js website:

http://code.angularjs.org/1.2.13/docs/guide/forms

In addition, you should not perform element manipulation at compile time.

Update



You need to look at the Custom Validation section .

Take an approach ctrl.$parsers

. You add your parser to the parser list and your fn will run anytime the model changes. Then you use ctrl.$setValidity('strNameOfValidation', true)

to set the validity. Angular will then add a class for you - .ng-valid-float

or .ng-invalid-float

.

var FLOAT_REGEXP = /^\-?\d+((\.|\,)\d+)?$/;
app.directive('smartFloat', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (FLOAT_REGEXP.test(viewValue)) {
          ctrl.$setValidity('float', true);
          return parseFloat(viewValue.replace(',', '.'));
        } else {
          ctrl.$setValidity('float', false);
          return undefined;
        }
      });
    }
  };
});

      

0


source







All Articles