diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index f7a79c3c02..e7e0be7ab0 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -625,5 +625,46 @@ describe('compiler compliance: styling', () => { expectEmit(result.source, template, 'Incorrect template'); }); + it('should stamp out pipe definitions in the creation block if used by styling bindings', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-component', + template: \`
\` + }) + export class MyComponent { + myStyleExp = [{color:'red'}, {color:'blue', duration:1000}] + myClassExp = 'foo bar apple'; + } + + @NgModule({declarations: [MyComponent]}) + export class MyModule {} + ` + } + }; + + const template = ` + template: function MyComponent_Template(rf, $ctx$) { + if (rf & 1) { + $r3$.ɵelementStart(0, "div"); + $r3$.ɵelementStyling(null, null, $r3$.ɵdefaultStyleSanitizer); + $r3$.ɵpipe(1, "classPipe"); + $r3$.ɵpipe(2, "stylePipe"); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(0, $r3$.ɵpipeBind1(1, 0, $ctx$.myClassExp), $r3$.ɵpipeBind1(2, 2, $ctx$.myStyleExp)); + $r3$.ɵelementStylingApply(0); + } + } + `; + + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect template'); + }); }); }); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 918d17a734..d5f278bcd9 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -643,18 +643,23 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const stylingInput = mapBasedStyleInput || mapBasedClassInput; if (stylingInput) { + // these values must be outside of the update block so that they can + // be evaluted (the AST visit call) during creation time so that any + // pipes can be picked up in time before the template is built + const mapBasedClassValue = + mapBasedClassInput ? mapBasedClassInput.value.visit(this._valueConverter) : null; + const mapBasedStyleValue = + mapBasedStyleInput ? mapBasedStyleInput.value.visit(this._valueConverter) : null; this.updateInstruction(stylingInput.sourceSpan, R3.elementStylingMap, () => { const params: o.Expression[] = [indexLiteral]; - if (mapBasedClassInput) { - const mapBasedClassValue = mapBasedClassInput.value.visit(this._valueConverter); + if (mapBasedClassValue) { params.push(this.convertPropertyBinding(implicit, mapBasedClassValue, true)); } else if (mapBasedStyleInput) { params.push(o.NULL_EXPR); } - if (mapBasedStyleInput) { - const mapBasedStyleValue = mapBasedStyleInput.value.visit(this._valueConverter); + if (mapBasedStyleValue) { params.push(this.convertPropertyBinding(implicit, mapBasedStyleValue, true)); }