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 in6f203c9575
). Later, the situation was improved to actually allow both bindings to co-exist (seea153b61098
), 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:
parent
2ccb579e06
commit
3a55698402
|
@ -246,10 +246,6 @@ export class StylingBuilder {
|
||||||
const entry:
|
const entry:
|
||||||
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, suffix: null};
|
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, suffix: null};
|
||||||
if (isMapBased) {
|
if (isMapBased) {
|
||||||
if (this._classMapInput) {
|
|
||||||
throw new Error(
|
|
||||||
'[class] and [className] bindings cannot be used on the same element simultaneously');
|
|
||||||
}
|
|
||||||
this._classMapInput = entry;
|
this._classMapInput = entry;
|
||||||
} else {
|
} else {
|
||||||
(this._singleClassInputs = this._singleClassInputs || []).push(entry);
|
(this._singleClassInputs = this._singleClassInputs || []).push(entry);
|
||||||
|
|
|
@ -17,6 +17,40 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing';
|
import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
describe('styling', () => {
|
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);
|
beforeEach(ngDevModeResetPerfCounters);
|
||||||
|
|
||||||
describe('apply in prioritization order', () => {
|
describe('apply in prioritization order', () => {
|
||||||
|
@ -3069,6 +3103,64 @@ describe('styling', () => {
|
||||||
expect(fixture.debugElement.nativeElement.innerHTML).toContain('three');
|
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', () => {
|
it('should allow to reset style property value defined using [style.prop.px] binding', () => {
|
||||||
@Component({
|
@Component({
|
||||||
template: '<div [style.left.px]="left"></div>',
|
template: '<div [style.left.px]="left"></div>',
|
||||||
|
@ -3625,35 +3717,6 @@ describe('styling', () => {
|
||||||
expectStyle(div).toEqual({color: 'white', display: 'block'});
|
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.')
|
onlyInIvy('styling priority resolution is Ivy only feature.')
|
||||||
.it('should allow lookahead binding on second pass #35118', () => {
|
.it('should allow lookahead binding on second pass #35118', () => {
|
||||||
@Component({
|
@Component({
|
||||||
|
|
Loading…
Reference in New Issue