X Tutup
Skip to content

Commit 7ce4f66

Browse files
feat: support binding to class.classname
Closes angular#551
1 parent ab9438f commit 7ce4f66

File tree

7 files changed

+84
-4
lines changed

7 files changed

+84
-4
lines changed

modules/core/src/compiler/pipeline/element_binder_builder.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {int, isPresent, isBlank, Type, BaseException, stringify} from 'facade/src/lang';
1+
import {int, isPresent, isBlank, Type, BaseException, StringWrapper, stringify} from 'facade/src/lang';
22
import {Element, DOM} from 'facade/src/dom';
33
import {ListWrapper, List, MapWrapper, StringMapWrapper} from 'facade/src/collection';
44

@@ -16,6 +16,26 @@ import {CompileStep} from './compile_step';
1616
import {CompileElement} from './compile_element';
1717
import {CompileControl} from './compile_control';
1818

19+
const CLASS_PREFIX = 'class.';
20+
var classSettersCache = StringMapWrapper.create();
21+
22+
function classSetterFactory(className:string) {
23+
var setterFn = StringMapWrapper.get(classSettersCache, className);
24+
25+
if (isBlank(setterFn)) {
26+
setterFn = function(element:Element, value) {
27+
if (value) {
28+
DOM.addClass(element, className);
29+
} else {
30+
DOM.removeClass(element, className);
31+
}
32+
};
33+
StringMapWrapper.set(classSettersCache, className, setterFn);
34+
}
35+
36+
return setterFn;
37+
}
38+
1939
/**
2040
* Creates the ElementBinders and adds watches to the
2141
* ProtoChangeDetector.
@@ -72,8 +92,16 @@ export class ElementBinderBuilder extends CompileStep {
7292

7393
_bindElementProperties(protoView, compileElement) {
7494
MapWrapper.forEach(compileElement.propertyBindings, (expression, property) => {
75-
if (DOM.hasProperty(compileElement.element, property)) {
76-
protoView.bindElementProperty(expression.ast, property, reflector.setter(property));
95+
var setterFn;
96+
97+
if (StringWrapper.startsWith(property, CLASS_PREFIX)) {
98+
setterFn = classSetterFactory(StringWrapper.substring(property, CLASS_PREFIX.length));
99+
} else if (DOM.hasProperty(compileElement.element, property)) {
100+
setterFn = reflector.setter(property);
101+
}
102+
103+
if (isPresent(setterFn)) {
104+
protoView.bindElementProperty(expression.ast, property, setterFn);
77105
}
78106
});
79107
}

modules/core/test/compiler/integration_spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ export function main() {
6969
});
7070
});
7171

72+
it('should consume element binding for class attribute', (done) => {
73+
compiler.compile(MyComp, el('<div class="foo" [class.bar]="boolProp"></div>')).then((pv) => {
74+
createView(pv);
75+
76+
ctx.boolProp = true;
77+
cd.detectChanges();
78+
expect(view.nodes[0].className).toEqual('foo ng-binding bar');
79+
80+
ctx.boolProp = false;
81+
cd.detectChanges();
82+
expect(view.nodes[0].className).toEqual('foo ng-binding');
83+
84+
done();
85+
});
86+
});
87+
7288
it('should support nested components.', (done) => {
7389
compiler.compile(MyComp, el('<child-cmp></child-cmp>')).then((pv) => {
7490
createView(pv);
@@ -147,6 +163,7 @@ class MyDir {
147163
})
148164
class MyComp {
149165
ctxProp:string;
166+
boolProp:boolean;
150167
constructor() {
151168
this.ctxProp = 'initial value';
152169
}

modules/core/test/compiler/pipeline/element_binder_builder_spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,27 @@ export function main() {
176176
expect(view.nodes[0].hidden).toEqual(false);
177177
});
178178

179+
it('should bind class with a dot', () => {
180+
var propertyBindings = MapWrapper.createFromStringMap({
181+
'class.bar': 'prop1',
182+
});
183+
var pipeline = createPipeline({propertyBindings: propertyBindings});
184+
var results = pipeline.process(el('<input class="foo" viewroot prop-binding>'));
185+
var pv = results[0].inheritedProtoView;
186+
187+
expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true);
188+
189+
instantiateView(pv);
190+
191+
evalContext.prop1 = true;
192+
changeDetector.detectChanges();
193+
expect(view.nodes[0].className).toEqual('foo ng-binding bar');
194+
195+
evalContext.prop1 = false;
196+
changeDetector.detectChanges();
197+
expect(view.nodes[0].className).toEqual('foo ng-binding');
198+
});
199+
179200
it('should bind events', () => {
180201
var eventBindings = MapWrapper.createFromStringMap({
181202
'event1': '1+1'

modules/facade/src/dom.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class DOM {
102102
static void addClass(Element element, String classname) {
103103
element.classes.add(classname);
104104
}
105+
static void removeClass(Element element, String classname) {
106+
element.classes.remove(classname);
107+
}
105108
static bool hasClass(Element element, String classname) =>
106109
element.classes.contains(classname);
107110

modules/facade/src/dom.es6

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ export class DOM {
121121
static addClass(element:Element, classname:string) {
122122
element.classList.add(classname);
123123
}
124+
static removeClass(element:Element, classname:string) {
125+
element.classList.remove(classname);
126+
}
124127
static hasClass(element:Element, classname:string) {
125128
return element.classList.contains(classname);
126129
}

modules/facade/src/lang.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class StringWrapper {
6262
return s.replaceAll(from, replace);
6363
}
6464

65+
static startsWith(String s, String start) {
66+
return s.startsWith(start);
67+
}
68+
6569
static String substring(String s, int start, [int end]) {
6670
return s.substring(start, end);
6771
}

modules/facade/src/lang.es6

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export class StringWrapper {
6868
return s.replace(from.multiple, replace);
6969
}
7070

71+
static startsWith(s:string, start:string) {
72+
return s.startsWith(start);
73+
}
74+
7175
static substring(s:string, start:int, end:int = undefined) {
7276
return s.substring(start, end);
7377
}
@@ -219,4 +223,4 @@ export function assertionsEnabled():boolean {
219223

220224
export function print(obj) {
221225
console.log(obj);
222-
}
226+
}

0 commit comments

Comments
 (0)
X Tutup