Skip to content

Commit a8b5725

Browse files
fix(class): allow class names with mixed case
Fixes #3001 BREAKING CHANGE: View renderer used to take normalized CSS class names (ex. fooBar for foo-bar). With this change a rendered implementation gets a calss name as specified in a template, without any transformations / normalization. This change only affects custom view renderers that should be updated accordingly. Closes #3264
1 parent 329a6e0 commit a8b5725

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-10
lines changed

modules/angular2/src/render/dom/view/proto_view_builder.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ import {DomElementBinder, Event, HostAction} from './element_binder';
2323

2424
import * as api from '../../api';
2525

26-
import {NG_BINDING_CLASS, EVENT_TARGET_SEPARATOR, queryBoundTextNodeIndices} from '../util';
26+
import {
27+
NG_BINDING_CLASS,
28+
EVENT_TARGET_SEPARATOR,
29+
queryBoundTextNodeIndices,
30+
camelCaseToDashCase
31+
} from '../util';
2732

2833
export class ProtoViewBuilder {
2934
variableBindings: Map<string, string> = new Map();
@@ -366,7 +371,8 @@ function createElementPropertyBinding(ast: ASTWithSource, propertyNameInTemplate
366371
} else if (parts[0] == ATTRIBUTE_PREFIX) {
367372
return new api.ElementPropertyBinding(api.PropertyBindingType.ATTRIBUTE, ast, parts[1]);
368373
} else if (parts[0] == CLASS_PREFIX) {
369-
return new api.ElementPropertyBinding(api.PropertyBindingType.CLASS, ast, parts[1]);
374+
return new api.ElementPropertyBinding(api.PropertyBindingType.CLASS, ast,
375+
camelCaseToDashCase(parts[1]));
370376
} else if (parts[0] == STYLE_PREFIX) {
371377
var unit = parts.length > 2 ? parts[2] : null;
372378
return new api.ElementPropertyBinding(api.PropertyBindingType.STYLE, ast, parts[1], unit);

modules/angular2/src/render/dom/view/view.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@ export class DomView {
4242

4343
setElementClass(elementIndex: number, className: string, isAdd: boolean) {
4444
var element = this.boundElements[elementIndex];
45-
var dashCasedClassName = camelCaseToDashCase(className);
4645
if (isAdd) {
47-
DOM.addClass(element, dashCasedClassName);
46+
DOM.addClass(element, className);
4847
} else {
49-
DOM.removeClass(element, dashCasedClassName);
48+
DOM.removeClass(element, className);
5049
}
5150
}
5251

modules/angular2/test/directives/class_spec.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ export function main() {
6161
});
6262
}));
6363

64+
65+
it('should add classes specified in an object literal without change in class names',
66+
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
67+
var template = `<div [class]="{'foo-bar': true, 'fooBar': true}"></div>`;
68+
69+
tcb.overrideTemplate(TestComponent, template)
70+
.createAsync(TestComponent)
71+
.then((rootTC) => {
72+
rootTC.detectChanges();
73+
expect(rootTC.componentViewChildren[0].nativeElement.className)
74+
.toEqual('ng-binding foo-bar fooBar');
75+
76+
async.done();
77+
});
78+
}));
79+
6480
it('should add and remove classes based on changes in object literal values',
6581
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
6682
var template = '<div [class]="{foo: condition, bar: !condition}"></div>';
@@ -141,14 +157,14 @@ export function main() {
141157

142158
it('should add classes specified in a list literal',
143159
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
144-
var template = `<div [class]="['foo', 'bar']"></div>`;
160+
var template = `<div [class]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`;
145161

146162
tcb.overrideTemplate(TestComponent, template)
147163
.createAsync(TestComponent)
148164
.then((rootTC) => {
149165
rootTC.detectChanges();
150166
expect(rootTC.componentViewChildren[0].nativeElement.className)
151-
.toEqual('ng-binding foo bar');
167+
.toEqual('ng-binding foo bar foo-bar fooBar');
152168

153169
async.done();
154170
});
@@ -212,14 +228,14 @@ export function main() {
212228

213229
it('should add classes specified in a string literal',
214230
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
215-
var template = `<div [class]="'foo bar'"></div>`;
231+
var template = `<div [class]="'foo bar foo-bar fooBar'"></div>`;
216232

217233
tcb.overrideTemplate(TestComponent, template)
218234
.createAsync(TestComponent)
219235
.then((rootTC) => {
220236
rootTC.detectChanges();
221237
expect(rootTC.componentViewChildren[0].nativeElement.className)
222-
.toEqual('ng-binding foo bar');
238+
.toEqual('ng-binding foo bar foo-bar fooBar');
223239

224240
async.done();
225241
});

modules/angular2/test/render/dom/view/view_spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,15 @@ export function main() {
100100
expect(DOM.hasClass(el, 'active')).toEqual(false);
101101
});
102102

103-
it('should de-normalize class names', () => {
103+
it('should not de-normalize class names', () => {
104104
view.setElementClass(0, 'veryActive', true);
105+
view.setElementClass(0, 'very-active', true);
106+
expect(DOM.hasClass(el, 'veryActive')).toEqual(true);
105107
expect(DOM.hasClass(el, 'very-active')).toEqual(true);
106108

107109
view.setElementClass(0, 'veryActive', false);
110+
view.setElementClass(0, 'very-active', false);
111+
expect(DOM.hasClass(el, 'veryActive')).toEqual(false);
108112
expect(DOM.hasClass(el, 'very-active')).toEqual(false);
109113
});
110114
});

0 commit comments

Comments
 (0)