Skip to content

Commit b50edfd

Browse files
committedJun 26, 2015
feat(NgStyle): add new NgStyle directive
Closes #2665
1 parent dd79103 commit b50edfd

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {Directive, onCheck} from 'angular2/annotations';
2+
import {ElementRef} from 'angular2/core';
3+
import {Pipe} from 'angular2/src/change_detection/pipes/pipe';
4+
import {PipeRegistry} from 'angular2/src/change_detection/pipes/pipe_registry';
5+
import {KeyValueChanges} from 'angular2/src/change_detection/pipes/keyvalue_changes';
6+
import {isPresent, print} from 'angular2/src/facade/lang';
7+
import {Renderer} from 'angular2/src/render/api';
8+
9+
@Directive({selector: '[ng-style]', lifecycle: [onCheck], properties: ['rawStyle: ng-style']})
10+
export class NgStyle {
11+
_pipe: Pipe;
12+
_rawStyle;
13+
14+
constructor(private _pipeRegistry: PipeRegistry, private _ngEl: ElementRef,
15+
private _renderer: Renderer) {}
16+
17+
set rawStyle(v) {
18+
this._rawStyle = v;
19+
this._pipe = this._pipeRegistry.get('keyValDiff', this._rawStyle);
20+
}
21+
22+
onCheck() {
23+
var diff = this._pipe.transform(this._rawStyle);
24+
if (isPresent(diff) && isPresent(diff.wrapped)) {
25+
this._applyChanges(diff.wrapped);
26+
}
27+
}
28+
29+
private _applyChanges(diff: KeyValueChanges): void {
30+
diff.forEachAddedItem((record) => { this._setStyle(record.key, record.currentValue); });
31+
diff.forEachChangedItem((record) => { this._setStyle(record.key, record.currentValue); });
32+
diff.forEachRemovedItem((record) => { this._setStyle(record.key, null); });
33+
}
34+
35+
private _setStyle(name: string, val: string): void {
36+
this._renderer.setElementStyle(this._ngEl, name, val);
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import {
2+
AsyncTestCompleter,
3+
beforeEach,
4+
beforeEachBindings,
5+
ddescribe,
6+
xdescribe,
7+
describe,
8+
el,
9+
expect,
10+
iit,
11+
inject,
12+
it,
13+
xit,
14+
} from 'angular2/test_lib';
15+
16+
import {StringMapWrapper} from 'angular2/src/facade/collection';
17+
18+
import {Component, View} from 'angular2/angular2';
19+
20+
import {TestBed} from 'angular2/src/test_lib/test_bed';
21+
import {DOM} from 'angular2/src/dom/dom_adapter';
22+
import {NgStyle} from 'angular2/src/directives/ng_style';
23+
24+
export function main() {
25+
describe('binding to CSS styles', () => {
26+
27+
it('should add styles specified in an object literal',
28+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
29+
var template = `<div [ng-style]="{'text-align': 'right'}"></div>`;
30+
31+
tb.createView(TestComponent, {html: template})
32+
.then((view) => {
33+
view.detectChanges();
34+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('right');
35+
36+
async.done();
37+
});
38+
}));
39+
40+
it('should add and change styles specified in an object expression',
41+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
42+
var template = `<div [ng-style]="expr"></div>`;
43+
44+
tb.createView(TestComponent, {html: template})
45+
.then((view) => {
46+
var expr: Map<string, any>;
47+
48+
view.context.expr = {'text-align': 'right'};
49+
view.detectChanges();
50+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('right');
51+
52+
expr = view.context.expr;
53+
expr['text-align'] = 'left';
54+
view.detectChanges();
55+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('left');
56+
57+
async.done();
58+
});
59+
}));
60+
61+
it('should remove styles when deleting a key in an object expression',
62+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
63+
var template = `<div [ng-style]="expr"></div>`;
64+
65+
tb.createView(TestComponent, {html: template})
66+
.then((view) => {
67+
view.context.expr = {'text-align': 'right'};
68+
view.detectChanges();
69+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('right');
70+
71+
StringMapWrapper.delete(view.context.expr, 'text-align');
72+
view.detectChanges();
73+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('');
74+
75+
async.done();
76+
});
77+
}));
78+
79+
it('should co-operate with the style attribute',
80+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
81+
var template = `<div style="font-size: 12px" [ng-style]="expr"></div>`;
82+
83+
tb.createView(TestComponent, {html: template})
84+
.then((view) => {
85+
view.context.expr = {'text-align': 'right'};
86+
view.detectChanges();
87+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('right');
88+
expect(DOM.getStyle(view.rootNodes[0], 'font-size')).toEqual('12px');
89+
90+
StringMapWrapper.delete(view.context.expr, 'text-align');
91+
view.detectChanges();
92+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('');
93+
expect(DOM.getStyle(view.rootNodes[0], 'font-size')).toEqual('12px');
94+
95+
async.done();
96+
});
97+
}));
98+
99+
it('should co-operate with the style.[styleName]="expr" special-case in the compiler',
100+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
101+
var template = `<div [style.font-size.px]="12" [ng-style]="expr"></div>`;
102+
103+
tb.createView(TestComponent, {html: template})
104+
.then((view) => {
105+
view.context.expr = {'text-align': 'right'};
106+
view.detectChanges();
107+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('right');
108+
expect(DOM.getStyle(view.rootNodes[0], 'font-size')).toEqual('12px');
109+
110+
StringMapWrapper.delete(view.context.expr, 'text-align');
111+
expect(DOM.getStyle(view.rootNodes[0], 'font-size')).toEqual('12px');
112+
113+
view.detectChanges();
114+
expect(DOM.getStyle(view.rootNodes[0], 'text-align')).toEqual('');
115+
116+
async.done();
117+
});
118+
}));
119+
})
120+
}
121+
122+
@Component({selector: 'test-cmp'})
123+
@View({directives: [NgStyle]})
124+
class TestComponent {
125+
expr;
126+
}

0 commit comments

Comments
 (0)
Please sign in to comment.