mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-23 19:40:56 +08:00
fix(ng:class): make ng:class friendly towards other code adding/removing classes
ng:class as well as ng:class-odd and ng:class-even always reset the class list to whatever it was before compilation, this makes it impossible to create another directive which adds its own classes on the element on which ng:class was applied. the fix simply removes all classes that were added previously by ng:class and add classes that the ng:class expression evaluates to. we can now guarantee that we won't clobber stuff added before or after compilation as long as all class names are unique. in order to implement this I had to beef up jqLite#addClass and jqLite#removeClass to be able to add/remove multiple classes without creating duplicates.
This commit is contained in:
@@ -393,14 +393,6 @@ describe('Binder', function(){
|
||||
assertHidden(scope.$element);
|
||||
});
|
||||
|
||||
it('BindClassUndefined', function(){
|
||||
var scope = this.compile('<div ng:class="undefined"/>');
|
||||
scope.$apply();
|
||||
|
||||
assertEquals(
|
||||
'<div class="undefined" ng:class="undefined"></div>',
|
||||
sortedHtml(scope.$element));
|
||||
});
|
||||
|
||||
it('BindClass', function(){
|
||||
var scope = this.compile('<div ng:class="clazz"/>');
|
||||
|
||||
@@ -196,13 +196,103 @@ describe("directive", function(){
|
||||
expect(element.hasClass('B')).toBe(false);
|
||||
});
|
||||
|
||||
it('should support adding multiple classes', function(){
|
||||
|
||||
it('should support adding multiple classes via an array', function(){
|
||||
var scope = compile('<div class="existing" ng:class="[\'A\', \'B\']"></div>');
|
||||
scope.$digest();
|
||||
expect(element.hasClass('existing')).toBeTruthy();
|
||||
expect(element.hasClass('A')).toBeTruthy();
|
||||
expect(element.hasClass('B')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it('should support adding multiple classes via a space delimited string', function(){
|
||||
var scope = compile('<div class="existing" ng:class="\'A B\'"></div>');
|
||||
scope.$digest();
|
||||
expect(element.hasClass('existing')).toBeTruthy();
|
||||
expect(element.hasClass('A')).toBeTruthy();
|
||||
expect(element.hasClass('B')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it('should preserve class added post compilation with pre-existing classes', function() {
|
||||
var scope = compile('<div class="existing" ng:class="dynClass"></div>');
|
||||
scope.dynClass = 'A';
|
||||
scope.$digest();
|
||||
expect(element.hasClass('existing')).toBe(true);
|
||||
|
||||
// add extra class, change model and eval
|
||||
element.addClass('newClass');
|
||||
scope.dynClass = 'B';
|
||||
scope.$digest();
|
||||
|
||||
expect(element.hasClass('existing')).toBe(true);
|
||||
expect(element.hasClass('B')).toBe(true);
|
||||
expect(element.hasClass('newClass')).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it('should preserve class added post compilation without pre-existing classes"', function() {
|
||||
var scope = compile('<div ng:class="dynClass"></div>');
|
||||
scope.dynClass = 'A';
|
||||
scope.$digest();
|
||||
expect(element.hasClass('A')).toBe(true);
|
||||
|
||||
// add extra class, change model and eval
|
||||
element.addClass('newClass');
|
||||
scope.dynClass = 'B';
|
||||
scope.$digest();
|
||||
|
||||
expect(element.hasClass('B')).toBe(true);
|
||||
expect(element.hasClass('newClass')).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it('should preserve other classes with similar name"', function() {
|
||||
var scope = compile('<div class="ui-panel ui-selected" ng:class="dynCls"></div>');
|
||||
scope.dynCls = 'panel';
|
||||
scope.$digest();
|
||||
scope.dynCls = 'foo';
|
||||
scope.$digest();
|
||||
expect(element.attr('class')).toBe('ui-panel ui-selected ng-directive foo');
|
||||
});
|
||||
|
||||
|
||||
it('should not add duplicate classes', function() {
|
||||
var scope = compile('<div class="panel bar" ng:class="dynCls"></div>');
|
||||
scope.dynCls = 'panel';
|
||||
scope.$digest();
|
||||
expect(element.attr('class')).toBe('panel bar ng-directive');
|
||||
});
|
||||
|
||||
|
||||
it('should remove classes even if it was specified via class attribute', function() {
|
||||
var scope = compile('<div class="panel bar" ng:class="dynCls"></div>');
|
||||
scope.dynCls = 'panel';
|
||||
scope.$digest();
|
||||
scope.dynCls = 'window';
|
||||
scope.$digest();
|
||||
expect(element.attr('class')).toBe('bar ng-directive window');
|
||||
});
|
||||
|
||||
|
||||
it('should remove classes even if they were added by another code', function() {
|
||||
var scope = compile('<div ng:class="dynCls"></div>');
|
||||
scope.dynCls = 'foo';
|
||||
scope.$digest();
|
||||
element.addClass('foo');
|
||||
scope.dynCls = '';
|
||||
scope.$digest();
|
||||
expect(element.attr('class')).toBe('ng-directive');
|
||||
});
|
||||
|
||||
|
||||
it('should convert undefined and null values to an empty string', function() {
|
||||
var scope = compile('<div ng:class="dynCls"></div>');
|
||||
scope.dynCls = [undefined, null];
|
||||
scope.$digest();
|
||||
expect(element.attr('class')).toBe('ng-directive');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -190,14 +190,15 @@ describe('jqLite', function(){
|
||||
});
|
||||
|
||||
|
||||
describe('addClass', function(){
|
||||
it('should allow adding of class', function(){
|
||||
describe('addClass', function() {
|
||||
it('should allow adding of class', function() {
|
||||
var selector = jqLite([a, b]);
|
||||
expect(selector.addClass('abc')).toEqual(selector);
|
||||
expect(jqLite(a).hasClass('abc')).toEqual(true);
|
||||
expect(jqLite(b).hasClass('abc')).toEqual(true);
|
||||
});
|
||||
|
||||
|
||||
it('should ignore falsy values', function() {
|
||||
var jqA = jqLite(a);
|
||||
expect(jqA[0].className).toBe('');
|
||||
@@ -211,6 +212,28 @@ describe('jqLite', function(){
|
||||
jqA.addClass(false);
|
||||
expect(jqA[0].className).toBe('');
|
||||
});
|
||||
|
||||
|
||||
it('should allow multiple classes to be added in a single string', function() {
|
||||
var jqA = jqLite(a);
|
||||
expect(a.className).toBe('');
|
||||
|
||||
jqA.addClass('foo bar baz');
|
||||
expect(a.className).toBe('foo bar baz');
|
||||
});
|
||||
|
||||
|
||||
it('should not add duplicate classes', function() {
|
||||
var jqA = jqLite(a);
|
||||
expect(a.className).toBe('');
|
||||
|
||||
a.className = 'foo';
|
||||
jqA.addClass('foo');
|
||||
expect(a.className).toBe('foo');
|
||||
|
||||
jqA.addClass('bar foo baz');
|
||||
expect(a.className).toBe('foo bar baz');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -246,6 +269,7 @@ describe('jqLite', function(){
|
||||
expect(jqLite(b).hasClass('abc')).toEqual(false);
|
||||
});
|
||||
|
||||
|
||||
it('should correctly remove middle class', function() {
|
||||
var element = jqLite('<div class="foo bar baz"></div>');
|
||||
expect(element.hasClass('bar')).toBe(true);
|
||||
@@ -256,6 +280,15 @@ describe('jqLite', function(){
|
||||
expect(element.hasClass('bar')).toBe(false);
|
||||
expect(element.hasClass('baz')).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it('should remove multiple classes specified as one string', function() {
|
||||
var jqA = jqLite(a);
|
||||
|
||||
a.className = 'foo bar baz';
|
||||
jqA.removeClass('foo baz noexistent');
|
||||
expect(a.className).toBe('bar');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user