Skip to content

Commit 6ad7b40

Browse files
crisbetoAndrewKushnir
authored andcommitted
fix(platform-server): invalid style attribute being generated for null values (#46433)
Fixes that the server renderer was producing an invalid `style` attribute when a null value is passed in. Also aligns the behavior with the DOM renderer by removing the attribute when it's empty. Fixes #46385. PR Close #46433
1 parent 5d3b97e commit 6ad7b40

File tree

2 files changed

+32
-38
lines changed

2 files changed

+32
-38
lines changed

packages/core/test/acceptance/styling_spec.ts

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
1616
import {expectPerfCounters} from '@angular/private/testing';
1717

1818
describe('styling', () => {
19-
/**
20-
* This helper function tests to see if the current browser supports non standard way of writing
21-
* into styles.
22-
*
23-
* This is not the correct way to write to style and is not supported in IE11.
24-
* ```
25-
* div.style = 'color: white';
26-
* ```
27-
*
28-
* This is the correct way to write to styles:
29-
* ```
30-
* div.style.cssText = 'color: white';
31-
* ```
32-
*
33-
* Even though writing to `div.style` is not officially supported, it works in all
34-
* browsers except IE11.
35-
*
36-
* This function detects this condition and allows us to skip affected tests.
37-
*/
38-
let _supportsWritingStringsToStyleProperty: boolean|null = null;
39-
function supportsWritingStringsToStyleProperty() {
40-
if (_supportsWritingStringsToStyleProperty === null) {
41-
const div = document.createElement('div');
42-
const CSS = 'color: white;';
43-
try {
44-
(div as any).style = CSS;
45-
} catch (e) {
46-
_supportsWritingStringsToStyleProperty = false;
47-
}
48-
_supportsWritingStringsToStyleProperty = (div.style.cssText === CSS);
49-
}
50-
return _supportsWritingStringsToStyleProperty;
51-
}
52-
5319
beforeEach(ngDevModeResetPerfCounters);
5420

5521
describe('apply in prioritization order', () => {
@@ -1406,6 +1372,26 @@ describe('styling', () => {
14061372
expect(element.classList.contains('dir-two')).toBeTruthy();
14071373
});
14081374

1375+
it('should not write empty style values to the DOM', () => {
1376+
@Component({
1377+
template: `
1378+
<div
1379+
[style.color]="null"
1380+
[style.--bg-color]="undefined"
1381+
[style.margin]="''"
1382+
[style.font-size]="' '"></div>
1383+
`
1384+
})
1385+
class Cmp {
1386+
}
1387+
1388+
TestBed.configureTestingModule({declarations: [Cmp]});
1389+
const fixture = TestBed.createComponent(Cmp);
1390+
fixture.detectChanges();
1391+
1392+
expect(fixture.nativeElement.innerHTML).toBe('<div></div>');
1393+
});
1394+
14091395
describe('NgClass', () => {
14101396
// We had a bug where NgClass would not allocate sufficient slots for host bindings,
14111397
// so it would overwrite information about other directives nearby. This test checks

packages/platform-server/src/server_renderer.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,12 @@ class DefaultServerRenderer2 implements Renderer2 {
155155

156156
setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void {
157157
style = style.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
158+
value = value == null ? '' : `${value}`.trim();
158159
const styleMap = _readStyleAttribute(el);
159160
if (flags & RendererStyleFlags2.Important) {
160161
value += ' !important';
161162
}
162-
styleMap[style] = value == null ? '' : value;
163+
styleMap[style] = value;
163164
_writeStyleAttribute(el, styleMap);
164165
}
165166

@@ -297,12 +298,19 @@ function _readStyleAttribute(element: any): {[name: string]: string} {
297298
}
298299

299300
function _writeStyleAttribute(element: any, styleMap: {[name: string]: string}) {
301+
// We have to construct the `style` attribute ourselves, instead of going through
302+
// `element.style.setProperty` like the other renderers, because `setProperty` won't
303+
// write newer CSS properties that Domino doesn't know about like `clip-path`.
300304
let styleAttrValue = '';
301305
for (const key in styleMap) {
302306
const newValue = styleMap[key];
303-
if (newValue != null) {
304-
styleAttrValue += key + ':' + styleMap[key] + ';';
307+
if (newValue != null && newValue !== '') {
308+
styleAttrValue += key + ':' + newValue + ';';
305309
}
306310
}
307-
element.setAttribute('style', styleAttrValue);
311+
if (styleAttrValue) {
312+
element.setAttribute('style', styleAttrValue);
313+
} else {
314+
element.removeAttribute('style');
315+
}
308316
}

0 commit comments

Comments
 (0)