Skip to content

Commit e7e438f

Browse files
committed
fix(directive): reapply ng-class when interpolated class attribute changes
Closes angular#1016
1 parent a57141f commit e7e438f

File tree

3 files changed

+63
-13
lines changed

3 files changed

+63
-13
lines changed

src/ng/compile.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,9 @@ function $CompileProvider($provide) {
999999
// we define observers array only for interpolated attrs
10001000
// and ignore observers for non interpolated attrs to save some memory
10011001
attr.$$observers[name] = [];
1002-
attr[name] = undefined;
1002+
if (name !== 'class') {
1003+
attr[name] = undefined;
1004+
}
10031005
scope.$watch(interpolateFn, function(value) {
10041006
attr.$set(name, value);
10051007
});

src/ng/directive/ngClass.js

+28-12
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,35 @@
22

33
function classDirective(name, selector) {
44
name = 'ngClass' + name;
5-
return ngDirective(function(scope, element, attr) {
6-
scope.$watch(attr[name], function(newVal, oldVal) {
7-
if (selector === true || scope.$index % 2 === selector) {
8-
if (oldVal && (newVal !== oldVal)) {
9-
if (isObject(oldVal) && !isArray(oldVal))
10-
oldVal = map(oldVal, function(v, k) { if (v) return k });
11-
element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
12-
}
13-
if (isObject(newVal) && !isArray(newVal))
5+
return ['$interpolate', function($interpolate) {
6+
return function(scope, element, attr) {
7+
// Reusable function for re-applying the ngClass
8+
function reapply(newVal, oldVal) {
9+
if (selector === true || scope.$index % 2 === selector) {
10+
if (oldVal && (newVal !== oldVal)) {
11+
if (isObject(oldVal) && !isArray(oldVal))
12+
oldVal = map(oldVal, function(v, k) { if (v) return k });
13+
element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
14+
}
15+
if (isObject(newVal) && !isArray(newVal))
1416
newVal = map(newVal, function(v, k) { if (v) return k });
15-
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
16-
}, true);
17-
});
17+
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal);
18+
}
19+
};
20+
scope.$watch(attr[name], reapply, true);
21+
22+
// Watch class attribute for changes
23+
if (attr['class']) {
24+
var interpolateFn = $interpolate(attr['class'], true);
25+
scope.$watch(interpolateFn, function(newClass, oldClass) {
26+
// Reapply ngClass
27+
var ngClass = scope.$eval(attr[name]);
28+
reapply(ngClass, ngClass);
29+
});
30+
}
31+
32+
};
33+
}];
1834
}
1935

2036
/**

test/ng/directive/ngClassSpec.js

+32
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,36 @@ describe('ngClass', function() {
201201
expect(e2.hasClass('C')).toBeFalsy();
202202
expect(e2.hasClass('D')).toBeFalsy();
203203
}));
204+
205+
it('should reapply ngClass when interpolated class attribute changes', inject(function($rootScope, $compile) {
206+
element = $compile('<div class="one {{cls}} three" ng-class="{four: four}"></div>')($rootScope);
207+
208+
$rootScope.$apply(function() {
209+
$rootScope.cls = "two";
210+
$rootScope.four = true;
211+
});
212+
expect(element).toHaveClass('one');
213+
expect(element).toHaveClass('two'); // interpolated
214+
expect(element).toHaveClass('three');
215+
expect(element).toHaveClass('four');
216+
217+
$rootScope.$apply(function() {
218+
$rootScope.cls = "too";
219+
});
220+
expect(element).toHaveClass('one');
221+
expect(element).toHaveClass('too'); // interpolated
222+
expect(element).toHaveClass('three');
223+
expect(element).toHaveClass('four'); // should still be there
224+
expect(element.hasClass('two')).toBeFalsy();
225+
226+
$rootScope.$apply(function() {
227+
$rootScope.cls = "to";
228+
});
229+
expect(element).toHaveClass('one');
230+
expect(element).toHaveClass('to'); // interpolated
231+
expect(element).toHaveClass('three');
232+
expect(element).toHaveClass('four'); // should still be there
233+
expect(element.hasClass('two')).toBeFalsy();
234+
expect(element.hasClass('too')).toBeFalsy();
235+
}));
204236
});

0 commit comments

Comments
 (0)