1

I have a directive that I put in the input of type class. I add the blur, focus event to know when I entered and exit the input to make the effect of the label (Material Design), but when I wrap the value through the angular ng-model I need to know that the field was filled.

Any idea?

app.directive('formControl', function() {
  return {
    restrict: 'C',
    link: function (scope, element, attrs) {

      // Add class filled to form-control's that have a value
      if(element.val()){
        element.parent().addClass('filled');
      }

      // Any event here that can tell me that the value was changed by the angular so I can put the css class

      element.bind('blur', function (e) {
        input = angular.element(e.currentTarget);
        if(input.val()){
          input.parent().addClass('filled');
        } else {
          input.parent().removeClass('filled');
        }
        input.parent().removeClass('active');
      }).bind('focus', function (e) {
        input = angular.element(e.currentTarget);
        input.parent().addClass('active');
      });

    }
  };
});
2
  • As you suggested, you can fire an event when the input is updated. Commented Aug 23, 2017 at 22:57
  • Yes, or that when being updated by ng-model I know that this occurred to be able to add the css. Commented Aug 23, 2017 at 23:05

1 Answer 1

1

Instead of adding the filled class inside the bind, you can add a watcher and add the class. Please refer the below example. Using colors in the classes to represent them getting added.

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

app.controller('MyController', ['$scope', MyController]);    

function MyController($scope) {
    $scope.name = 'World';
    $scope.name2 = 'hello';
}
app.directive('formControl', function() {
  return {
    restrict: 'C',
    require: 'ngModel',
    link: function (scope, element, attrs, ngModel) {

      // Add class filled to form-control's that have a value
      if(ngModel.$viewValue){
        element.parent().addClass('filled');
      }

      // Any event here that can tell me that the value was changed by the angular so I can put the css class
      element.bind('blur', function (e) {
        input = angular.element(e.currentTarget);
        input.parent().removeClass('active');
      }).bind('focus', function (e) {
        input = angular.element(e.currentTarget);
        input.parent().addClass('active');
      });
      scope.$watch(function(){return ngModel.$viewValue;}, function(newValue){
        if('required' in attrs){
          if(newValue){
            element.parent().addClass('filled');
          } else {
            element.parent().removeClass('filled');
          }
        }
      })

    }
  };
});
.filled{
  background-color:lightblue;
}
.active{
  border:1px solid red;
}
<div ng-controller='MyController' ng-app="myApp">
    <label> The below input does not have required attribute</label>
    <input type="text" class="form-control" ng-model="name">
    <br>
    <br>
    <label> The below input has required attribute</label>
    <input type="text" class="form-control" required ng-model="name2">
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>

Additionally if you want to show an error message like how you see in ng-messages.

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

app.controller('MyController', ['$scope', MyController]);    

function MyController($scope) {
    $scope.name = 'World';
    $scope.name2 = 'hello';
}
app.directive('formControl', function() {
  return {
    restrict: 'C',
    require: 'ngModel',
    link: function (scope, element, attrs, ngModel) {

      // Add class filled to form-control's that have a value
      if(ngModel.$viewValue){
        element.parent().addClass('filled');
      }

      // Any event here that can tell me that the value was changed by the angular so I can put the css class
      element.bind('blur', function (e) {
        input = angular.element(e.currentTarget);
        input.parent().removeClass('active');
      }).bind('focus', function (e) {
        input = angular.element(e.currentTarget);
        input.parent().addClass('active');
      });
      scope.$watch(function(){return ngModel.$viewValue;}, function(newValue){
        if('required' in attrs){
          if(newValue){
            element.parent().addClass('filled');
          } else {
            element.parent().removeClass('filled');
          }
        }
      })

    }
  };
});
.filled{
  background-color:lightblue;
}
.active{
  border:1px solid red;
}
div.filled > .error-message{
  display:none;
}
div:not(.filled) > .error-message{
  display:block;
}
.error-message{
  text-align:center;
  margin-top:5px;
}
<div ng-controller='MyController' ng-app="myApp">
    <label> The below input does not have required attribute</label>
    <input type="text" class="form-control" ng-model="name">
    <br>
    <br>
    <label> The below input has required attribute</label>
    <input type="text" class="form-control" required ng-model="name2">
    <div class="error-message"> This Field is required</div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>

I hope this solves your issue :)

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

3 Comments

Thank you for your help. It worked, but I need ng-model to be optional.
@RudáCunha I dont understand, I am not trying to make the input as mandatory, I was expecting that you were trying to make this kind of input, so I provided a way of adding the classes for focus and ng-model filled.
There will be input that will have ng-model and will have input that will not have. If I leave it as required it from error.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.