How prevent angular auto trim for fields?

Is there any way prevent angular from auto trim for fields in the whole application? I know that I can prevent it for specified field using ngTrim directive, but it doesn't look good add this directive to all text fields in the application, is there any way do it for all fields in the angular module? Here is code, if you add add spaces in the begin of input they will not appear in label:

<div ng-app>
  <div ng-controller="TodoCtrl">
      {{field}}
    <input type="text" ng-model="field">
  </div>
</div>

Answers:

Answer

You can extend input[text] directive, the code below will automatically change the value of the attribute ngTrim to false:

.directive('input', function($compile){
    // Runs during compile
    return {
      link(scope, iElement, iAttrs) {
        if (iElement.attr('type') === 'text') {
          iAttrs.$set('ngTrim', "false");
        }
      }
    };
});

Reference: https://docs.angularjs.org/api/ng/type/$compile.directive.Attributes

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-text-input-directive</title>
  

  <script src="https://docs.angularjs.org/angular.min.js"></script>
  

  
</head>
<body ng-app="textInputExample">
  <script>
  angular.module('textInputExample', [])
    .controller('ExampleController', ['$scope', function($scope) {
      $scope.example = {
        text: 'guest'
      };
    }])
    .directive('input', function($compile){
    	// Runs during compile
    	return {
    	  link(scope, iElement, iAttrs) {
    	    if (iElement.attr('type') === 'text') {
    	      iAttrs.$set('ngTrim', "false");
    	    }
    	  }
    	};
    });
</script>
<form name="myForm" ng-controller="ExampleController">
  <label>Single word:
    <input type="text" name="input" ng-model="example.text" required>
  </label>
  <div role="alert">
    <span class="error" ng-show="myForm.input.$error.required">
      Required!</span>
    <span class="error" ng-show="myForm.input.$error.pattern">
      Single word only!</span>
  </div>
  <tt>text = {{example.text}} - 3</tt><br/>
  <tt>text = {{example.text.length}} - 3</tt><br/>
  <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
  <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
  <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
 </form>
</body>
</html>

EDIT:

How it works

1) You can bind multiple directives to the same html element and they can share the same $scope and $attributes.

2) iAttrs.$set('ngTrim', "false"); is updating the attribute ng-trim. You can't do this using normal dom manipulation because the dom is already compiled (https://docs.angularjs.org/api/ng/service/$compile)

3) Calling iAttrs.$set will trigger updates on all directives, so it will override the original ng-trim attribute value.

Answer

Another way to extend the input directive (or any directive/service, for that matter) is by using a decorator:

app.config(function($provide) {
  $provide.decorator('inputDirective', function($delegate) {
    var directive = $delegate[0],
        link = directive.link;

    link.post = function(scope, element, attrs) {
      attrs.$set('ngTrim', 'false');
    };

    return $delegate;
  });
});

Working Plunker

I personally prefer this approach because it allows me to execute the directive's original code, if needed. In this particular case that isn't necessary because the input directive has no link function, so you can simply provide your own without worrying about breaking anything.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.