ngClass string binding expression with class map

1.8k views Asked by At

Is it possible to use ngClass with an expression AND a class map? I want to conditionally add a class based on the existence of a variable as well as use that variable in the expression that creates the class.

For instance, if isActive() is true and getStatus() returns "valid" I want the class list to be "element element--active element--valid". If getStatus() returns undefined I want the class list to be "element element--active".

<div
  class="element"
  ng-class="{
   'element--active': ctrl.isActive(),
   'element--{{ ctrl.getStatus() }}': ctrl.getStatus() 
  }"></div>

Doesn't seem to work.

<div 
  class="element element--{{ctrl.getStatus()}}"
  ng-class="{
   'element--active': ctrl.isActive()
  }"></div>

Works but then there's an extra hanging "element--" if getStatus() returns undefined.

Do I have to add a method in my controller to handle the class generation?

2

There are 2 answers

0
ShankarSangoli On

You can use class and ng-class map on the same element. But since your class name is dynamic you will have to something like this.

<div
  ng-class="'element '
            + (ctrl.isActive() ? ' element--active' : '') 
            + (ctrl.getStatus() ? ' element--' + ctrl.getStatus() : '')"></div>
2
PSL On

i'd suggest to make just one function call to get the classes. It will make it cleaner and have the class logic in one place.

In your controller:

this.getElementStatus = function(){
   var rules = {active:this.isActive()}; //Prefix with element-- {element--active:}
   rules[this.getStatus()] = true; //Prefix with element--, rules['element--' + this.getStatus()] = true
   return rules;
}

and your view would just be:

<div 
  class="element"
  ng-class="ctrl.getElementStatus()"></div>

It seems like your element-- is redundant with the rule instead make use of cascadeability(CSS) property. and define rules as :

Example:

.element.active{ /*....*/ }
.element.success {/*...*/}
.element.error{/*...*/}

This will help in maintenance, gets more verbose and get to the natural way of adding css rules and could remove these kind of complexities from the view.

You could as well do:

<div class="element" 
     ng-class="{'active': ctrl.isActive(), '{{ctrl.getStatus()}}':true}"

or :

<div class="element" 
     ng-class="[ctrl.isActive() ? 'active' : '', ctrl.getStatus()]"

If you don't mind getting a true added as a rule(should not affect anything anyways) then,

 <div class="element" 
     ng-class="[!ctrl.isActive() || 'element--active' , 'element--' + ctrl.getStatus()]">