Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 4588e62

Browse files
bfangerpetebacondarwin
authored andcommitted
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
1 parent ea9fd82 commit 4588e62

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

src/ng/directive/ngClass.js

+30-11
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,15 @@ function classDirective(name, selector) {
9696
}
9797

9898
function arrayClasses(classVal) {
99+
var classes = [];
99100
if (isArray(classVal)) {
100-
return classVal.join(' ').split(' ');
101+
forEach(classVal, function(v) {
102+
classes = classes.concat(arrayClasses(v));
103+
});
104+
return classes;
101105
} else if (isString(classVal)) {
102106
return classVal.split(' ');
103107
} else if (isObject(classVal)) {
104-
var classes = [];
105108
forEach(classVal, function(v, k) {
106109
if (v) {
107110
classes = classes.concat(k.split(' '));
@@ -129,16 +132,18 @@ function classDirective(name, selector) {
129132
* 1. If the expression evaluates to a string, the string should be one or more space-delimited class
130133
* names.
131134
*
132-
* 2. If the expression evaluates to an array, each element of the array should be a string that is
133-
* one or more space-delimited class names.
134-
*
135-
* 3. If the expression evaluates to an object, then for each key-value pair of the
135+
* 2. If the expression evaluates to an object, then for each key-value pair of the
136136
* object with a truthy value the corresponding key is used as a class name.
137137
*
138+
* 3. If the expression evaluates to an array, each element of the array should either be a string as in
139+
* type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
140+
* to give you more control over what CSS classes appear. See the code below for an example of this.
141+
*
142+
*
138143
* The directive won't add duplicate classes if a particular class was already set.
139144
*
140-
* When the expression changes, the previously added classes are removed and only then the
141-
* new classes are added.
145+
* When the expression changes, the previously added classes are removed and only then are the
146+
* new classes added.
142147
*
143148
* @animations
144149
* **add** - happens just before the class is applied to the elements
@@ -167,17 +172,24 @@ function classDirective(name, selector) {
167172
<input ng-model="style1" placeholder="Type: bold, strike or red"><br>
168173
<input ng-model="style2" placeholder="Type: bold, strike or red"><br>
169174
<input ng-model="style3" placeholder="Type: bold, strike or red"><br>
175+
<hr>
176+
<p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
177+
<input ng-model="style4" placeholder="Type: bold, strike"><br>
178+
<input type="checkbox" ng-model="warning"> warning (apply "orange" class)
170179
</file>
171180
<file name="style.css">
172181
.strike {
173-
text-decoration: line-through;
182+
text-decoration: line-through;
174183
}
175184
.bold {
176185
font-weight: bold;
177186
}
178187
.red {
179188
color: red;
180189
}
190+
.orange {
191+
color: orange;
192+
}
181193
</file>
182194
<file name="protractor.js" type="protractor">
183195
var ps = element.all(by.css('p'));
@@ -202,11 +214,18 @@ function classDirective(name, selector) {
202214
});
203215
204216
it('array example should have 3 classes', function() {
205-
expect(ps.last().getAttribute('class')).toBe('');
217+
expect(ps.get(2).getAttribute('class')).toBe('');
206218
element(by.model('style1')).sendKeys('bold');
207219
element(by.model('style2')).sendKeys('strike');
208220
element(by.model('style3')).sendKeys('red');
209-
expect(ps.last().getAttribute('class')).toBe('bold strike red');
221+
expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
222+
});
223+
224+
it('array with map example should have 2 classes', function() {
225+
expect(ps.last().getAttribute('class')).toBe('');
226+
element(by.model('style4')).sendKeys('bold');
227+
element(by.model('warning')).click();
228+
expect(ps.last().getAttribute('class')).toBe('bold orange');
210229
});
211230
</file>
212231
</example>

test/ng/directive/ngClassSpec.js

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ describe('ngClass', function() {
6363
expect(element.hasClass('AnotB')).toBeFalsy();
6464
}));
6565

66+
it('should support adding multiple classes via an array mixed with conditionally via a map', inject(function($rootScope, $compile) {
67+
element = $compile('<div class="existing" ng-class="[\'A\', {\'B\': condition}]"></div>')($rootScope);
68+
$rootScope.$digest();
69+
expect(element.hasClass('existing')).toBeTruthy();
70+
expect(element.hasClass('A')).toBeTruthy();
71+
expect(element.hasClass('B')).toBeFalsy();
72+
$rootScope.condition = true;
73+
$rootScope.$digest();
74+
expect(element.hasClass('B')).toBeTruthy();
75+
76+
}));
6677

6778
it('should remove classes when the referenced object is the same but its property is changed',
6879
inject(function($rootScope, $compile) {

0 commit comments

Comments
 (0)