Permalink
Browse files

feat(ngClass): add support for conditional map within an array.

This change allows `ngClass` expressions to have both objects and strings
within an array:

```js
$scope.classVar = 'nav-item';
$scope.activeVar = true;
```

```html
<div ng-class=" [classVar, {'is-active': activeVar }] ">
```

In this case, the CSS classes that will be added are: 'nav-item' and 'is-active'.

Closes #4807
  • Loading branch information...
1 parent ea9fd82 commit 4588e627bb7238b2113241919b948d0e5166c76d @bfanger bfanger committed with petebacondarwin Mar 18, 2015
Showing with 41 additions and 11 deletions.
  1. +30 −11 src/ng/directive/ngClass.js
  2. +11 −0 test/ng/directive/ngClassSpec.js
@@ -96,12 +96,15 @@ function classDirective(name, selector) {
}
function arrayClasses(classVal) {
+ var classes = [];
if (isArray(classVal)) {
- return classVal.join(' ').split(' ');
+ forEach(classVal, function(v) {
+ classes = classes.concat(arrayClasses(v));
+ });
+ return classes;
} else if (isString(classVal)) {
return classVal.split(' ');
} else if (isObject(classVal)) {
- var classes = [];
forEach(classVal, function(v, k) {
if (v) {
classes = classes.concat(k.split(' '));
@@ -129,16 +132,18 @@ function classDirective(name, selector) {
* 1. If the expression evaluates to a string, the string should be one or more space-delimited class
* names.
*
- * 2. If the expression evaluates to an array, each element of the array should be a string that is
- * one or more space-delimited class names.
- *
- * 3. If the expression evaluates to an object, then for each key-value pair of the
+ * 2. 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.
*
+ * 3. If the expression evaluates to an array, each element of the array should either be a string as in
+ * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
+ * to give you more control over what CSS classes appear. See the code below for an example of this.
+ *
+ *
* The directive won't add duplicate classes if a particular class was already set.
*
- * When the expression changes, the previously added classes are removed and only then the
- * new classes are added.
+ * When the expression changes, the previously added classes are removed and only then are the
+ * new classes added.
*
* @animations
* **add** - happens just before the class is applied to the elements
@@ -167,17 +172,24 @@ function classDirective(name, selector) {
<input ng-model="style1" placeholder="Type: bold, strike or red"><br>
<input ng-model="style2" placeholder="Type: bold, strike or red"><br>
<input ng-model="style3" placeholder="Type: bold, strike or red"><br>
+ <hr>
+ <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
+ <input ng-model="style4" placeholder="Type: bold, strike"><br>
+ <input type="checkbox" ng-model="warning"> warning (apply "orange" class)
</file>
<file name="style.css">
.strike {
- text-decoration: line-through;
+ text-decoration: line-through;
}
.bold {
font-weight: bold;
}
.red {
color: red;
}
+ .orange {
+ color: orange;
@gkalpak
gkalpak Mar 20, 2015 Member

👍 for orange color :)

+ }
</file>
<file name="protractor.js" type="protractor">
var ps = element.all(by.css('p'));
@@ -202,11 +214,18 @@ function classDirective(name, selector) {
});
it('array example should have 3 classes', function() {
- expect(ps.last().getAttribute('class')).toBe('');
+ expect(ps.get(2).getAttribute('class')).toBe('');
element(by.model('style1')).sendKeys('bold');
element(by.model('style2')).sendKeys('strike');
element(by.model('style3')).sendKeys('red');
- expect(ps.last().getAttribute('class')).toBe('bold strike red');
+ expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
+ });
+
+ it('array with map example should have 2 classes', function() {
+ expect(ps.last().getAttribute('class')).toBe('');
+ element(by.model('style4')).sendKeys('bold');
+ element(by.model('warning')).click();
+ expect(ps.last().getAttribute('class')).toBe('bold orange');
});
</file>
</example>
@@ -63,6 +63,17 @@ describe('ngClass', function() {
expect(element.hasClass('AnotB')).toBeFalsy();
}));
+ it('should support adding multiple classes via an array mixed with conditionally via a map', inject(function($rootScope, $compile) {
+ element = $compile('<div class="existing" ng-class="[\'A\', {\'B\': condition}]"></div>')($rootScope);
+ $rootScope.$digest();
+ expect(element.hasClass('existing')).toBeTruthy();
+ expect(element.hasClass('A')).toBeTruthy();
+ expect(element.hasClass('B')).toBeFalsy();
+ $rootScope.condition = true;
+ $rootScope.$digest();
+ expect(element.hasClass('B')).toBeTruthy();
+
+ }));
it('should remove classes when the referenced object is the same but its property is changed',
inject(function($rootScope, $compile) {

2 comments on commit 4588e62

@osi-oswald

This is fantastic! When will this be available? ;-)

@petebacondarwin
Member

In the next release 1.4.0-beta.7

Please sign in to comment.