1

I cant change the option class attribute. OptionClass actually work. I founded it from the this site. But my real code not work. I dont know where is the bug.

I only want to change the options background-color with expression, for example if id>100 then background color is red etc.

My Select

 <select ng-model="firstSection" ng-options="o.label for o in options" multiple 
class="invoiceSelect" options-class="{ 'is-eligible' : Id<100, 'not-eligible': !Id<100 }"></select>

My Filling methods

    var myApp = angular.module('app', []);
            myApp.controller('myCtrl', function ($scope, $http, $filter) {
        $scope.getInvoiceByRfiPolicyId = function (rfiPolicyId) {

                        $http.get('http://somesitelink.com/' + rfiPolicyId)
                      .then(function (response) {
                          $scope.options = response.data.map(o=> {
                              return { label: 'Numbers:' + o.InvoiceNumber + ' InvDate:' + $scope.dateParse(o.InvoiceDate), value: o.InvoiceId, Id:o.InvoiceId, eligible: true }
                          });

                      });

                    }
    });

Here is my optionClass function

myApp.directive('optionsClass', function ($parse) {
            return {
                require: 'select',
                link: function (scope, elem, attrs, ngSelect) {
                    var parts = attrs.ngOptions.split(' ');
                    var optionsSourceStr = parts[parts.indexOf('in') + 1];
                    var getOptionsClass = $parse(attrs.optionsClass);

                    scope.$watchCollection(optionsSourceStr, function (items) {
                        scope.$$postDigest(function () {
                            angular.forEach(items, function (item, index) {
                                var classes = getOptionsClass(item),
                                                                    option = elem.find('option[value="' + item.id + '"]');
                                angular.forEach(classes, function (add, className) {
                                    if (add) {
                                        angular.element(option).addClass(className);
                                    }
                                });
                            });
                        });
                    });
                }
            };
        });
Aravind
  • 40,391
  • 16
  • 91
  • 110
Emre Ekşioğlu
  • 359
  • 2
  • 13
  • have you tryed using ng-class directive ? this is the way to manipulate class in angular https://docs.angularjs.org/api/ng/directive/ngClass – Panos K Sep 06 '18 at 08:13
  • it is not appropriate to use it. Because i want to change some options with value. So i dont have any option element. I am using ng-options attribute. If you are a example for this, i will investigate it. – Emre Ekşioğlu Sep 06 '18 at 08:37
  • try adding the class with jQuery, That should work. – Akber Iqbal Sep 06 '18 at 11:30
  • Why dont you use `option` tag with `ng-repeat` like this and remove `ng-options`? `` – Ashish Sep 06 '18 at 12:07
  • because my value not a simple data. It's a class, and different properties which i use it. So – Emre Ekşioğlu Sep 06 '18 at 12:21
  • Because the ng-repeat directive repeats a block of HTML code for each item in an array, it can be used to create options in a dropdown list, but the ng-options directive was made especially for filling a dropdown list with options, and has at least one important advantage: Dropdowns made with ng-options allows the selected value to be an object, while dropdowns made from ng-repeat has to be a string. – Emre Ekşioğlu Sep 06 '18 at 12:21

1 Answers1

1

A working example is given in the embedded code snippet below.

You must have got the solution from here. There are two issues in the code used:

1. Finding option element

find method in this statement option = elem.find('option[value="' + item.id + '"]') tries to look using attribute selector but find method of jqLite (which is embedded in AngularJS) is limited to look up by tag names only so this doesn't work in your code. Added a simple method to find the required option.

It is working in the question that you referred because code pasted there had an assumption to be working with jQuery and find method in jQuery allows you to find based on a variety of selectors.

2. Expressions in options-class directive

Group the expressions using (<expression>) as shown here options-class="{ 'is-eligible' : (Id<2), 'not-eligible': !(Id<2) }", otherwise ! negation operator will first negate the Id value and then perform the comparison.

angular.module('ExampleApp', [])
  .controller('ExampleController', function($scope) {
    $scope.options = [{
        label: 'Numbers: Invoice001',
        value: 1,
        Id: 1,
        eligible: true
      },
      {
        label: 'Numbers: Invoice002',
        value: 2,
        Id: 2,
        eligible: true
      },
      {
        label: 'Numbers: Invoice003',
        value: 3,
        Id: 3,
        eligible: true
      }
    ];

  })

  .directive('optionsClass', function($parse) {
    return {
      require: 'select',
      link: function(scope, elem, attrs, ngSelect) {

        function findOptionByValueAttr(options, findByValue) {
          for (var i = 0; i < options.length; i++) {
            var option = angular.element(options[i]);
            if (option.attr('value') === findByValue.toString()) {
              return option;
            }
          }
        }
        var parts = attrs.ngOptions.split(' ');
        var optionsSourceStr = parts[parts.indexOf('in') + 1];

console.log(attrs.optionsClass);
var getOptionsClass = $parse(attrs.optionsClass);
        scope.$watchCollection(optionsSourceStr, function(items) {

          angular.forEach(items, function(item, index) {
          
console.log(getOptionsClass(item));
            var classes = getOptionsClass(item),
              /*option = elem.find('option[value="' + item.Id + '"]');*/
              option = findOptionByValueAttr(elem.children(), item.Id);
            console.log(item);

            angular.forEach(classes, function(add, className) {
              if (add) {
                option.addClass(className);
              }
            });
          });

        });


      } // link function ends

    }; // return value ends
  }); // directive ends
.is-eligible {
  background-color: lightgreen;
}

.not-eligible {
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="ExampleApp" ng-controller="ExampleController">

  <select ng-model="firstSection" ng-options="o.label for o in options track by o.Id" multiple class="invoiceSelect" options-class="{ 'is-eligible' : (Id<2), 'not-eligible': !(Id<2) }"></select>

</div>

Design Suggestions

Styling the options is not recommended as this behavior is not consistent across browsers and option elements are rendered differently on mobile.

You may check following design considerations to avoid styling:

  • Modify the label and/or disable those options which you eventually want the user to NOT select. This is possible using ng-options.
  • On selecting an option, highlight the external surrounding parent area enclosing the select element to alert the user to understand the difference and may accompany with a supporting text, disabling the relevant areas, submit buttons etc.

Hope these will be helpful.

Ritesh Jagga
  • 1,387
  • 1
  • 11
  • 23