diff --git a/modules/angular2/src/core/compiler/pipeline/element_binder_builder.js b/modules/angular2/src/core/compiler/pipeline/element_binder_builder.js index 9eaea4af03..848242fde9 100644 --- a/modules/angular2/src/core/compiler/pipeline/element_binder_builder.js +++ b/modules/angular2/src/core/compiler/pipeline/element_binder_builder.js @@ -1,4 +1,4 @@ -import {int, isPresent, isBlank, Type, BaseException, StringWrapper, stringify} from 'angular2/src/facade/lang'; +import {int, isPresent, isBlank, Type, BaseException, StringWrapper, RegExpWrapper, stringify} from 'angular2/src/facade/lang'; import {Element, DOM} from 'angular2/src/facade/dom'; import {ListWrapper, List, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; @@ -16,6 +16,8 @@ import {CompileStep} from './compile_step'; import {CompileElement} from './compile_element'; import {CompileControl} from './compile_control'; +var DOT_REGEXP = RegExpWrapper.create('\\.'); + const CLASS_PREFIX = 'class.'; var classSettersCache = StringMapWrapper.create(); @@ -36,6 +38,29 @@ function classSetterFactory(className:string) { return setterFn; } +const STYLE_PREFIX = 'style.'; +var styleSettersCache = StringMapWrapper.create(); + +function styleSetterFactory(styleName:string, stylesuffix:string) { + var cacheKey = styleName + stylesuffix; + var setterFn = StringMapWrapper.get(styleSettersCache, cacheKey); + + if (isBlank(setterFn)) { + setterFn = function(element:Element, value) { + var valAsStr; + if (isPresent(value)) { + valAsStr = stringify(value); + DOM.setStyle(element, styleName, valAsStr + stylesuffix); + } else { + DOM.removeStyle(element, styleName); + } + }; + StringMapWrapper.set(classSettersCache, cacheKey, setterFn); + } + + return setterFn; +} + /** * Creates the ElementBinders and adds watches to the * ProtoChangeDetector. @@ -92,10 +117,14 @@ export class ElementBinderBuilder extends CompileStep { _bindElementProperties(protoView, compileElement) { MapWrapper.forEach(compileElement.propertyBindings, (expression, property) => { - var setterFn; - + var setterFn, styleParts, styleSuffix; + if (StringWrapper.startsWith(property, CLASS_PREFIX)) { setterFn = classSetterFactory(StringWrapper.substring(property, CLASS_PREFIX.length)); + } else if (StringWrapper.startsWith(property, STYLE_PREFIX)) { + styleParts = StringWrapper.split(property, DOT_REGEXP); + styleSuffix = styleParts.length > 2 ? ListWrapper.get(styleParts, 2) : ''; + setterFn = styleSetterFactory(ListWrapper.get(styleParts, 1), styleSuffix); } else if (DOM.hasProperty(compileElement.element, property)) { setterFn = reflector.setter(property); } diff --git a/modules/angular2/src/facade/dom.dart b/modules/angular2/src/facade/dom.dart index 7e86c4bd9a..c250ec5017 100644 --- a/modules/angular2/src/facade/dom.dart +++ b/modules/angular2/src/facade/dom.dart @@ -120,6 +120,16 @@ class DOM { static bool hasClass(Element element, String classname) => element.classes.contains(classname); + static setStyle(Element element, String stylename, String stylevalue) { + element.style.setProperty(stylename, stylevalue); + } + static removeStyle(Element element, String stylename) { + element.style.removeProperty(stylename); + } + static getStyle(Element element, String stylename) { + return element.style.getPropertyValue(stylename); + } + static String tagName(Element element) => element.tagName; static Map attributeMap(Element element) => diff --git a/modules/angular2/src/facade/dom.es6 b/modules/angular2/src/facade/dom.es6 index faaa1ca3ec..bd14f254f4 100644 --- a/modules/angular2/src/facade/dom.es6 +++ b/modules/angular2/src/facade/dom.es6 @@ -139,6 +139,15 @@ export class DOM { static hasClass(element:Element, classname:string) { return element.classList.contains(classname); } + static setStyle(element:Element, stylename:string, stylevalue:string) { + element.style[stylename] = stylevalue; + } + static removeStyle(element:Element, stylename:string) { + element.style[stylename] = null; + } + static getStyle(element:Element, stylename:string) { + return element.style[stylename]; + } static tagName(element:Element):string { return element.tagName; } diff --git a/modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js b/modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js index f74e4be00e..f406bf2045 100644 --- a/modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js +++ b/modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js @@ -178,6 +178,73 @@ export function main() { expect(view.nodes[0].hidden).toEqual(false); }); + it('should bind class with a dot', () => { + var propertyBindings = MapWrapper.createFromStringMap({ + 'class.bar': 'prop1', + }); + var pipeline = createPipeline({propertyBindings: propertyBindings}); + var results = pipeline.process(el('')); + var pv = results[0].inheritedProtoView; + + expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true); + + instantiateView(pv); + + evalContext.prop1 = true; + changeDetector.detectChanges(); + expect(view.nodes[0].className).toEqual('foo ng-binding bar'); + + evalContext.prop1 = false; + changeDetector.detectChanges(); + expect(view.nodes[0].className).toEqual('foo ng-binding'); + }); + + it('should bind style with a dot', () => { + var propertyBindings = MapWrapper.createFromStringMap({ + 'style.color': 'prop1', + }); + var pipeline = createPipeline({propertyBindings: propertyBindings}); + var results = pipeline.process(el('
')); + var pv = results[0].inheritedProtoView; + + expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true); + + instantiateView(pv); + + evalContext.prop1 = 'red'; + changeDetector.detectChanges(); + expect(view.nodes[0].style.color).toEqual('red'); + + evalContext.prop1 = 'blue'; + changeDetector.detectChanges(); + expect(view.nodes[0].style.color).toEqual('blue'); + }); + + it('should bind style with a dot and suffix', () => { + var propertyBindings = MapWrapper.createFromStringMap({ + 'style.font-size.px': 'prop1', + }); + var pipeline = createPipeline({propertyBindings: propertyBindings}); + var results = pipeline.process(el('
')); + var pv = results[0].inheritedProtoView; + + expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true); + + instantiateView(pv); + + evalContext.prop1 = 10; + changeDetector.detectChanges(); + expect(DOM.getStyle(view.nodes[0], 'font-size')).toEqual('10px'); + + evalContext.prop1 = 20; + changeDetector.detectChanges(); + expect(DOM.getStyle(view.nodes[0], 'font-size')).toEqual('20px'); + + evalContext.prop1 = null; + changeDetector.detectChanges(); + expect(DOM.getStyle(view.nodes[0], 'font-size')).toEqual(''); + }); + it('should bind events', () => { var eventBindings = MapWrapper.createFromStringMap({ 'event1': '1+1'