darkace
darkace

Reputation: 878

Syntax of ng-repeat ng-class conditional

Hi I'm trying to resolve the following html so that it applies the css class stored in $root.buttonClass='btn-primary' (for example)

<li ng-controller="controllerCtrl">
   <a ng-class="{'$root.buttonClass':viewingContext=='{{entity}}'}" 
      ng-repeat="entity in entities" 
      ng-click="setContext(entity)" 
     type="">
     <span class="label bg-info pull-right" 
           ng-class="{hidden:viewingContext!='{{entity}}', show:viewingContext=='{{entity}}'}">
           viewing</span>
           {{entity}}</a>
</li>

The controller is fairly simple:

  $scope.setContext = function (entity) {
    console.log('set the context as: ' + entity);
    if (entity == $scope.entities[0]) {
      $scope.$root.buttonClass = 'btn-primary';
      $scope.viewingContext = entity;
    }
    if (entity == $scope.entities[1]) {
      $scope.$root.buttonClass = 'btn-warning';
      $scope.viewingContext = entity;
    }
    if (entity == $scope.entities[2]) {
      $scope.$root.buttonClass = 'btn-danger';
      $scope.viewingContext = entity;
    }
  };

The line in the tag might be the problem!

<a ng-class="{'$root.buttonClass':viewingContext=='{{entity}}'}" 
   ng-repeat="entity in entities" 
   ng-click="setContext(entity)" 
   type="">

Update:

Attempted to make a js fiddle http://jsfiddle.net/gn6b4ng8/2

Upvotes: 1

Views: 234

Answers (2)

Yaron Schwimmer
Yaron Schwimmer

Reputation: 5357

I don't think ngClass will work the way you want it.

Technically you could achieve your goal with ngClass, only if you recompile the elements after each change. This way, Angular will apply the changes in the value of ngClass to your element.

I don't think it's a nice way to do it.

Luckily, this is Angular, and you can create your own functionality using directives. You can create a directive, let's call it dynamicClass, that will have a similar behavior to that of ngClass, but will respond to changes in the class name:

myApp.directive('dynamicClass', function($compile) {
    return {
        restrict: 'A',
        link: function($scope, element, attrs) {
            $scope.$watch(function() {
                return attrs.dynamicClass;
            }, function(newVal, oldVal) {
                var condition = newVal.match(/:(.*?)\}$/)[1];
                var cls = newVal.match(/^\{'?(.*?)'?:/)[1];
                var oldCls = oldVal.match(/^\{'?(.*?)'?:/)[1];
                element.removeClass(oldCls);
                if ($scope.$eval(condition)) {
                    element.addClass(cls);
                }    

            });
        }
    };
});

usage:

<a dynamic-class="{'{{$root.buttonClass}}':viewingContext=='{{entity}}'}" 
  ng-repeat="entity in entities" 
  ng-click="setContext(entity)">

I forked your fiddle to test it. It works.

Upvotes: 0

John Niedzwiecki
John Niedzwiecki

Reputation: 314

You can't have a dynamic key name in an object. From the documentation, it looks like you're trying to use the second type of expression, an object, but violating the structure "If the expression evaluates to an object, then for each key-value pair of the object with a truthy value the corresponding key is used as a class name." The key would be used as a class name, as is.

It looks like what you want to be using the first type of expression possible for ng-class "If the expression evaluates to a string, the string should be one or more space-delimited class names." If instead you do something like ng-class="$root.buttonClass". That should solve your problem by then resolving to your class name you store in buttonClass. You can see an example in the documentation where it uses <p ng-class="style">Using String Syntax</p>

Upvotes: 1

Related Questions