fix(core): remove obsolete check for [class] and [className] presence (#41254)

Previously presence of both [class] and [className] bindings on an element was treated as compiler error (implemented in 6f203c9575). Later, the situation was improved to actually allow both bindings to co-exist (see a153b61098), however the compiler check was not removed completely. The only situation where the error is thrown at this moment is when static (but with interpolation) and bound `class` attributes are present on an element, for ex.:

```
<div class="{{ one }}" [class]="'two'"></div>
```

In the current situation the error is acually misleading (as it refers to `[className]`).

This commit removes the mentioned compiler check as obsolete and makes the `class` and `style` attribute processing logically the same (the last occurrence is used to compute the value).

PR Close #41254
This commit is contained in:
Andrew Kushnir 2021-03-17 17:20:57 -07:00 committed by Misko Hevery
parent 2ccb579e06
commit 3a55698402
2 changed files with 92 additions and 33 deletions

View File

@ -246,10 +246,6 @@ export class StylingBuilder {
const entry:
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, suffix: null};
if (isMapBased) {
if (this._classMapInput) {
throw new Error(
'[class] and [className] bindings cannot be used on the same element simultaneously');
}
this._classMapInput = entry;
} else {
(this._singleClassInputs = this._singleClassInputs || []).push(entry);

View File

@ -17,6 +17,40 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing';
describe('styling', () => {
/**
* This helper function tests to see if the current browser supports non standard way of writing
* into styles.
*
* This is not the correct way to write to style and is not supported in IE11.
* ```
* div.style = 'color: white';
* ```
*
* This is the correct way to write to styles:
* ```
* div.style.cssText = 'color: white';
* ```
*
* Even though writing to `div.style` is not officially supported, it works in all
* browsers except IE11.
*
* This function detects this condition and allows us to skip affected tests.
*/
let _supportsWritingStringsToStyleProperty: boolean|null = null;
function supportsWritingStringsToStyleProperty() {
if (_supportsWritingStringsToStyleProperty === null) {
const div = document.createElement('div');
const CSS = 'color: white;';
try {
(div as any).style = CSS;
} catch (e) {
_supportsWritingStringsToStyleProperty = false;
}
_supportsWritingStringsToStyleProperty = (div.style.cssText === CSS);
}
return _supportsWritingStringsToStyleProperty;
}
beforeEach(ngDevModeResetPerfCounters);
describe('apply in prioritization order', () => {
@ -3069,6 +3103,64 @@ describe('styling', () => {
expect(fixture.debugElement.nativeElement.innerHTML).toContain('three');
});
it('should allow static and bound `class` attribute, but use last occurrence', () => {
@Component({
template: `
<div id="first" class="zero {{one}}" [class]="'two'"></div>
<div id="second" [class]="'two'" class="zero {{one}}"></div>
`,
})
class MyComp {
one = 'one';
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
const first = fixture.nativeElement.querySelector('#first').outerHTML;
expect(first).not.toContain('zero');
expect(first).not.toContain('one');
expect(first).toContain('two');
const second = fixture.nativeElement.querySelector('#second').outerHTML;
expect(second).toContain('zero');
expect(second).toContain('one');
expect(second).not.toContain('two');
});
it('should allow static and bound `style` attribute, but use last occurrence', () => {
if (!ivyEnabled && !supportsWritingStringsToStyleProperty()) {
// VE does not treat `[style]` as anything special, instead it simply writes to the
// `style` property on the element like so `element.style=value`. This seems to work fine
// every where except IE11, where it throws an error and as a consequence this test fails in
// VE on IE11.
return;
}
@Component({
template: `
<div id="first" style="margin: {{margin}}" [style]="'padding: 20px;'"></div>
<div id="second" [style]="'padding: 20px;'" style="margin: {{margin}}"></div>
`,
})
class MyComp {
margin = '10px';
}
TestBed.configureTestingModule({declarations: [MyComp]});
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
const first = fixture.nativeElement.querySelector('#first').outerHTML;
expect(first).not.toContain('margin');
expect(first).toContain('padding');
const second = fixture.nativeElement.querySelector('#second').outerHTML;
expect(second).toContain('margin');
expect(second).not.toContain('padding');
});
it('should allow to reset style property value defined using [style.prop.px] binding', () => {
@Component({
template: '<div [style.left.px]="left"></div>',
@ -3625,35 +3717,6 @@ describe('styling', () => {
expectStyle(div).toEqual({color: 'white', display: 'block'});
});
/**
* Tests to see if the current browser supports non standard way of writing into styles.
*
* This is not the correct way to write to style and is not supported in IE11.
* ```
* div.style = 'color: white';
* ```
*
* This is the correct way to write to styles:
* ```
* div.style.cssText = 'color: white';
* ```
*
* Even though writing to `div.style` is not officially supported, it works in all
* browsers except IE11.
*
* This function detects this condition and allows us to skip the test.
*/
function supportsWritingStringsToStyleProperty() {
const div = document.createElement('div');
const CSS = 'color: white;';
try {
(div as any).style = CSS;
} catch (e) {
return false;
}
return div.style.cssText === CSS;
}
onlyInIvy('styling priority resolution is Ivy only feature.')
.it('should allow lookahead binding on second pass #35118', () => {
@Component({