fix(ivy): avoid generating instructions for empty style and class bindings (#30024)
Fixes Ivy throwing an error because it tries to generate styling instructions for empty `style` and `class` bindings. This PR resolves FW-1274. PR Close #30024
This commit is contained in:
parent
a9242c4fc2
commit
63523f7964
|
@ -649,6 +649,30 @@ describe('compiler compliance: styling', () => {
|
|||
expectEmit(result.source, template, 'Incorrect template');
|
||||
|
||||
});
|
||||
|
||||
it('should not create instructions for empty style bindings', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`<div [style.color]></div>\`
|
||||
})
|
||||
export class MyComponent {
|
||||
}
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
expect(result.source).not.toContain('elementStyling');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('[class]', () => {
|
||||
|
@ -802,6 +826,30 @@ describe('compiler compliance: styling', () => {
|
|||
const result = compile(files, angularFiles);
|
||||
expectEmit(result.source, template, 'Incorrect template');
|
||||
});
|
||||
|
||||
it('should not create instructions for empty class bindings', () => {
|
||||
const files = {
|
||||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`<div [class.is-open]></div>\`
|
||||
})
|
||||
export class MyComponent {
|
||||
}
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const result = compile(files, angularFiles);
|
||||
expect(result.source).not.toContain('elementStyling');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('[style] mixed with [class]', () => {
|
||||
|
|
|
@ -10,6 +10,7 @@ import {AttributeMarker} from '../../core';
|
|||
import {AST, BindingType, Interpolation} from '../../expression_parser/ast';
|
||||
import * as o from '../../output/output_ast';
|
||||
import {ParseSourceSpan} from '../../parse_util';
|
||||
import {isEmptyExpression} from '../../template_parser/template_parser';
|
||||
import * as t from '../r3_ast';
|
||||
import {Identifiers as R3} from '../r3_identifiers';
|
||||
|
||||
|
@ -160,7 +161,10 @@ export class StylingBuilder {
|
|||
|
||||
registerStyleInput(
|
||||
name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan,
|
||||
unit?: string|null): BoundStylingEntry {
|
||||
unit?: string|null): BoundStylingEntry|null {
|
||||
if (isEmptyExpression(value)) {
|
||||
return null;
|
||||
}
|
||||
const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name);
|
||||
const entry: BoundStylingEntry = {
|
||||
name: property,
|
||||
|
@ -180,7 +184,10 @@ export class StylingBuilder {
|
|||
}
|
||||
|
||||
registerClassInput(name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan):
|
||||
BoundStylingEntry {
|
||||
BoundStylingEntry|null {
|
||||
if (isEmptyExpression(value)) {
|
||||
return null;
|
||||
}
|
||||
const {property, hasOverrideFlag} = parseProperty(name);
|
||||
const entry:
|
||||
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, unit: null};
|
||||
|
|
|
@ -899,7 +899,7 @@ export function removeSummaryDuplicates<T extends{type: CompileTypeMetadata}>(it
|
|||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
function isEmptyExpression(ast: AST): boolean {
|
||||
export function isEmptyExpression(ast: AST): boolean {
|
||||
if (ast instanceof ASTWithSource) {
|
||||
ast = ast.ast;
|
||||
}
|
||||
|
|
|
@ -106,4 +106,28 @@ describe('styling', () => {
|
|||
const outer = element.querySelector('.outer-area');
|
||||
expect(outer.textContent.trim()).toEqual('outer');
|
||||
});
|
||||
|
||||
it('should do nothing for empty style bindings', () => {
|
||||
@Component({template: '<div [style.color]></div>'})
|
||||
class App {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toBe('<div></div>');
|
||||
});
|
||||
|
||||
it('should do nothing for empty class bindings', () => {
|
||||
@Component({template: '<div [class.is-open]></div>'})
|
||||
class App {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App]});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toBe('<div></div>');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue