1

I have scoured the internet trying to figure out why the proprietary AngularJS validation is not working when using jQuery.Select2 and the ui-select2 directive - is it a bug??

Edit: ok I've discovered it is only tagging inputs this is occurring, my Select drop downs and text inputs are working fine.

Here's the fiddle http://jsfiddle.net/whiteb0x/ftEHu/

Html:

  <form name="myForm" ng-controller="Ctrl">
    userType: <input ui-select2="version1" class="input-xlarge" type="hidden" name="input" ng-model="userType" required>
    <span class="error" ng-show="myForm.input.$error.required">Required</span><br>
    <tt>userType = {{userType}}</tt><br>
    <tt>myForm.input.$valid = {{myForm.input.$valid}} wtf???????!!!</tt><br>
    <tt>myForm.input.$error = {{myForm.input.$error}} huh????</tt><br>
    <tt>myForm.$valid = {{myForm.$valid}} | please hand me a gun :)</tt><br>
    <tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
   </form>

Javascript:

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

function Ctrl($scope) {
  $scope.userType = '';
  $scope.version1 = {
      tags : null
  };    
}

2 Answers 2

18

I believe there's a problem in how select2 directive is passing the value between the ngModel and select2 plugin.

In short, when there are no tags selected, the UI's select2 directive will set the model to [] (empty array), because that's the default value returned by the select2 plugin on empty multi-select inputs (See the docs for select2 Data method)

I'll post an issue on Github to confirm this, but in the meantime here's a workaround:

function Ctrl($scope) {
  $scope.userType = null;
  $scope.version1 = {
      tags : null
  };

  $scope.$watch('userType', function(userType){
    if(angular.isArray(userType) && userType.length === 0){
      $scope.userType = '';
    }
  });
}

Or you could use this custom 'required-multiple' directive which will take empty array into consideration when validating the model:

app.directive('requiredMultiple', function() {
  function isEmpty(value) {
    return angular.isUndefined(value) || (angular.isArray(value) && value.length === 0) || value === '' || value === null || value !== value;
  }

  return {
    require: '?ngModel',
    link: function(scope, elm, attr, ctrl) {
      if (!ctrl) return;
      attr.required = true; // force truthy in case we are on non input element

      var validator = function(value) {
        if (attr.required && (isEmpty(value) || value === false)) {
          ctrl.$setValidity('required', false);
          return;
        } else {
          ctrl.$setValidity('required', true);
          return value;
        }
      };

      ctrl.$formatters.push(validator);
      ctrl.$parsers.unshift(validator);

      attr.$observe('required', function() {
        validator(ctrl.$viewValue);
      });
    }
  };
});
Sign up to request clarification or add additional context in comments.

3 Comments

is there a workaround? I'm trying to keep the validation on this project as simple as possible
Stewie thank you so much. I wish I could thumbs this up 10 times
Well, your gratitude is worth at least 10 thumbs-ups.
0

For tagging, the solution I've been using for this issue is setting ng-minlength="1" on the input. Seems to work well enough.

Comments

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.