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 9370eac221..4f0c9d05d6 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
@@ -454,7 +454,7 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
- $r3$.ɵɵclassMap($r3$.ɵɵinterpolation1("foo foo-", $ctx$.fooId, ""));
+ $r3$.ɵɵclassMapInterpolate1("foo foo-", $ctx$.fooId, "");
$r3$.ɵɵstylingApply();
}
}
@@ -468,7 +468,7 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
- $r3$.ɵɵclassMap($r3$.ɵɵinterpolation2("foo foo-", $ctx$.fooId, "-", $ctx$.fooUsername, ""));
+ $r3$.ɵɵclassMapInterpolate2("foo foo-", $ctx$.fooId, "-", $ctx$.fooUsername, "");
$r3$.ɵɵstylingApply();
}
}
@@ -1340,6 +1340,239 @@ describe('compiler compliance: styling', () => {
});
});
+ describe('interpolations', () => {
+ it('should generate the proper update instructions for interpolated classes', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: \`
+
+
+
+
+
+
+
+
+
+
+ \`
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ const template = `
+ …
+ if (rf & 2) {
+ $r3$.ɵɵclassMapInterpolateV(["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(1);
+ $r3$.ɵɵclassMapInterpolate8("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(2);
+ $r3$.ɵɵclassMapInterpolate7("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(3);
+ $r3$.ɵɵclassMapInterpolate6("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(4);
+ $r3$.ɵɵclassMapInterpolate5("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(5);
+ $r3$.ɵɵclassMapInterpolate4("a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(6);
+ $r3$.ɵɵclassMapInterpolate3("a", ctx.one, "b", ctx.two, "c", ctx.three, "d");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(7);
+ $r3$.ɵɵclassMapInterpolate2("a", ctx.one, "b", ctx.two, "c");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(8);
+ $r3$.ɵɵclassMapInterpolate1("a", ctx.one, "b");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(9);
+ $r3$.ɵɵclassMap(ctx.one);
+ $r3$.ɵɵstylingApply();
+ }
+ …
+ `;
+ const result = compile(files, angularFiles);
+
+ expectEmit(result.source, template, 'Incorrect handling of interpolated classes');
+ });
+
+ it('should throw for interpolations inside `style`', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: ''
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ expect(() => compile(files, angularFiles)).toThrowError(/Unexpected interpolation/);
+ });
+
+ it('should throw for interpolations inside individual class bindings', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: ''
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ expect(() => compile(files, angularFiles)).toThrowError(/Unexpected interpolation/);
+ });
+
+ it('should generate the proper update instructions for interpolated style properties', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: \`
+
+
+
+
+
+
+
+
+
+
+ \`
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ const template = `
+ …
+ if (rf & 2) {
+ $r3$.ɵɵstylePropInterpolateV(0, ["a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i", ctx.nine, "j"]);
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(1);
+ $r3$.ɵɵstylePropInterpolate8(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h", ctx.eight, "i");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(2);
+ $r3$.ɵɵstylePropInterpolate7(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g", ctx.seven, "h");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(3);
+ $r3$.ɵɵstylePropInterpolate6(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f", ctx.six, "g");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(4);
+ $r3$.ɵɵstylePropInterpolate5(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e", ctx.five, "f");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(5);
+ $r3$.ɵɵstylePropInterpolate4(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d", ctx.four, "e");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(6);
+ $r3$.ɵɵstylePropInterpolate3(0, "a", ctx.one, "b", ctx.two, "c", ctx.three, "d");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(7);
+ $r3$.ɵɵstylePropInterpolate2(0, "a", ctx.one, "b", ctx.two, "c");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(8);
+ $r3$.ɵɵstylePropInterpolate1(0, "a", ctx.one, "b");
+ $r3$.ɵɵstylingApply();
+ $r3$.ɵɵselect(9);
+ $r3$.ɵɵstyleProp(0, ctx.one);
+ $r3$.ɵɵstylingApply();
+ }
+ …
+ `;
+ const result = compile(files, angularFiles);
+
+ expectEmit(result.source, template, 'Incorrect handling of interpolated style properties');
+ });
+
+ it('should generate update instructions for interpolated style properties with a suffix',
+ () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: \`
+
+ \`
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ const template = `
+ …
+ if (rf & 2) {
+ $r3$.ɵɵstylePropInterpolate2(0, "a", ctx.one, "b", ctx.two, "c", "px");
+ $r3$.ɵɵstylingApply();
+ }
+ …
+ `;
+ const result = compile(files, angularFiles);
+
+ expectEmit(result.source, template, 'Incorrect handling of interpolated style properties');
+ });
+
+ it('should generate update instructions for interpolated style properties with !important',
+ () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: \`
+
+ \`
+ })
+ export class MyComponent {
+ }
+ `
+ }
+ };
+
+ const template = `
+ …
+ if (rf & 2) {
+ $r3$.ɵɵstylePropInterpolate2(0, "a", ctx.one, "b", ctx.two, "c", null, true);
+ $r3$.ɵɵstylingApply();
+ }
+ …
+ `;
+ const result = compile(files, angularFiles);
+
+ expectEmit(result.source, template, 'Incorrect handling of interpolated style properties');
+ });
+
+ });
+
it('should count only non-style and non-class host bindings on Components', () => {
const files = {
app: {
diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts
index 4b903693ab..75f8312305 100644
--- a/packages/compiler/src/render3/r3_identifiers.ts
+++ b/packages/compiler/src/render3/r3_identifiers.ts
@@ -72,8 +72,46 @@ export class Identifiers {
static classMap: o.ExternalReference = {name: 'ɵɵclassMap', moduleName: CORE};
+ static classMapInterpolate1:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate1', moduleName: CORE};
+ static classMapInterpolate2:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate2', moduleName: CORE};
+ static classMapInterpolate3:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate3', moduleName: CORE};
+ static classMapInterpolate4:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate4', moduleName: CORE};
+ static classMapInterpolate5:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate5', moduleName: CORE};
+ static classMapInterpolate6:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate6', moduleName: CORE};
+ static classMapInterpolate7:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate7', moduleName: CORE};
+ static classMapInterpolate8:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolate8', moduleName: CORE};
+ static classMapInterpolateV:
+ o.ExternalReference = {name: 'ɵɵclassMapInterpolateV', moduleName: CORE};
+
static styleProp: o.ExternalReference = {name: 'ɵɵstyleProp', moduleName: CORE};
+ static stylePropInterpolate1:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate1', moduleName: CORE};
+ static stylePropInterpolate2:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate2', moduleName: CORE};
+ static stylePropInterpolate3:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate3', moduleName: CORE};
+ static stylePropInterpolate4:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate4', moduleName: CORE};
+ static stylePropInterpolate5:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate5', moduleName: CORE};
+ static stylePropInterpolate6:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate6', moduleName: CORE};
+ static stylePropInterpolate7:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate7', moduleName: CORE};
+ static stylePropInterpolate8:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolate8', moduleName: CORE};
+ static stylePropInterpolateV:
+ o.ExternalReference = {name: 'ɵɵstylePropInterpolateV', moduleName: CORE};
+
static stylingApply: o.ExternalReference = {name: 'ɵɵstylingApply', moduleName: CORE};
static styleSanitizer: o.ExternalReference = {name: 'ɵɵstyleSanitizer', moduleName: CORE};
diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts
index f2efe3a0bd..c0b0af36f2 100644
--- a/packages/compiler/src/render3/view/compiler.ts
+++ b/packages/compiler/src/render3/view/compiler.ts
@@ -12,7 +12,7 @@ import {CompileReflector} from '../../compile_reflector';
import {BindingForm, convertPropertyBinding} from '../../compiler_util/expression_converter';
import {ConstantPool, DefinitionKind} from '../../constant_pool';
import * as core from '../../core';
-import {AST, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast';
+import {AST, Interpolation, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast';
import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config';
import * as o from '../../output/output_ast';
import {ParseError, ParseSourceSpan, typeSourceSpan} from '../../parse_util';
@@ -28,7 +28,7 @@ import {Render3ParseResult} from '../r3_template_transform';
import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util';
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from './api';
-import {Instruction, StylingBuilder} from './styling_builder';
+import {StylingBuilder, StylingInstruction} from './styling_builder';
import {BindingScope, TemplateDefinitionBuilder, ValueConverter, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn} from './template';
import {CONTEXT_NAME, DefinitionMap, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator} from './util';
@@ -777,8 +777,8 @@ function bindingFn(implicit: any, value: AST) {
}
function createStylingStmt(
- instruction: Instruction, bindingContext: any, bindingFn: Function): o.Statement {
- const params = instruction.buildParams(value => bindingFn(bindingContext, value).currValExpr);
+ instruction: StylingInstruction, bindingContext: any, bindingFn: Function): o.Statement {
+ const params = instruction.params(value => bindingFn(bindingContext, value).currValExpr);
return o.importExpr(instruction.reference, null, instruction.sourceSpan)
.callFn(params, instruction.sourceSpan)
.toStmt();
diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts
index 3ca675ecaf..26133a1eed 100644
--- a/packages/compiler/src/render3/view/styling_builder.ts
+++ b/packages/compiler/src/render3/view/styling_builder.ts
@@ -11,23 +11,26 @@ 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 {error} from '../../util';
import * as t from '../r3_ast';
import {Identifiers as R3} from '../r3_identifiers';
import {parse as parseStyle} from './style_parser';
import {compilerIsNewStylingInUse} from './styling_state';
import {ValueConverter} from './template';
+import {getInterpolationArgsLength} from './util';
const IMPORTANT_FLAG = '!important';
/**
* A styling expression summary that is to be processed by the compiler
*/
-export interface Instruction {
+export interface StylingInstruction {
sourceSpan: ParseSourceSpan|null;
reference: o.ExternalReference;
allocateBindingSlots: number;
- buildParams(convertFn: (value: any) => o.Expression): o.Expression[];
+ supportsInterpolation?: boolean;
+ params: ((convertFn: (value: any) => o.Expression | o.Expression[]) => o.Expression[]);
}
/**
@@ -261,13 +264,13 @@ export class StylingBuilder {
*/
buildHostAttrsInstruction(
sourceSpan: ParseSourceSpan|null, attrs: o.Expression[],
- constantPool: ConstantPool): Instruction|null {
+ constantPool: ConstantPool): StylingInstruction|null {
if (this._directiveExpr && (attrs.length || this._hasInitialValues)) {
return {
sourceSpan,
reference: R3.elementHostAttrs,
allocateBindingSlots: 0,
- buildParams: () => {
+ params: () => {
// params => elementHostAttrs(attrs)
this.populateInitialStylingAttrs(attrs);
const attrArray = !attrs.some(attr => attr instanceof o.WrappedNodeExpr) ?
@@ -286,14 +289,14 @@ export class StylingBuilder {
* The instruction generation code below is used for producing the AOT statement code which is
* responsible for registering style/class bindings to an element.
*/
- buildStylingInstruction(sourceSpan: ParseSourceSpan|null, constantPool: ConstantPool): Instruction
- |null {
+ buildStylingInstruction(sourceSpan: ParseSourceSpan|null, constantPool: ConstantPool):
+ StylingInstruction|null {
if (this.hasBindings) {
return {
sourceSpan,
allocateBindingSlots: 0,
reference: R3.styling,
- buildParams: () => {
+ params: () => {
// a string array of every style-based binding
const styleBindingProps =
this._singleStyleInputs ? this._singleStyleInputs.map(i => o.literal(i.name)) : [];
@@ -344,7 +347,7 @@ export class StylingBuilder {
* The instruction data will contain all expressions for `classMap` to function
* which includes the `[class]` expression params.
*/
- buildClassMapInstruction(valueConverter: ValueConverter): Instruction|null {
+ buildClassMapInstruction(valueConverter: ValueConverter): StylingInstruction|null {
if (this._classMapInput) {
return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput);
}
@@ -357,7 +360,7 @@ export class StylingBuilder {
* The instruction data will contain all expressions for `styleMap` to function
* which includes the `[style]` expression params.
*/
- buildStyleMapInstruction(valueConverter: ValueConverter): Instruction|null {
+ buildStyleMapInstruction(valueConverter: ValueConverter): StylingInstruction|null {
if (this._styleMapInput) {
return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput);
}
@@ -365,7 +368,8 @@ export class StylingBuilder {
}
private _buildMapBasedInstruction(
- valueConverter: ValueConverter, isClassBased: boolean, stylingInput: BoundStylingEntry) {
+ valueConverter: ValueConverter, isClassBased: boolean,
+ stylingInput: BoundStylingEntry): StylingInstruction {
let totalBindingSlotsRequired = 0;
if (compilerIsNewStylingInUse()) {
// the old implementation does not reserve slot values for
@@ -377,27 +381,42 @@ export class StylingBuilder {
// be evaluated (the AST visit call) during creation time so that any
// pipes can be picked up in time before the template is built
const mapValue = stylingInput.value.visit(valueConverter);
- if (mapValue instanceof Interpolation) {
+ let reference: o.ExternalReference;
+ if (mapValue instanceof Interpolation && isClassBased) {
totalBindingSlotsRequired += mapValue.expressions.length;
+ reference = getClassMapInterpolationExpression(mapValue);
+ } else {
+ reference = isClassBased ? R3.classMap : R3.styleMap;
}
- const reference = isClassBased ? R3.classMap : R3.styleMap;
return {
sourceSpan: stylingInput.sourceSpan,
reference,
allocateBindingSlots: totalBindingSlotsRequired,
- buildParams: (convertFn: (value: any) => o.Expression) => { return [convertFn(mapValue)]; }
+ supportsInterpolation: isClassBased,
+ params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
+ const convertResult = convertFn(mapValue);
+ return Array.isArray(convertResult) ? convertResult : [convertResult];
+ }
};
}
private _buildSingleInputs(
reference: o.ExternalReference, inputs: BoundStylingEntry[], mapIndex: Map,
- allowUnits: boolean, valueConverter: ValueConverter): Instruction[] {
+ allowUnits: boolean, valueConverter: ValueConverter,
+ getInterpolationExpressionFn?: (value: Interpolation) => o.ExternalReference):
+ StylingInstruction[] {
let totalBindingSlotsRequired = 0;
return inputs.map(input => {
const bindingIndex: number = mapIndex.get(input.name !) !;
const value = input.value.visit(valueConverter);
- totalBindingSlotsRequired += (value instanceof Interpolation) ? value.expressions.length : 0;
+ if (value instanceof Interpolation) {
+ totalBindingSlotsRequired += value.expressions.length;
+
+ if (getInterpolationExpressionFn) {
+ reference = getInterpolationExpressionFn(value);
+ }
+ }
if (compilerIsNewStylingInUse()) {
// the old implementation does not reserve slot values for
// binding entries. The new one does.
@@ -405,14 +424,18 @@ export class StylingBuilder {
}
return {
sourceSpan: input.sourceSpan,
+ supportsInterpolation: !!getInterpolationExpressionFn,
allocateBindingSlots: totalBindingSlotsRequired, reference,
- buildParams: (convertFn: (value: any) => o.Expression) => {
+ params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
// min params => stylingProp(elmIndex, bindingIndex, value)
// max params => stylingProp(elmIndex, bindingIndex, value, overrideFlag)
- const params: o.Expression[] = [];
- params.push(o.literal(bindingIndex));
- params.push(convertFn(value));
-
+ const params: o.Expression[] = [o.literal(bindingIndex)];
+ const convertResult = convertFn(value);
+ if (Array.isArray(convertResult)) {
+ params.push(...convertResult);
+ } else {
+ params.push(convertResult);
+ }
if (allowUnits) {
if (input.unit) {
params.push(o.literal(input.unit));
@@ -431,7 +454,7 @@ export class StylingBuilder {
});
}
- private _buildClassInputs(valueConverter: ValueConverter): Instruction[] {
+ private _buildClassInputs(valueConverter: ValueConverter): StylingInstruction[] {
if (this._singleClassInputs) {
return this._buildSingleInputs(
R3.classProp, this._singleClassInputs, this._classesIndex, false, valueConverter);
@@ -439,29 +462,30 @@ export class StylingBuilder {
return [];
}
- private _buildStyleInputs(valueConverter: ValueConverter): Instruction[] {
+ private _buildStyleInputs(valueConverter: ValueConverter): StylingInstruction[] {
if (this._singleStyleInputs) {
return this._buildSingleInputs(
- R3.styleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter);
+ R3.styleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter,
+ getStylePropInterpolationExpression);
}
return [];
}
- private _buildApplyFn(): Instruction {
+ private _buildApplyFn(): StylingInstruction {
return {
sourceSpan: this._lastStylingInput ? this._lastStylingInput.sourceSpan : null,
reference: R3.stylingApply,
allocateBindingSlots: 0,
- buildParams: () => { return []; }
+ params: () => { return []; }
};
}
- private _buildSanitizerFn() {
+ private _buildSanitizerFn(): StylingInstruction {
return {
sourceSpan: this._firstStylingInput ? this._firstStylingInput.sourceSpan : null,
reference: R3.styleSanitizer,
allocateBindingSlots: 0,
- buildParams: () => [o.importExpr(R3.defaultStyleSanitizer)]
+ params: () => [o.importExpr(R3.defaultStyleSanitizer)]
};
}
@@ -470,7 +494,7 @@ export class StylingBuilder {
* into the update block of a template function or a directive hostBindings function.
*/
buildUpdateLevelInstructions(valueConverter: ValueConverter) {
- const instructions: Instruction[] = [];
+ const instructions: StylingInstruction[] = [];
if (this.hasBindings) {
if (compilerIsNewStylingInUse() && this._useDefaultSanitizer) {
instructions.push(this._buildSanitizerFn());
@@ -548,3 +572,61 @@ export function parseProperty(name: string):
return {property, unit, hasOverrideFlag};
}
+
+/**
+ * Gets the instruction to generate for an interpolated class map.
+ * @param interpolation An Interpolation AST
+ */
+function getClassMapInterpolationExpression(interpolation: Interpolation): o.ExternalReference {
+ switch (getInterpolationArgsLength(interpolation)) {
+ case 1:
+ return R3.classMap;
+ case 3:
+ return R3.classMapInterpolate1;
+ case 5:
+ return R3.classMapInterpolate2;
+ case 7:
+ return R3.classMapInterpolate3;
+ case 9:
+ return R3.classMapInterpolate4;
+ case 11:
+ return R3.classMapInterpolate5;
+ case 13:
+ return R3.classMapInterpolate6;
+ case 15:
+ return R3.classMapInterpolate7;
+ case 17:
+ return R3.classMapInterpolate8;
+ default:
+ return R3.classMapInterpolateV;
+ }
+}
+
+/**
+ * Gets the instruction to generate for an interpolated style prop.
+ * @param interpolation An Interpolation AST
+ */
+function getStylePropInterpolationExpression(interpolation: Interpolation) {
+ switch (getInterpolationArgsLength(interpolation)) {
+ case 1:
+ return R3.styleProp;
+ case 3:
+ return R3.stylePropInterpolate1;
+ case 5:
+ return R3.stylePropInterpolate2;
+ case 7:
+ return R3.stylePropInterpolate3;
+ case 9:
+ return R3.stylePropInterpolate4;
+ case 11:
+ return R3.stylePropInterpolate5;
+ case 13:
+ return R3.stylePropInterpolate6;
+ case 15:
+ return R3.stylePropInterpolate7;
+ case 17:
+ return R3.stylePropInterpolate8;
+ default:
+ return R3.stylePropInterpolateV;
+ }
+}
diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts
index f9c7bab668..e1c61c7451 100644
--- a/packages/compiler/src/render3/view/template.ts
+++ b/packages/compiler/src/render3/view/template.ts
@@ -36,8 +36,8 @@ import {I18nContext} from './i18n/context';
import {I18nMetaVisitor} from './i18n/meta';
import {getSerializedI18nContent} from './i18n/serializer';
import {I18N_ICU_MAPPING_PREFIX, TRANSLATION_PREFIX, assembleBoundTextPlaceholders, assembleI18nBoundString, formatI18nPlaceholderName, getTranslationConstPrefix, getTranslationDeclStmts, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, metaFromI18nMessage, placeholdersToParams, wrapI18nPlaceholder} from './i18n/util';
-import {Instruction, StylingBuilder} from './styling_builder';
-import {CONTEXT_NAME, IMPLICIT_REFERENCE, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, asLiteral, chainedInstruction, getAttrsForDirectiveMatching, invalid, trimTrailingNulls, unsupported} from './util';
+import {StylingBuilder, StylingInstruction} from './styling_builder';
+import {CONTEXT_NAME, IMPLICIT_REFERENCE, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, asLiteral, chainedInstruction, getAttrsForDirectiveMatching, getInterpolationArgsLength, invalid, trimTrailingNulls, unsupported} from './util';
@@ -1067,14 +1067,21 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver
}
private processStylingInstruction(
- elementIndex: number, instruction: Instruction|null, createMode: boolean) {
+ elementIndex: number, instruction: StylingInstruction|null, createMode: boolean) {
if (instruction) {
- const paramsFn = () => instruction.buildParams(value => this.convertPropertyBinding(value));
if (createMode) {
- this.creationInstruction(instruction.sourceSpan, instruction.reference, paramsFn);
+ this.creationInstruction(instruction.sourceSpan, instruction.reference, () => {
+ return instruction.params(value => this.convertPropertyBinding(value)) as o.Expression[];
+ });
} else {
- this.updateInstruction(
- elementIndex, instruction.sourceSpan, instruction.reference, paramsFn);
+ this.updateInstruction(elementIndex, instruction.sourceSpan, instruction.reference, () => {
+ return instruction
+ .params(value => {
+ return (instruction.supportsInterpolation && value instanceof Interpolation) ?
+ this.getUpdateInstructionArguments(value) :
+ this.convertPropertyBinding(value);
+ }) as o.Expression[];
+ });
}
}
}
@@ -1150,12 +1157,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver
}
private convertPropertyBinding(value: AST): o.Expression {
- const interpolationFn =
- value instanceof Interpolation ? interpolate : () => error('Unexpected interpolation');
-
const convertedPropertyBinding = convertPropertyBinding(
this, this.getImplicitReceiverExpr(), value, this.bindingContext(), BindingForm.TrySimple,
- interpolationFn);
+ () => error('Unexpected interpolation'));
const valExpr = convertedPropertyBinding.currValExpr;
this._tempVariables.push(...convertedPropertyBinding.stmts);
@@ -1751,31 +1755,6 @@ function getNgProjectAsLiteral(attribute: t.TextAttribute): o.Expression[] {
return [o.literal(core.AttributeMarker.ProjectAs), asLiteral(parsedR3Selector)];
}
-function interpolate(args: o.Expression[]): o.Expression {
- args = args.slice(1); // Ignore the length prefix added for render2
- switch (args.length) {
- case 3:
- return o.importExpr(R3.interpolation1).callFn(args);
- case 5:
- return o.importExpr(R3.interpolation2).callFn(args);
- case 7:
- return o.importExpr(R3.interpolation3).callFn(args);
- case 9:
- return o.importExpr(R3.interpolation4).callFn(args);
- case 11:
- return o.importExpr(R3.interpolation5).callFn(args);
- case 13:
- return o.importExpr(R3.interpolation6).callFn(args);
- case 15:
- return o.importExpr(R3.interpolation7).callFn(args);
- case 17:
- return o.importExpr(R3.interpolation8).callFn(args);
- }
- (args.length >= 19 && args.length % 2 == 1) ||
- error(`Invalid interpolation argument length ${args.length}`);
- return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]);
-}
-
/**
* Gets the instruction to generate for an interpolated property
* @param interpolation An Interpolation AST
@@ -1861,22 +1840,6 @@ function getTextInterpolationExpression(interpolation: Interpolation): o.Externa
}
}
-/**
- * Gets the number of arguments expected to be passed to a generated instruction in the case of
- * interpolation instructions.
- * @param interpolation An interpolation ast
- */
-function getInterpolationArgsLength(interpolation: Interpolation) {
- const {expressions, strings} = interpolation;
- if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
- // If the interpolation has one interpolated value, but the prefix and suffix are both empty
- // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
- // `textInterpolate`.
- return 1;
- } else {
- return expressions.length + strings.length;
- }
-}
/**
* Options that can be used to modify how a template is parsed by `parseTemplate()`.
*/
diff --git a/packages/compiler/src/render3/view/util.ts b/packages/compiler/src/render3/view/util.ts
index 29881deefd..068d09d487 100644
--- a/packages/compiler/src/render3/view/util.ts
+++ b/packages/compiler/src/render3/view/util.ts
@@ -7,6 +7,7 @@
*/
import {ConstantPool} from '../../constant_pool';
+import {Interpolation} from '../../expression_parser/ast';
import * as o from '../../output/output_ast';
import {ParseSourceSpan} from '../../parse_util';
import {splitAtColon} from '../../util';
@@ -201,3 +202,20 @@ export function chainedInstruction(
return expression;
}
+
+/**
+ * Gets the number of arguments expected to be passed to a generated instruction in the case of
+ * interpolation instructions.
+ * @param interpolation An interpolation ast
+ */
+export function getInterpolationArgsLength(interpolation: Interpolation) {
+ const {expressions, strings} = interpolation;
+ if (expressions.length === 1 && strings.length === 2 && strings[0] === '' && strings[1] === '') {
+ // If the interpolation has one interpolated value, but the prefix and suffix are both empty
+ // strings, we only pass one argument, to a special instruction like `propertyInterpolate` or
+ // `textInterpolate`.
+ return 1;
+ } else {
+ return expressions.length + strings.length;
+ }
+}
diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts
index a50a8de594..473d68fae2 100644
--- a/packages/core/src/core_render3_private_export.ts
+++ b/packages/core/src/core_render3_private_export.ts
@@ -130,7 +130,25 @@ export {
ɵɵstyling,
ɵɵstyleMap,
ɵɵclassMap,
+ ɵɵclassMapInterpolate1,
+ ɵɵclassMapInterpolate2,
+ ɵɵclassMapInterpolate3,
+ ɵɵclassMapInterpolate4,
+ ɵɵclassMapInterpolate5,
+ ɵɵclassMapInterpolate6,
+ ɵɵclassMapInterpolate7,
+ ɵɵclassMapInterpolate8,
+ ɵɵclassMapInterpolateV,
ɵɵstyleProp,
+ ɵɵstylePropInterpolate1,
+ ɵɵstylePropInterpolate2,
+ ɵɵstylePropInterpolate3,
+ ɵɵstylePropInterpolate4,
+ ɵɵstylePropInterpolate5,
+ ɵɵstylePropInterpolate6,
+ ɵɵstylePropInterpolate7,
+ ɵɵstylePropInterpolate8,
+ ɵɵstylePropInterpolateV,
ɵɵstylingApply,
ɵɵclassProp,
ɵɵelementHostAttrs,
diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts
index 761acb1956..bbdb46ee1c 100644
--- a/packages/core/src/render3/index.ts
+++ b/packages/core/src/render3/index.ts
@@ -36,6 +36,16 @@ export {
ɵɵattributeInterpolateV,
ɵɵclassMap,
+ ɵɵclassMapInterpolate1,
+ ɵɵclassMapInterpolate2,
+ ɵɵclassMapInterpolate3,
+ ɵɵclassMapInterpolate4,
+ ɵɵclassMapInterpolate5,
+ ɵɵclassMapInterpolate6,
+ ɵɵclassMapInterpolate7,
+ ɵɵclassMapInterpolate8,
+ ɵɵclassMapInterpolateV,
+
ɵɵclassProp,
ɵɵcomponentHostSyntheticListener,
@@ -97,7 +107,18 @@ export {
ɵɵselect,
ɵɵstyleMap,
+
ɵɵstyleProp,
+ ɵɵstylePropInterpolate1,
+ ɵɵstylePropInterpolate2,
+ ɵɵstylePropInterpolate3,
+ ɵɵstylePropInterpolate4,
+ ɵɵstylePropInterpolate5,
+ ɵɵstylePropInterpolate6,
+ ɵɵstylePropInterpolate7,
+ ɵɵstylePropInterpolate8,
+ ɵɵstylePropInterpolateV,
+
ɵɵstyleSanitizer,
ɵɵstyling,
ɵɵstylingApply,
diff --git a/packages/core/src/render3/instructions/all.ts b/packages/core/src/render3/instructions/all.ts
index ab291b1cb4..0eb52c5ee2 100644
--- a/packages/core/src/render3/instructions/all.ts
+++ b/packages/core/src/render3/instructions/all.ts
@@ -48,3 +48,5 @@ export * from './styling';
export {styleSanitizer as ɵɵstyleSanitizer} from '../styling_next/instructions';
export * from './text';
export * from './text_interpolation';
+export * from './class_map_interpolation';
+export * from './style_prop_interpolation';
diff --git a/packages/core/src/render3/instructions/class_map_interpolation.ts b/packages/core/src/render3/instructions/class_map_interpolation.ts
new file mode 100644
index 0000000000..7279919701
--- /dev/null
+++ b/packages/core/src/render3/instructions/class_map_interpolation.ts
@@ -0,0 +1,353 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {NO_CHANGE} from '../tokens';
+
+import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
+import {ɵɵclassMap} from './styling';
+
+/**
+ *
+ * Update an interpolated class on an element with single bound value surrounded by text.
+ *
+ * Used when the value passed to a property has 1 interpolated value in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate1('prefix', v0, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate1(prefix: string, v0: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 2 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 2 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate2('prefix', v0, '-', v1, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate2(
+ prefix: string, v0: any, i0: string, v1: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 3 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 3 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate3(
+ * 'prefix', v0, '-', v1, '-', v2, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate3(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 4 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 4 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate4(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate4(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 5 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 5 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate5(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate5(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 6 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 6 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate6(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate6(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, i4: string, v5: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 7 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 7 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate7(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param i5 Static value used for concatenation only.
+ * @param v6 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate7(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ *
+ * Update an interpolated class on an element with 8 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 8 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolate8(
+ * 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
+ * ```
+ *
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param i5 Static value used for concatenation only.
+ * @param v6 Value checked for change.
+ * @param i6 Static value used for concatenation only.
+ * @param v7 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolate8(
+ prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
+ i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
+ suffix: string): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
+
+/**
+ * Update an interpolated class on an element with 8 or more bound values surrounded by text.
+ *
+ * Used when the number of interpolated values exceeds 7.
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵclassMapInterpolateV(
+ * ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
+ * 'suffix']);
+ * ```
+ *.
+ * @param values The a collection of values and the strings in-between those values, beginning with
+ * a string prefix and ending with a string suffix.
+ * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
+ * @codeGenApi
+ */
+export function ɵɵclassMapInterpolateV(values: any[]): void {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolationV(values);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵclassMap(interpolatedValue);
+ }
+}
diff --git a/packages/core/src/render3/instructions/style_prop_interpolation.ts b/packages/core/src/render3/instructions/style_prop_interpolation.ts
new file mode 100644
index 0000000000..4f67b48136
--- /dev/null
+++ b/packages/core/src/render3/instructions/style_prop_interpolation.ts
@@ -0,0 +1,425 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+import {NO_CHANGE} from '../tokens';
+import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation';
+import {TsickleIssue1009} from './shared';
+import {ɵɵstyleProp} from './styling';
+
+
+/**
+ *
+ * Update an interpolated style property on an element with single bound value surrounded by text.
+ *
+ * Used when the value passed to a property has 1 interpolated value in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate1(0, 'prefix', v0, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate1(
+ styleIndex: number, prefix: string, v0: any, suffix: string, valueSuffix?: string | null,
+ forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate1;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 2 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 2 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate2(0, 'prefix', v0, '-', v1, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate2(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, suffix: string,
+ valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate2;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 3 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 3 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate3(0, 'prefix', v0, '-', v1, '-', v2, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate3(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate3;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 4 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 4 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate4(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate4(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ i2: string, v3: any, suffix: string, valueSuffix?: string | null,
+ forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate4;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 5 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 5 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate5(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate5(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ i2: string, v3: any, i3: string, v4: any, suffix: string, valueSuffix?: string | null,
+ forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate5;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 6 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 6 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate6(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate6(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string,
+ valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate6;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 7 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 7 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate7(
+ * 0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param i5 Static value used for concatenation only.
+ * @param v6 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate7(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any,
+ suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate7;
+}
+
+/**
+ *
+ * Update an interpolated style property on an element with 8 bound values surrounded by text.
+ *
+ * Used when the value passed to a property has 8 interpolated values in it:
+ *
+ * ```html
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolate8(0, 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6,
+ * '-', v7, 'suffix');
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`.
+ * @param prefix Static value used for concatenation only.
+ * @param v0 Value checked for change.
+ * @param i0 Static value used for concatenation only.
+ * @param v1 Value checked for change.
+ * @param i1 Static value used for concatenation only.
+ * @param v2 Value checked for change.
+ * @param i2 Static value used for concatenation only.
+ * @param v3 Value checked for change.
+ * @param i3 Static value used for concatenation only.
+ * @param v4 Value checked for change.
+ * @param i4 Static value used for concatenation only.
+ * @param v5 Value checked for change.
+ * @param i5 Static value used for concatenation only.
+ * @param v6 Value checked for change.
+ * @param i6 Static value used for concatenation only.
+ * @param v7 Value checked for change.
+ * @param suffix Static value used for concatenation only.
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolate8(
+ styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
+ i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string,
+ v7: any, suffix: string, valueSuffix?: string | null,
+ forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolatedValue =
+ ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix);
+ if (interpolatedValue !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolatedValue as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolate8;
+}
+
+/**
+ * Update an interpolated style property on an element with 8 or more bound values surrounded by
+ * text.
+ *
+ * Used when the number of interpolated values exceeds 7.
+ *
+ * ```html
+ *
+ *
+ * ```
+ *
+ * Its compiled representation is:
+ *
+ * ```ts
+ * ɵɵstylePropInterpolateV(
+ * 0, ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
+ * 'suffix']);
+ * ```
+ *
+ * @param styleIndex Index of style to update. This index value refers to the
+ * index of the style in the style bindings array that was passed into
+ * `styling`..
+ * @param values The a collection of values and the strings in-between those values, beginning with
+ * a string prefix and ending with a string suffix.
+ * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
+ * @param valueSuffix Optional suffix. Used with scalar values to add unit such as `px`.
+ * @param forceOverride Whether or not to update the styling value immediately.
+ * @returns itself, so that it may be chained.
+ * @codeGenApi
+ */
+export function ɵɵstylePropInterpolateV(
+ styleIndex: number, values: any[], valueSuffix?: string | null,
+ forceOverride?: boolean): TsickleIssue1009 {
+ // TODO(FW-1340): Refactor to remove the use of other instructions here.
+ const interpolated = ɵɵinterpolationV(values);
+ if (interpolated !== NO_CHANGE) {
+ ɵɵstyleProp(styleIndex, interpolated as string, valueSuffix, forceOverride);
+ }
+ return ɵɵstylePropInterpolateV;
+}
diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts
index 9fc8aec6b1..fb557dea0e 100644
--- a/packages/core/src/render3/instructions/styling.ts
+++ b/packages/core/src/render3/instructions/styling.ts
@@ -310,7 +310,7 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
*
* @codeGenApi
*/
-export function ɵɵclassMap(classes: {[styleName: string]: any} | NO_CHANGE | string | null): void {
+export function ɵɵclassMap(classes: {[styleName: string]: any} | string | null): void {
const index = getSelectedIndex();
const lView = getLView();
const stylingContext = getStylingContext(index, lView);
@@ -323,7 +323,7 @@ export function ɵɵclassMap(classes: {[styleName: string]: any} | NO_CHANGE | s
// inputs are only evaluated from a template binding into a directive, therefore,
// there should not be a situation where a directive host bindings function
// evaluates the inputs (this should only happen in the template function)
- if (hasClassInput(tNode) && classes !== NO_CHANGE) {
+ if (hasClassInput(tNode)) {
const initialClasses = getInitialClassNameValue(stylingContext);
const classInputVal =
(initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes);
diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts
index 8eb0b2350f..5b3ebb13b3 100644
--- a/packages/core/src/render3/jit/environment.ts
+++ b/packages/core/src/render3/jit/environment.ts
@@ -115,9 +115,27 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵreference': r3.ɵɵreference,
'ɵɵelementHostAttrs': r3.ɵɵelementHostAttrs,
'ɵɵclassMap': r3.ɵɵclassMap,
+ 'ɵɵclassMapInterpolate1': r3.ɵɵclassMapInterpolate1,
+ 'ɵɵclassMapInterpolate2': r3.ɵɵclassMapInterpolate2,
+ 'ɵɵclassMapInterpolate3': r3.ɵɵclassMapInterpolate3,
+ 'ɵɵclassMapInterpolate4': r3.ɵɵclassMapInterpolate4,
+ 'ɵɵclassMapInterpolate5': r3.ɵɵclassMapInterpolate5,
+ 'ɵɵclassMapInterpolate6': r3.ɵɵclassMapInterpolate6,
+ 'ɵɵclassMapInterpolate7': r3.ɵɵclassMapInterpolate7,
+ 'ɵɵclassMapInterpolate8': r3.ɵɵclassMapInterpolate8,
+ 'ɵɵclassMapInterpolateV': r3.ɵɵclassMapInterpolateV,
'ɵɵstyling': r3.ɵɵstyling,
'ɵɵstyleMap': r3.ɵɵstyleMap,
'ɵɵstyleProp': r3.ɵɵstyleProp,
+ 'ɵɵstylePropInterpolate1': r3.ɵɵstylePropInterpolate1,
+ 'ɵɵstylePropInterpolate2': r3.ɵɵstylePropInterpolate2,
+ 'ɵɵstylePropInterpolate3': r3.ɵɵstylePropInterpolate3,
+ 'ɵɵstylePropInterpolate4': r3.ɵɵstylePropInterpolate4,
+ 'ɵɵstylePropInterpolate5': r3.ɵɵstylePropInterpolate5,
+ 'ɵɵstylePropInterpolate6': r3.ɵɵstylePropInterpolate6,
+ 'ɵɵstylePropInterpolate7': r3.ɵɵstylePropInterpolate7,
+ 'ɵɵstylePropInterpolate8': r3.ɵɵstylePropInterpolate8,
+ 'ɵɵstylePropInterpolateV': r3.ɵɵstylePropInterpolateV,
'ɵɵstyleSanitizer': r3.ɵɵstyleSanitizer,
'ɵɵstylingApply': r3.ɵɵstylingApply,
'ɵɵclassProp': r3.ɵɵclassProp,
diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts
index 4b66286004..6fd6d69156 100644
--- a/packages/core/test/acceptance/styling_spec.ts
+++ b/packages/core/test/acceptance/styling_spec.ts
@@ -200,4 +200,177 @@ describe('styling', () => {
// that we use to run tests doesn't support `clip-path` in `CSSStyleDeclaration`.
expect(html).toMatch(/style=["|']clip-path:\s*url\(.*#test.*\)/);
});
+
+ it('should support interpolations inside a class binding', () => {
+ @Component({
+ template: `
+
+
+
+
+
+
+
+
+
+
+ `
+ })
+ class Cmp {
+ one = 'one';
+ two = 'two';
+ three = 'three';
+ four = 'four';
+ five = 'five';
+ six = 'six';
+ seven = 'seven';
+ eight = 'eight';
+ nine = 'nine';
+ }
+
+ TestBed.configureTestingModule({declarations: [Cmp]});
+ const fixture = TestBed.createComponent(Cmp);
+ const instance = fixture.componentInstance;
+ fixture.detectChanges();
+
+ const divs = fixture.nativeElement.querySelectorAll('div');
+
+ expect(divs[0].getAttribute('class')).toBe('aonebtwocthreedfourefivefsixgsevenheightininej');
+ expect(divs[1].getAttribute('class')).toBe('aonebtwocthreedfourefivefsixgsevenheighti');
+ expect(divs[2].getAttribute('class')).toBe('aonebtwocthreedfourefivefsixgsevenh');
+ expect(divs[3].getAttribute('class')).toBe('aonebtwocthreedfourefivefsixg');
+ expect(divs[4].getAttribute('class')).toBe('aonebtwocthreedfourefivef');
+ expect(divs[5].getAttribute('class')).toBe('aonebtwocthreedfoure');
+ expect(divs[6].getAttribute('class')).toBe('aonebtwocthreed');
+ expect(divs[7].getAttribute('class')).toBe('aonebtwoc');
+ expect(divs[8].getAttribute('class')).toBe('aoneb');
+ expect(divs[9].getAttribute('class')).toBe('one');
+
+ instance.one = instance.two = instance.three = instance.four = instance.five = instance.six =
+ instance.seven = instance.eight = instance.nine = '';
+ fixture.detectChanges();
+
+ expect(divs[0].getAttribute('class')).toBe('abcdefghij');
+ expect(divs[1].getAttribute('class')).toBe('abcdefghi');
+ expect(divs[2].getAttribute('class')).toBe('abcdefgh');
+ expect(divs[3].getAttribute('class')).toBe('abcdefg');
+ expect(divs[4].getAttribute('class')).toBe('abcdef');
+ expect(divs[5].getAttribute('class')).toBe('abcde');
+ expect(divs[6].getAttribute('class')).toBe('abcd');
+ expect(divs[7].getAttribute('class')).toBe('abc');
+ expect(divs[8].getAttribute('class')).toBe('ab');
+ expect(divs[9].getAttribute('class')).toBeFalsy();
+ });
+
+ it('should support interpolations inside a class binding when other classes are present', () => {
+ @Component({template: ''})
+ class Cmp {
+ one = 'one';
+ two = 'two';
+ }
+
+ TestBed.configureTestingModule({declarations: [Cmp]});
+ const fixture = TestBed.createComponent(Cmp);
+ fixture.detectChanges();
+ const classList = fixture.nativeElement.querySelector('div').classList;
+
+ expect(classList).toContain('zero');
+ expect(classList).toContain('i-one');
+ expect(classList).toContain('two');
+ expect(classList).toContain('three');
+
+ fixture.componentInstance.one = fixture.componentInstance.two = '';
+ fixture.detectChanges();
+
+ expect(classList).toContain('zero');
+ expect(classList).toContain('i-');
+ expect(classList).toContain('three');
+ expect(classList).not.toContain('i-one');
+ expect(classList).not.toContain('two');
+ });
+
+ it('should support interpolations inside a style property binding', () => {
+ @Component({
+ template: `
+
+
+
+
+
+
+
+
+
+
+ `
+ })
+ class Cmp {
+ singleBinding: string|null = '1337px';
+ one = 1;
+ two = 2;
+ three = 3;
+ four = 4;
+ five = 5;
+ six = 6;
+ seven = 7;
+ eight = 8;
+ nine = 9;
+ }
+
+ TestBed.configureTestingModule({declarations: [Cmp]});
+ const fixture = TestBed.createComponent(Cmp);
+ const instance = fixture.componentInstance;
+ fixture.detectChanges();
+
+ const divs: NodeListOf = fixture.nativeElement.querySelectorAll('div');
+
+ expect(divs[0].style.fontFamily).toBe('f123456789');
+ expect(divs[1].style.fontFamily).toBe('f12345678');
+ expect(divs[2].style.fontFamily).toBe('f1234567');
+ expect(divs[3].style.fontFamily).toBe('f123456');
+ expect(divs[4].style.fontFamily).toBe('f12345');
+ expect(divs[5].style.fontFamily).toBe('f1234');
+ expect(divs[6].style.fontFamily).toBe('f123');
+ expect(divs[7].style.fontFamily).toBe('f12');
+ expect(divs[8].style.fontFamily).toBe('f1');
+ expect(divs[9].style.width).toBe('1337px');
+
+ instance.singleBinding = null;
+ instance.one = instance.two = instance.three = instance.four = instance.five = instance.six =
+ instance.seven = instance.eight = instance.nine = 1;
+ fixture.detectChanges();
+
+ expect(divs[0].style.fontFamily).toBe('f111111111');
+ expect(divs[1].style.fontFamily).toBe('f11111111');
+ expect(divs[2].style.fontFamily).toBe('f1111111');
+ expect(divs[3].style.fontFamily).toBe('f111111');
+ expect(divs[4].style.fontFamily).toBe('f11111');
+ expect(divs[5].style.fontFamily).toBe('f1111');
+ expect(divs[6].style.fontFamily).toBe('f111');
+ expect(divs[7].style.fontFamily).toBe('f11');
+ expect(divs[8].style.fontFamily).toBe('f1');
+ expect(divs[9].style.width).toBeFalsy();
+ });
+
+ it('should support interpolations when a style property has a unit suffix', () => {
+ @Component({template: ''})
+ class Cmp {
+ one = 1;
+ three = 3;
+ }
+
+ TestBed.configureTestingModule({declarations: [Cmp]});
+ const fixture = TestBed.createComponent(Cmp);
+ fixture.detectChanges();
+ const div = fixture.nativeElement.querySelector('div');
+
+ expect(div.style.width).toBe('1337px');
+
+ fixture.componentInstance.one = 2;
+ fixture.componentInstance.three = 6;
+ fixture.detectChanges();
+
+ expect(div.style.width).toBe('2667px');
+ });
+
});
diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts
index f42053504b..ce8cd741cb 100644
--- a/tools/public_api_guard/core/core.d.ts
+++ b/tools/public_api_guard/core/core.d.ts
@@ -702,7 +702,25 @@ export interface ɵɵBaseDef {
export declare function ɵɵclassMap(classes: {
[styleName: string]: any;
-} | NO_CHANGE | string | null): void;
+} | string | null): void;
+
+export declare function ɵɵclassMapInterpolate1(prefix: string, v0: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate2(prefix: string, v0: any, i0: string, v1: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate3(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate4(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate5(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate6(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate7(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolate8(prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string): void;
+
+export declare function ɵɵclassMapInterpolateV(values: any[]): void;
export declare function ɵɵclassProp(classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void;
@@ -1043,6 +1061,24 @@ export declare function ɵɵstyleMap(styles: {
export declare function ɵɵstyleProp(styleIndex: number, value: string | number | String | PlayerFactory | null, suffix?: string | null, forceOverride?: boolean): void;
+export declare function ɵɵstylePropInterpolate1(styleIndex: number, prefix: string, v0: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate2(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate3(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate4(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate5(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate6(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate7(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolate8(styleIndex: number, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string, valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
+export declare function ɵɵstylePropInterpolateV(styleIndex: number, values: any[], valueSuffix?: string | null, forceOverride?: boolean): TsickleIssue1009;
+
export declare function ɵɵstyling(classBindingNames?: string[] | null, styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null): void;
export declare function ɵɵstylingApply(): void;