Skip to content

Commit 3af103a

Browse files
committed
fix(core): support sanitizer value in the [style] bindings (angular#35564)
When binding to `[style]` we correctly sanitized/unwrapped properties but we did not do it for the object itself. ``` @HostBinding("style") style: SafeStyle = this.sanitizer.bypassSecurityTrustStyle( "background: red; color: white; display: block;" ); ``` Above code would fail since the `[style]` would not unwrap the `SafeValue` and would treat it as object resulting in incorrect behavior. Fix angular#35476 (FW-1875) PR Close angular#35564
1 parent 975a11b commit 3af103a

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed

packages/core/src/render3/instructions/styling.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -625,23 +625,25 @@ export function getHostDirectiveDef(tData: TData): DirectiveDef<any>|null {
625625
export function toStylingKeyValueArray(
626626
keyValueArraySet: (keyValueArray: KeyValueArray<any>, key: string, value: any) => void,
627627
stringParser: (styleKeyValueArray: KeyValueArray<any>, text: string) => void,
628-
value: string|string[]|{[key: string]: any}|null|undefined): KeyValueArray<any> {
628+
value: string|string[]|{[key: string]: any}|SafeValue|null|undefined): KeyValueArray<any> {
629629
if (value == null /*|| value === undefined */ || value === '') return EMPTY_ARRAY as any;
630630
const styleKeyValueArray: KeyValueArray<any> = [] as any;
631-
if (Array.isArray(value)) {
632-
for (let i = 0; i < value.length; i++) {
633-
keyValueArraySet(styleKeyValueArray, value[i], true);
631+
const unwrappedValue = unwrapSafeValue(value) as string | string[] | {[key: string]: any};
632+
if (Array.isArray(unwrappedValue)) {
633+
for (let i = 0; i < unwrappedValue.length; i++) {
634+
keyValueArraySet(styleKeyValueArray, unwrappedValue[i], true);
634635
}
635-
} else if (typeof value === 'object') {
636-
for (const key in value) {
637-
if (value.hasOwnProperty(key)) {
638-
keyValueArraySet(styleKeyValueArray, key, value[key]);
636+
} else if (typeof unwrappedValue === 'object') {
637+
for (const key in unwrappedValue) {
638+
if (unwrappedValue.hasOwnProperty(key)) {
639+
keyValueArraySet(styleKeyValueArray, key, unwrappedValue[key]);
639640
}
640641
}
641-
} else if (typeof value === 'string') {
642-
stringParser(styleKeyValueArray, value);
642+
} else if (typeof unwrappedValue === 'string') {
643+
stringParser(styleKeyValueArray, unwrappedValue);
643644
} else {
644-
ngDevMode && throwError('Unsupported styling type ' + typeof value + ': ' + value);
645+
ngDevMode &&
646+
throwError('Unsupported styling type ' + typeof unwrappedValue + ': ' + unwrappedValue);
645647
}
646648
return styleKeyValueArray;
647649
}

packages/core/test/acceptance/styling_spec.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,55 @@ describe('styling', () => {
33843384
});
33853385

33863386
describe('regression', () => {
3387+
it('should support sanitizer value in the [style] bindings', () => {
3388+
if (!ivyEnabled && !supportsWritingStringsToStyleProperty()) {
3389+
// VE does not treat `[style]` as anything special, instead it simply writes to the
3390+
// `style` property on the element like so `element.style=value`. This seems to work fine
3391+
// every where except ie10, where it throws an error and as a consequence this test fails in
3392+
// VE on ie10.
3393+
return;
3394+
}
3395+
@Component({template: `<div [style]="style"></div>`})
3396+
class HostBindingTestComponent {
3397+
style: SafeStyle = this.sanitizer.bypassSecurityTrustStyle('color: white; display: block;');
3398+
constructor(private sanitizer: DomSanitizer) {}
3399+
}
3400+
TestBed.configureTestingModule({declarations: [HostBindingTestComponent]});
3401+
const fixture = TestBed.createComponent(HostBindingTestComponent);
3402+
fixture.detectChanges();
3403+
const div: HTMLElement = fixture.nativeElement.querySelector('div');
3404+
expectStyle(div).toEqual({color: 'white', display: 'block'});
3405+
});
3406+
3407+
/**
3408+
* Tests to see if the current browser supports non standard way of writing into styles.
3409+
*
3410+
* This is not the correct way to write to style and is not supported in ie10.
3411+
* ```
3412+
* div.style = 'color: white';
3413+
* ```
3414+
*
3415+
* This is the correct way to write to styles:
3416+
* ```
3417+
* div.style.cssText = 'color: white';
3418+
* ```
3419+
*
3420+
* Even though writing to `div.style` is not officially supported, it works in all
3421+
* browsers except ie10.
3422+
*
3423+
* This function detects this condition and allows us to skip the test.
3424+
*/
3425+
function supportsWritingStringsToStyleProperty() {
3426+
const div = document.createElement('div');
3427+
const CSS = 'color: white;';
3428+
try {
3429+
(div as any).style = CSS;
3430+
} catch (e) {
3431+
return false;
3432+
}
3433+
return div.style.cssText === CSS;
3434+
}
3435+
33873436
onlyInIvy('styling priority resolution is Ivy only feature.')
33883437
.it('should allow lookahead binding on second pass #35118', () => {
33893438
@Component({
@@ -3445,4 +3494,4 @@ function expectStyle(element: HTMLElement) {
34453494

34463495
function expectClass(element: HTMLElement) {
34473496
return expect(getElementClasses(element));
3448-
}
3497+
}

0 commit comments

Comments
 (0)