diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index d835d497dd87f..da43e03965cdb 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -5,7 +5,7 @@ * 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 {Directive, DoCheck, Input, ɵRenderFlags, ɵɵdefineDirective, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementHostStylingMap} from '@angular/core'; +import {Directive, DoCheck, Input, ɵRenderFlags, ɵɵdefineDirective, ɵɵelementHostClassMap, ɵɵelementHostStyling, ɵɵelementHostStylingApply} from '@angular/core'; import {NgClassImpl, NgClassImplProvider} from './ng_class_impl'; @@ -38,7 +38,7 @@ export const ngClassDirectiveDef__POST_R3__ = ɵɵdefineDirective({ ɵɵelementHostStyling(); } if (rf & ɵRenderFlags.Update) { - ɵɵelementHostStylingMap(ctx.getValue()); + ɵɵelementHostClassMap(ctx.getValue()); ɵɵelementHostStylingApply(); } } diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index 5565472d91897..a5e5c96b31a91 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -5,7 +5,7 @@ * 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 {Directive, DoCheck, Input, ɵRenderFlags, ɵɵdefineDirective, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementHostStylingMap} from '@angular/core'; +import {Directive, DoCheck, Input, ɵRenderFlags, ɵɵdefineDirective, ɵɵelementHostStyleMap, ɵɵelementHostStyling, ɵɵelementHostStylingApply} from '@angular/core'; import {NgStyleImpl, NgStyleImplProvider} from './ng_style_impl'; @@ -38,7 +38,7 @@ export const ngStyleDirectiveDef__POST_R3__ = ɵɵdefineDirective({ ɵɵelementHostStyling(); } if (rf & ɵRenderFlags.Update) { - ɵɵelementHostStylingMap(null, ctx.getValue()); + ɵɵelementHostStyleMap(ctx.getValue()); ɵɵelementHostStylingApply(); } } 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 34e8aed772efa..6a36aa5f78e43 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 @@ -389,7 +389,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, null, $ctx$.myStyleExp); + $r3$.ɵɵelementStyleMap(0, $ctx$.myStyleExp); $r3$.ɵɵelementStylingApply(0); } } @@ -454,7 +454,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $r3$.ɵɵinterpolation1("foo foo-", $ctx$.fooId, "")); + $r3$.ɵɵelementClassMap(0, $r3$.ɵɵinterpolation1("foo foo-", $ctx$.fooId, "")); $r3$.ɵɵelementStylingApply(0); } } @@ -468,7 +468,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $r3$.ɵɵinterpolation2("foo foo-", $ctx$.fooId, "-", $ctx$.fooUsername, "")); + $r3$.ɵɵelementClassMap(0, $r3$.ɵɵinterpolation2("foo foo-", $ctx$.fooId, "-", $ctx$.fooUsername, "")); $r3$.ɵɵelementStylingApply(0); } } @@ -482,7 +482,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $ctx$.exp); + $r3$.ɵɵelementClassMap(0, $ctx$.exp); $r3$.ɵɵelementStylingApply(0); } } @@ -538,7 +538,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, null, $ctx$.myStyleExp); + $r3$.ɵɵelementStyleMap(0, $ctx$.myStyleExp); $r3$.ɵɵelementStyleProp(0, 0, $ctx$.myWidth); $r3$.ɵɵelementStyleProp(0, 1, $ctx$.myHeight); $r3$.ɵɵelementStylingApply(0); @@ -704,7 +704,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0,$ctx$.myClassExp); + $r3$.ɵɵelementClassMap(0,$ctx$.myClassExp); $r3$.ɵɵelementStylingApply(0); } } @@ -760,7 +760,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $ctx$.myClassExp); + $r3$.ɵɵelementClassMap(0, $ctx$.myClassExp); $r3$.ɵɵelementClassProp(0, 0, $ctx$.yesToApple); $r3$.ɵɵelementClassProp(0, 1, $ctx$.yesToOrange); $r3$.ɵɵelementStylingApply(0); @@ -882,7 +882,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $ctx$.myClassExp, $ctx$.myStyleExp); + $r3$.ɵɵelementStyleMap(0, $ctx$.myStyleExp); + $r3$.ɵɵelementClassMap(0, $ctx$.myClassExp); $r3$.ɵɵelementStylingApply(0); } } @@ -919,12 +920,13 @@ describe('compiler compliance: styling', () => { if (rf & 1) { $r3$.ɵɵelementStart(0, "div"); $r3$.ɵɵelementStyling(null, null, $r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵpipe(1, "classPipe"); - $r3$.ɵɵpipe(2, "stylePipe"); + $r3$.ɵɵpipe(1, "stylePipe"); + $r3$.ɵɵpipe(2, "classPipe"); $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $r3$.ɵɵpipeBind1(1, 0, $ctx$.myClassExp), $r3$.ɵɵpipeBind1(2, 2, $ctx$.myStyleExp)); + $r3$.ɵɵelementStyleMap(0, $r3$.ɵɵpipeBind1(1, 0, $ctx$.myStyleExp)); + $r3$.ɵɵelementClassMap(0, $r3$.ɵɵpipeBind1(2, 2, $ctx$.myClassExp)); $r3$.ɵɵelementStylingApply(0); } } @@ -980,7 +982,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, $e2_styling$, $r3$.ɵɵpipeBind2(1, 1, $ctx$.myStyleExp, 1000)); + $r3$.ɵɵelementStyleMap(0, $r3$.ɵɵpipeBind2(1, 1, $ctx$.myStyleExp, 1000)); + $r3$.ɵɵelementClassMap(0, $e2_styling$); $r3$.ɵɵelementStyleProp(0, 0, $r3$.ɵɵpipeBind2(2, 4, $ctx$.barExp, 3000)); $r3$.ɵɵelementStyleProp(0, 1, $r3$.ɵɵpipeBind2(3, 7, $ctx$.bazExp, 4000)); $r3$.ɵɵelementClassProp(0, 0, $r3$.ɵɵpipeBind2(4, 10, $ctx$.fooExp, 2000)); @@ -1042,7 +1045,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementHostStyling($e0_classBindings$, $e0_styleBindings$, $r3$.ɵɵdefaultStyleSanitizer); } if (rf & 2) { - $r3$.ɵɵelementHostStylingMap(ctx.myClass, ctx.myStyle); + $r3$.ɵɵelementHostStyleMap(ctx.myStyle); + $r3$.ɵɵelementHostClassMap(ctx.myClass); $r3$.ɵɵelementHostStyleProp(0, ctx.myColorProp); $r3$.ɵɵelementHostClassProp(0, ctx.myFooClass); $r3$.ɵɵelementHostStylingApply(); @@ -1102,7 +1106,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementHostStyling(_c0, _c1, $r3$.ɵɵdefaultStyleSanitizer); } if (rf & 2) { - $r3$.ɵɵelementHostStylingMap(ctx.myClasses, ctx.myStyle); + $r3$.ɵɵelementHostStyleMap(ctx.myStyle); + $r3$.ɵɵelementHostClassMap(ctx.myClasses); $r3$.ɵɵelementHostStyleProp(0, ctx.myHeightProp, "pt"); $r3$.ɵɵelementHostStyleProp(1, ctx.myWidthProp); $r3$.ɵɵelementHostClassProp(0, ctx.myBarClass); @@ -1166,7 +1171,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵelementStylingMap(0, ctx.myClassExp, ctx.myStyleExp); + $r3$.ɵɵelementStyleMap(0, ctx.myStyleExp); + $r3$.ɵɵelementClassMap(0, ctx.myClassExp); $r3$.ɵɵelementStyleProp(0, 0, ctx.myHeightExp, null, true); $r3$.ɵɵelementClassProp(0, 0, ctx.myBarClassExp, true); $r3$.ɵɵelementStylingApply(0); @@ -1183,7 +1189,8 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementHostStyling(_c0, _c1, $r3$.ɵɵdefaultStyleSanitizer); } if (rf & 2) { - $r3$.ɵɵelementHostStylingMap(ctx.myClassExp, ctx.myStyleExp); + $r3$.ɵɵelementHostStyleMap(ctx.myStyleExp); + $r3$.ɵɵelementHostClassMap(ctx.myClassExp); $r3$.ɵɵelementHostStyleProp(0, ctx.myWidthExp, null, true); $r3$.ɵɵelementHostClassProp(0, ctx.myFooClassExp, true); $r3$.ɵɵelementHostStylingApply(); @@ -1251,7 +1258,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementHostStyling(); } if (rf & 2) { - $r3$.ɵɵelementHostStylingMap(ctx.myClassMap); + $r3$.ɵɵelementHostClassMap(ctx.myClassMap); $r3$.ɵɵelementHostStylingApply(); } } @@ -1335,7 +1342,8 @@ describe('compiler compliance: styling', () => { if (rf & 2) { $r3$.ɵɵproperty("id", ctx.id, null, true); $r3$.ɵɵproperty("title", ctx.title, null, true); - $r3$.ɵɵelementHostStylingMap(ctx.myClass, ctx.myStyle); + $r3$.ɵɵelementHostStyleMap(ctx.myStyle); + $r3$.ɵɵelementHostClassMap(ctx.myClass); $r3$.ɵɵelementHostStylingApply(); } } diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 9f4e612e147a3..5ef035aef0420 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -51,7 +51,9 @@ export class Identifiers { static elementStyling: o.ExternalReference = {name: 'ɵɵelementStyling', moduleName: CORE}; - static elementStylingMap: o.ExternalReference = {name: 'ɵɵelementStylingMap', moduleName: CORE}; + static elementStyleMap: o.ExternalReference = {name: 'ɵɵelementStyleMap', moduleName: CORE}; + + static elementClassMap: o.ExternalReference = {name: 'ɵɵelementClassMap', moduleName: CORE}; static elementStyleProp: o.ExternalReference = {name: 'ɵɵelementStyleProp', moduleName: CORE}; @@ -62,8 +64,11 @@ export class Identifiers { static elementHostStyling: o.ExternalReference = {name: 'ɵɵelementHostStyling', moduleName: CORE}; - static elementHostStylingMap: - o.ExternalReference = {name: 'ɵɵelementHostStylingMap', moduleName: CORE}; + static elementHostStyleMap: + o.ExternalReference = {name: 'ɵɵelementHostStyleMap', moduleName: CORE}; + + static elementHostClassMap: + o.ExternalReference = {name: 'ɵɵelementHostClassMap', moduleName: CORE}; static elementHostStyleProp: o.ExternalReference = {name: 'ɵɵelementHostStyleProp', moduleName: CORE}; diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts index 33c7d7ffbe034..a0815c19e122c 100644 --- a/packages/compiler/src/render3/view/styling_builder.ts +++ b/packages/compiler/src/render3/view/styling_builder.ts @@ -61,7 +61,8 @@ interface BoundStylingEntry { * elementStyling(...) * } * if (updateMode) { - * elementStylingMap(...) + * elementStyleMap(...) + * elementClassMap(...) * elementStyleProp(...) * elementClassProp(...) * elementStylingApp(...) @@ -339,71 +340,65 @@ export class StylingBuilder { } /** - * Builds an instruction with all the expressions and parameters for `elementStylingMap`. + * Builds an instruction with all the expressions and parameters for `elementClassMap`. * - * The instruction data will contain all expressions for `elementStylingMap` to function - * which include the `[style]` and `[class]` expression params (if they exist) as well as - * the sanitizer and directive reference expression. + * The instruction data will contain all expressions for `elementClassMap` to function + * which includes the `[class]` expression params. */ - buildElementStylingMapInstruction(valueConverter: ValueConverter): Instruction|null { - if (this._classMapInput || this._styleMapInput) { - const stylingInput = this._classMapInput ! || this._styleMapInput !; - let totalBindingSlotsRequired = 0; - - // 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 = - this._classMapInput ? this._classMapInput.value.visit(valueConverter) : null; - if (mapBasedClassValue instanceof Interpolation) { - totalBindingSlotsRequired += mapBasedClassValue.expressions.length; - } - - const mapBasedStyleValue = - this._styleMapInput ? this._styleMapInput.value.visit(valueConverter) : null; - if (mapBasedStyleValue instanceof Interpolation) { - totalBindingSlotsRequired += mapBasedStyleValue.expressions.length; - } + buildElementClassMapInstruction(valueConverter: ValueConverter): Instruction|null { + if (this._classMapInput) { + return this._buildMapBasedInstruction(valueConverter, true, this._classMapInput); + } + return null; + } - const isHostBinding = this._directiveExpr; - const reference = isHostBinding ? R3.elementHostStylingMap : R3.elementStylingMap; + /** + * Builds an instruction with all the expressions and parameters for `elementStyleMap`. + * + * The instruction data will contain all expressions for `elementStyleMap` to function + * which includes the `[style]` expression params. + */ + buildElementStyleMapInstruction(valueConverter: ValueConverter): Instruction|null { + if (this._styleMapInput) { + return this._buildMapBasedInstruction(valueConverter, false, this._styleMapInput); + } + return null; + } - return { - sourceSpan: stylingInput.sourceSpan, - reference, - allocateBindingSlots: totalBindingSlotsRequired, - buildParams: (convertFn: (value: any) => o.Expression) => { - // HOST: - // min params => elementHostStylingMap(classMap) - // max params => elementHostStylingMap(classMap, styleMap) - // Template: - // min params => elementStylingMap(elmIndex, classMap) - // max params => elementStylingMap(elmIndex, classMap, styleMap) + private _buildMapBasedInstruction( + valueConverter: ValueConverter, isClassBased: boolean, stylingInput: BoundStylingEntry) { + let totalBindingSlotsRequired = 0; - const params: o.Expression[] = []; - if (!isHostBinding) { - params.push(this._elementIndexExpr); - } + // these values must be outside of the update block so that they can + // 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) { + totalBindingSlotsRequired += mapValue.expressions.length; + } - let expectedNumberOfArgs = 0; - if (mapBasedStyleValue) { - expectedNumberOfArgs = 2; - } else if (mapBasedClassValue) { - // index and class = 2 - expectedNumberOfArgs = 1; - } + const isHostBinding = this._directiveExpr; + let reference: o.ExternalReference; + if (isClassBased) { + reference = isHostBinding ? R3.elementHostClassMap : R3.elementClassMap; + } else { + reference = isHostBinding ? R3.elementHostStyleMap : R3.elementStyleMap; + } - addParam( - params, mapBasedClassValue, mapBasedClassValue ? convertFn(mapBasedClassValue) : null, - 1, expectedNumberOfArgs); - addParam( - params, mapBasedStyleValue, mapBasedStyleValue ? convertFn(mapBasedStyleValue) : null, - 2, expectedNumberOfArgs); - return params; + return { + sourceSpan: stylingInput.sourceSpan, + reference, + allocateBindingSlots: totalBindingSlotsRequired, + buildParams: (convertFn: (value: any) => o.Expression) => { + const params: o.Expression[] = []; + if (!isHostBinding) { + params.push(this._elementIndexExpr); } - }; - } - return null; + + params.push(convertFn(mapValue)); + return params; + } + }; } private _buildSingleInputs( @@ -498,9 +493,13 @@ export class StylingBuilder { buildUpdateLevelInstructions(valueConverter: ValueConverter) { const instructions: Instruction[] = []; if (this.hasBindings) { - const mapInstruction = this.buildElementStylingMapInstruction(valueConverter); - if (mapInstruction) { - instructions.push(mapInstruction); + const styleMapInstruction = this.buildElementStyleMapInstruction(valueConverter); + if (styleMapInstruction) { + instructions.push(styleMapInstruction); + } + const classMapInstruction = this.buildElementClassMapInstruction(valueConverter); + if (classMapInstruction) { + instructions.push(classMapInstruction); } instructions.push(...this._buildStyleInputs(valueConverter)); instructions.push(...this._buildClassInputs(valueConverter)); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index fa751dac6ed1c..16fe7d13d7c6f 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -686,8 +686,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // the code here will collect all update-level styling instructions and add them to the // update block of the template function AOT code. Instructions like `elementStyleProp`, - // `elementStylingMap`, `elementClassProp` and `elementStylingApply` are all generated - // and assign in the code below. + // `elementStyleMap`, `elementClassMap`, `elementClassProp` and `elementStylingApply` + // are all generated and assigned in the code below. stylingBuilder.buildUpdateLevelInstructions(this._valueConverter).forEach(instruction => { this._bindingSlots += instruction.allocateBindingSlots; this.processStylingInstruction(implicit, instruction, false); diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 422e7dcc74eac..565a137cfd1d6 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -111,14 +111,16 @@ export { ɵɵelementContainerStart, ɵɵelementContainerEnd, ɵɵelementStyling, - ɵɵelementStylingMap, + ɵɵelementStyleMap, + ɵɵelementClassMap, ɵɵelementStyleProp, ɵɵelementStylingApply, ɵɵelementClassProp, ɵɵelementHostAttrs, + ɵɵelementHostClassMap, + ɵɵelementHostStyleMap, ɵɵelementHostStyling, - ɵɵelementHostStylingMap, ɵɵelementHostStyleProp, ɵɵelementHostClassProp, ɵɵelementHostStylingApply, diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 8b7ca59962f70..857723275ce33 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -34,6 +34,7 @@ export { ɵɵelement, ɵɵelementAttribute, + ɵɵelementClassMap, ɵɵelementClassProp, ɵɵelementContainerEnd, @@ -41,17 +42,18 @@ export { ɵɵelementEnd, ɵɵelementHostAttrs, + ɵɵelementHostClassMap, ɵɵelementHostClassProp, + ɵɵelementHostStyleMap, ɵɵelementHostStyleProp, ɵɵelementHostStyling, ɵɵelementHostStylingApply, - ɵɵelementHostStylingMap, ɵɵelementProperty, ɵɵelementStart, + ɵɵelementStyleMap, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, - ɵɵelementStylingMap, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index 5ca901decb257..0ec94635aaee4 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -11,7 +11,7 @@ import {TNode, TNodeType} from '../interfaces/node'; import {PlayerFactory} from '../interfaces/player'; import {FLAGS, HEADER_OFFSET, LView, LViewFlags, RENDERER, RootContextFlags} from '../interfaces/view'; import {getActiveDirectiveId, getActiveDirectiveSuperClassDepth, getLView, getPreviousOrParentTNode, getSelectedIndex} from '../state'; -import {getInitialClassNameValue, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from '../styling/class_and_style_bindings'; +import {getInitialClassNameValue, renderStyling, updateClassMap, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleMap, updateStyleProp as updateElementStyleProp} from '../styling/class_and_style_bindings'; import {ParamsOf, enqueueHostInstruction, registerHostDirective} from '../styling/host_instructions_queue'; import {BoundPlayerFactory} from '../styling/player_factory'; import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from '../styling/shared'; @@ -34,14 +34,16 @@ import {scheduleTick, setInputsForProperty} from './shared'; * * Template level styling instructions: * - elementStyling - * - elementStylingMap + * - elementStyleMap + * - elementClassMap * - elementStyleProp * - elementClassProp * - elementStylingApply * * Host bindings level styling instructions: * - elementHostStyling - * - elementHostStylingMap + * - elementHostStyleMap + * - elementHostClassMap * - elementHostStyleProp * - elementHostClassProp * - elementHostStylingApply @@ -147,7 +149,7 @@ function initElementStyling( * * If the style value is falsy then it will be removed from the element * (or assigned a different value depending if there are any styles placed - * on the element with `elementStylingMap` or any static styles that are + * on the element with `elementStyleMap` or any static styles that are * present from when the element was created with `elementStyling`). * * Note that the styling element is updated as part of `elementStylingApply`. @@ -182,7 +184,7 @@ export function ɵɵelementStyleProp( * * If the style value is falsy then it will be removed from the host element * (or assigned a different value depending if there are any styles placed - * on the same element with `elementHostStylingMap` or any static styles that + * on the same element with `elementHostStyleMap` or any static styles that * are present from when the element was patched with `elementHostStyling`). * * Note that the styling applied to the host element once @@ -305,28 +307,24 @@ function booleanOrNull(value: any): boolean|null { /** - * Update style and/or class bindings using object literals on an element. + * Update style bindings using an object literal on an element. * - * This instruction is meant to apply styling via the `[style]="exp"` and `[class]="exp"` template - * bindings. When styles/classes are applied to the element they will then be updated with - * respect to any styles/classes set with `elementStyleProp` or `elementClassProp`. If any - * styles or classes are set to falsy then they will be removed from the element. + * This instruction is meant to apply styling via the `[style]="exp"` template bindings. + * When styles are applied to the element they will then be updated with respect to + * any styles/classes set via `elementStyleProp`. If any styles are set to falsy + * then they will be removed from the element. * * Note that the styling instruction will not be applied until `elementStylingApply` is called. * * @param index Index of the element's with which styling is associated. - * @param classes A key/value map or string of CSS classes that will be added to the - * given element. Any missing classes (that have already been applied to the element - * beforehand) will be removed (unset) from the element's list of CSS classes. * @param styles A key/value style map of the styles that will be applied to the given element. * Any missing styles (that have already been applied to the element beforehand) will be * removed (unset) from the element's styling. * * @codeGenApi */ -export function ɵɵelementStylingMap( - index: number, classes: {[key: string]: any} | string | NO_CHANGE | null, - styles?: {[styleName: string]: any} | NO_CHANGE | null): void { +export function ɵɵelementStyleMap( + index: number, styles: {[styleName: string]: any} | NO_CHANGE | null): void { const lView = getLView(); const stylingContext = getStylingContext(index, lView); const tNode = getTNode(index, lView); @@ -334,14 +332,6 @@ export function ɵɵelementStylingMap( // 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) { - const initialClasses = getInitialClassNameValue(stylingContext); - const classInputVal = - (initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes); - setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal); - classes = NO_CHANGE; - } - if (hasStyleInput(tNode) && styles !== NO_CHANGE) { const initialStyles = getInitialClassNameValue(stylingContext); const styleInputVal = @@ -350,51 +340,107 @@ export function ɵɵelementStylingMap( styles = NO_CHANGE; } - updateStylingMap(stylingContext, classes, styles); + updateStyleMap(stylingContext, styles); } /** - * Update style and/or class host bindings using object literals on an element within the host - * bindings function for a directive/component. + * Update class bindings using an object literal or class-string on an element. * - * This instruction is meant to apply styling via the `@HostBinding('style')` and - * `@HostBinding('class')` bindings for a component's or directive's host element. - * When styles/classes are applied to the host element they will then be updated - * with respect to any styles/classes set with `elementHostStyleProp` or - * `elementHostClassProp`. If any styles or classes are set to falsy then they - * will be removed from the element. + * This instruction is meant to apply styling via the `[class]="exp"` template bindings. + * When classes are applied to the element they will then be updated with + * respect to any styles/classes set via `elementClassProp`. If any + * classes are set to falsy then they will be removed from the element. * - * Note that the styling instruction will not be applied until - * `elementHostStylingApply` is called. + * Note that the styling instruction will not be applied until `elementStylingApply` is called. * + * @param index Index of the element's with which styling is associated. * @param classes A key/value map or string of CSS classes that will be added to the * given element. Any missing classes (that have already been applied to the element * beforehand) will be removed (unset) from the element's list of CSS classes. + * + * @codeGenApi + */ +export function ɵɵelementClassMap( + index: number, classes: {[styleName: string]: any} | NO_CHANGE | string | null): void { + const lView = getLView(); + const stylingContext = getStylingContext(index, lView); + const tNode = getTNode(index, lView); + // 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) { + const initialClasses = getInitialClassNameValue(stylingContext); + const classInputVal = + (initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes); + setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal); + classes = NO_CHANGE; + } + updateClassMap(stylingContext, classes); +} + + +/** + * Update style host bindings using object literals on an element within the host + * bindings function for a directive/component. + * + * This instruction is meant to apply styling via the `@HostBinding('style')` + * host bindings for a component's or directive's host element. + * When styles are applied to the host element they will then be updated + * with respect to any other styles set with `elementHostStyleProp`. If + * If any styles are set to falsy then they will be removed from the element. + * + * Note that the styling instruction will not be applied until + * `elementHostStylingApply` is called. + * * @param styles A key/value style map of the styles that will be applied to the given element. * Any missing styles (that have already been applied to the element beforehand) will be * removed (unset) from the element's styling. * * @codeGenApi */ -export function ɵɵelementHostStylingMap( - classes: {[key: string]: any} | string | NO_CHANGE | null, - styles?: {[styleName: string]: any} | NO_CHANGE | null): void { +export function ɵɵelementHostStyleMap(styles: {[styleName: string]: any} | NO_CHANGE | null): void { const directiveStylingIndex = getActiveDirectiveStylingIndex(); const hostElementIndex = getSelectedIndex(); const stylingContext = getStylingContext(hostElementIndex, getLView()); - const args: ParamsOf = - [stylingContext, classes, styles, directiveStylingIndex]; - enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStylingMap, args); + const args: ParamsOf = [stylingContext, styles, directiveStylingIndex]; + enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStyleMap, args); } +/** + * Update class host bindings using object literals on an element within the host + * bindings function for a directive/component. + * + * This instruction is meant to apply styling via the `@HostBinding('class')` + * host bindings for a component's or directive's host element. + * When classes are applied to the host element they will then be updated + * with respect to any other classes set with `elementHostClassProp`. If + * any classes are set to falsy then they will be removed from the element. + * + * Note that the styling instruction will not be applied until + * `elementHostStylingApply` is called. + * + * @param classes A key/value map or string of CSS classes that will be added to the + * given element. Any missing classes (that have already been applied to the element + * beforehand) will be removed (unset) from the element's list of CSS classes. + * + * @codeGenApi + */ +export function ɵɵelementHostClassMap(classes: {[key: string]: any} | string | NO_CHANGE | null): + void { + const directiveStylingIndex = getActiveDirectiveStylingIndex(); + const hostElementIndex = getSelectedIndex(); + const stylingContext = getStylingContext(hostElementIndex, getLView()); + const args: ParamsOf = [stylingContext, classes, directiveStylingIndex]; + enqueueHostInstruction(stylingContext, directiveStylingIndex, updateClassMap, args); +} /** * Apply all style and class binding values to the element. * - * This instruction is meant to be run after `elementStylingMap`, `elementStyleProp` - * or `elementClassProp` instructions have been run and will only apply styling to - * the element if any styling bindings have been updated. + * This instruction is meant to be run after `elementStyleMap`, `elementClassMap`, + * `elementStyleProp` or `elementClassProp` instructions have been run and will + * only apply styling to the element if any styling bindings have been updated. * * @param index Index of the element's with which styling is associated. * @@ -407,10 +453,10 @@ export function ɵɵelementStylingApply(index: number): void { /** * Apply all style and class host binding values to the element. * - * This instruction is meant to be run after `elementHostStylingMap`, - * `elementHostStyleProp` or `elementHostClassProp` instructions have - * been run and will only apply styling to the host element if any - * styling bindings have been updated. + * This instruction is meant to be run after both `elementHostStyleMap` + * `elementHostClassMap`, `elementHostStyleProp` or `elementHostClassProp` + * instructions have been run and will only apply styling to the host + * element if any styling bindings have been updated. * * @codeGenApi */ diff --git a/packages/core/src/render3/interfaces/styling.ts b/packages/core/src/render3/interfaces/styling.ts index 02722704424b9..963cd4e772878 100644 --- a/packages/core/src/render3/interfaces/styling.ts +++ b/packages/core/src/render3/interfaces/styling.ts @@ -122,8 +122,8 @@ import {LView} from './view'; * values are and how they work. * * Each time a binding property is updated (whether it be through a single - * property instruction like `elementStyleProp`, `elementClassProp` or - * `elementStylingMap`) then the values in the context will be updated as + * property instruction like `elementStyleProp`, `elementClassProp`, + * `elementStyleMap` or `elementClassMap`) then the values in the context will be updated as * well. * * If for example `[style.width]` updates to `555px` then its value will be reflected @@ -161,7 +161,8 @@ import {LView} from './view'; * - `elementStyling` * - `elementStyleProp` * - `elementClassProp` - * - `elementStylingMap` + * - `elementStyleMap` + * - `elementClassMap` * - `elementStylingApply` * * Each time a directive value is passed in, it will be converted into an index by examining the @@ -298,13 +299,13 @@ export interface StylingContext extends [StylingIndex.SinglePropOffsetPositions]: SinglePropOffsetValues; /** - * The last class value that was interpreted by elementStylingMap. This is cached + * The last class value that was interpreted by `elementStyleMap`. This is cached * So that the algorithm can exit early incase the value has not changed. */ [StylingIndex.CachedMultiClasses]: any|MapBasedOffsetValues; /** - * The last style value that was interpreted by elementStylingMap. This is cached + * The last style value that was interpreted by `elementClassMap`. This is cached * So that the algorithm can exit early incase the value has not changed. */ [StylingIndex.CachedMultiStyles]: any|MapBasedOffsetValues; @@ -313,7 +314,7 @@ export interface StylingContext extends * A queue of all hostStyling instructions. * * This array (queue) is populated only when host-level styling instructions - * (e.g. `hostStylingMap` and `hostClassProp`) are used to apply style and + * (e.g. `hostStyleMap` and `hostClassProp`) are used to apply style and * class values via host bindings to the host element. Despite these being * standard angular instructions, they are not designed to immediately apply * their values to the styling context when executed. What happens instead is @@ -336,7 +337,7 @@ export interface StylingContext extends * the styling is applied). * * This queue is used when any `hostStyling` instructions are executed from the `hostBindings` - * function. Template-level styling functions (e.g. `elementStylingMap` and `elementClassProp`) + * function. Template-level styling functions (e.g. `elementStyleMap` and `elementClassProp`) * do not make use of this queue (they are applied to the styling context immediately). * * Due to the nature of how components/directives are evaluated, directives (both parent and @@ -781,7 +782,7 @@ export const enum DirectiveOwnerAndPlayerBuilderIndex { /** * The default directive styling index value for template-based bindings. * - * All host-level bindings (e.g. `hostStyleProp` and `hostStylingMap`) are + * All host-level bindings (e.g. `hostStyleProp` and `hostClassMap`) are * assigned a directive styling index value based on the current directive * uniqueId and the directive super-class inheritance depth. But for template * bindings they always have the same directive styling index value. diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 86454a051404a..6a9a0d8dd4773 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -106,13 +106,15 @@ export const angularCoreEnv: {[name: string]: Function} = { 'ɵɵloadContentQuery': r3.ɵɵloadContentQuery, 'ɵɵreference': r3.ɵɵreference, 'ɵɵelementHostAttrs': r3.ɵɵelementHostAttrs, + 'ɵɵelementClassMap': r3.ɵɵelementClassMap, 'ɵɵelementStyling': r3.ɵɵelementStyling, - 'ɵɵelementStylingMap': r3.ɵɵelementStylingMap, + 'ɵɵelementStyleMap': r3.ɵɵelementStyleMap, 'ɵɵelementStyleProp': r3.ɵɵelementStyleProp, 'ɵɵelementStylingApply': r3.ɵɵelementStylingApply, 'ɵɵelementClassProp': r3.ɵɵelementClassProp, + 'ɵɵelementHostClassMap': r3.ɵɵelementHostClassMap, 'ɵɵelementHostStyling': r3.ɵɵelementHostStyling, - 'ɵɵelementHostStylingMap': r3.ɵɵelementHostStylingMap, + 'ɵɵelementHostStyleMap': r3.ɵɵelementHostStyleMap, 'ɵɵelementHostStyleProp': r3.ɵɵelementHostStyleProp, 'ɵɵelementHostStylingApply': r3.ɵɵelementHostStylingApply, 'ɵɵelementHostClassProp': r3.ɵɵelementHostClassProp, diff --git a/packages/core/src/render3/styling/class_and_style_bindings.ts b/packages/core/src/render3/styling/class_and_style_bindings.ts index 0237d071c9e33..af1c585b5e50d 100644 --- a/packages/core/src/render3/styling/class_and_style_bindings.ts +++ b/packages/core/src/render3/styling/class_and_style_bindings.ts @@ -486,17 +486,16 @@ function getMatchingBindingIndex( } /** - * Registers the provided multi styling (`[style]` and `[class]`) values to the context. + * Registers the provided multi class values to the context. * - * This function will iterate over the provided `classesInput` and `stylesInput` map - * values and insert/update or remove them from the context at exactly the right - * spot. + * This function will iterate over the provided `classesInput` values and + * insert/update or remove them from the context at exactly the right spot. * * This function also takes in a directive which implies that the styling values will * be evaluated for that directive with respect to any other styling that already exists - * on the context. When there are styles that conflict (e.g. say `ngStyle` and `[style]` - * both update the `width` property at the same time) then the styling algorithm code below - * will decide which one wins based on the directive styling prioritization mechanism. This + * on the context. When there are styles that conflict (e.g. say `ngClass` and `[class]` + * both update the `foo` className value at the same time) then the styling algorithm code below + * will decide which one wins based on the directive styling prioritization mechanism. (This * mechanism is better explained in render3/interfaces/styling.ts#directives). * * This function will not render any styling values on screen, but is rather designed to @@ -509,100 +508,108 @@ function getMatchingBindingIndex( * @param classesInput The key/value map of CSS class names that will be used for the update. * @param stylesInput The key/value map of CSS styles that will be used for the update. */ -export function updateStylingMap( +export function updateClassMap( context: StylingContext, classesInput: {[key: string]: any} | string | BoundPlayerFactory| null, - stylesInput?: {[key: string]: any} | BoundPlayerFactory| null, directiveIndex: number = 0): void { - ngDevMode && ngDevMode.stylingMap++; + updateStylingMap(context, classesInput, true, directiveIndex); +} + +/** + * Registers the provided multi style values to the context. + * + * This function will iterate over the provided `stylesInput` values and + * insert/update or remove them from the context at exactly the right spot. + * + * This function also takes in a directive which implies that the styling values will + * be evaluated for that directive with respect to any other styling that already exists + * on the context. When there are styles that conflict (e.g. say `ngStyle` and `[style]` + * both update the `width` property at the same time) then the styling algorithm code below + * will decide which one wins based on the directive styling prioritization mechanism. (This + * mechanism is better explained in render3/interfaces/styling.ts#directives). + * + * This function will not render any styling values on screen, but is rather designed to + * prepare the context for that. `renderStyling` must be called afterwards to render any + * styling data that was set in this function (note that `updateClassProp` and + * `updateStyleProp` are designed to be run after this function is run). + * + * @param context The styling context that will be updated with the + * newly provided style values. + * @param stylesInput The key/value map of CSS styles that will be used for the update. + */ +export function updateStyleMap( + context: StylingContext, stylesInput: {[key: string]: any} | string | + BoundPlayerFactory| null, + directiveIndex: number = 0): void { + updateStylingMap(context, stylesInput, false, directiveIndex); +} + +function updateStylingMap( + context: StylingContext, input: {[key: string]: any} | string | + BoundPlayerFactory| null, + entryIsClassBased: boolean, directiveIndex: number = 0): void { + ngDevMode && (entryIsClassBased ? ngDevMode.classMap++ : ngDevMode.styleMap++); ngDevMode && assertValidDirectiveIndex(context, directiveIndex); - classesInput = classesInput || null; - stylesInput = stylesInput || null; - const ignoreAllClassUpdates = isMultiValueCacheHit(context, true, directiveIndex, classesInput); - const ignoreAllStyleUpdates = isMultiValueCacheHit(context, false, directiveIndex, stylesInput); // early exit (this is what's done to avoid using ctx.bind() to cache the value) - if (ignoreAllClassUpdates && ignoreAllStyleUpdates) return; + if (isMultiValueCacheHit(context, entryIsClassBased, directiveIndex, input)) return; - classesInput = - classesInput === NO_CHANGE ? readCachedMapValue(context, true, directiveIndex) : classesInput; - stylesInput = - stylesInput === NO_CHANGE ? readCachedMapValue(context, false, directiveIndex) : stylesInput; + input = + input === NO_CHANGE ? readCachedMapValue(context, entryIsClassBased, directiveIndex) : input; const element = context[StylingIndex.ElementPosition] !as HTMLElement; - const classesPlayerBuilder = classesInput instanceof BoundPlayerFactory ? - new ClassAndStylePlayerBuilder(classesInput as any, element, BindingType.Class) : - null; - const stylesPlayerBuilder = stylesInput instanceof BoundPlayerFactory ? - new ClassAndStylePlayerBuilder(stylesInput as any, element, BindingType.Style) : + const playerBuilder = input instanceof BoundPlayerFactory ? + new ClassAndStylePlayerBuilder( + input as any, element, entryIsClassBased ? BindingType.Class : BindingType.Style) : null; - const classesValue = classesPlayerBuilder ? - (classesInput as BoundPlayerFactory<{[key: string]: any}|string>) !.value : - classesInput; - const stylesValue = stylesPlayerBuilder ? stylesInput !['value'] : stylesInput; + const rawValue = + playerBuilder ? (input as BoundPlayerFactory<{[key: string]: any}|string>) !.value : input; - let classNames: string[] = EMPTY_ARRAY; - let applyAllClasses = false; + // the position is always the same, but whether the player builder gets set + // at all (depending if its set) will be reflected in the index value below... + const playerBuilderPosition = entryIsClassBased ? PlayerIndex.ClassMapPlayerBuilderPosition : + PlayerIndex.StyleMapPlayerBuilderPosition; + let playerBuilderIndex = playerBuilder ? playerBuilderPosition : 0; let playerBuildersAreDirty = false; - - const classesPlayerBuilderIndex = - classesPlayerBuilder ? PlayerIndex.ClassMapPlayerBuilderPosition : 0; - if (hasPlayerBuilderChanged( - context, classesPlayerBuilder, PlayerIndex.ClassMapPlayerBuilderPosition)) { - setPlayerBuilder(context, classesPlayerBuilder, PlayerIndex.ClassMapPlayerBuilderPosition); - playerBuildersAreDirty = true; - } - - const stylesPlayerBuilderIndex = - stylesPlayerBuilder ? PlayerIndex.StyleMapPlayerBuilderPosition : 0; - if (hasPlayerBuilderChanged( - context, stylesPlayerBuilder, PlayerIndex.StyleMapPlayerBuilderPosition)) { - setPlayerBuilder(context, stylesPlayerBuilder, PlayerIndex.StyleMapPlayerBuilderPosition); + if (hasPlayerBuilderChanged(context, playerBuilder, playerBuilderPosition)) { + setPlayerBuilder(context, playerBuilder, playerBuilderPosition); playerBuildersAreDirty = true; } // each time a string-based value pops up then it shouldn't require a deep // check of what's changed. - if (!ignoreAllClassUpdates) { - if (typeof classesValue == 'string') { - classNames = classesValue.split(/\s+/); + let startIndex: number; + let endIndex: number; + let propNames: string[]; + let applyAll = false; + if (entryIsClassBased) { + if (typeof rawValue == 'string') { + propNames = rawValue.split(/\s+/); // this boolean is used to avoid having to create a key/value map of `true` values - // since a classname string implies that all those classes are added - applyAllClasses = true; + // since a className string implies that all those classes are added + applyAll = true; } else { - classNames = classesValue ? Object.keys(classesValue) : EMPTY_ARRAY; - } - } - - const multiStylesStartIndex = getMultiStylesStartIndex(context); - let multiClassesStartIndex = getMultiClassesStartIndex(context); - let multiClassesEndIndex = context.length; - - if (!ignoreAllStyleUpdates) { - const styleProps = stylesValue ? Object.keys(stylesValue) : EMPTY_ARRAY; - const styles = stylesValue || EMPTY_OBJ; - const totalNewEntries = patchStylingMapIntoContext( - context, directiveIndex, stylesPlayerBuilderIndex, multiStylesStartIndex, - multiClassesStartIndex, styleProps, styles, stylesInput, false); - if (totalNewEntries) { - multiClassesStartIndex += totalNewEntries * StylingIndex.Size; - multiClassesEndIndex += totalNewEntries * StylingIndex.Size; + propNames = rawValue ? Object.keys(rawValue) : EMPTY_ARRAY; } + startIndex = getMultiClassesStartIndex(context); + endIndex = context.length; + } else { + startIndex = getMultiStylesStartIndex(context); + endIndex = getMultiClassesStartIndex(context); + propNames = rawValue ? Object.keys(rawValue) : EMPTY_ARRAY; } - if (!ignoreAllClassUpdates) { - const classes = (classesValue || EMPTY_OBJ) as{[key: string]: any}; - patchStylingMapIntoContext( - context, directiveIndex, classesPlayerBuilderIndex, multiClassesStartIndex, - multiClassesEndIndex, classNames, applyAllClasses || classes, classesInput, true); - } + const values = (rawValue || EMPTY_OBJ) as{[key: string]: any}; + patchStylingMapIntoContext( + context, directiveIndex, playerBuilderIndex, startIndex, endIndex, propNames, + applyAll || values, input, entryIsClassBased); if (playerBuildersAreDirty) { setContextPlayersDirty(context, true); } - ngDevMode && ngDevMode.stylingMapCacheMiss++; + ngDevMode && (entryIsClassBased ? ngDevMode.classMapCacheMiss++ : ngDevMode.styleMapCacheMiss++); } /** @@ -1918,4 +1925,4 @@ function assertValidDirectiveIndex(context: StylingContext, directiveIndex: numb dirs[index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] === -1) { throw new Error('The provided directive is not registered with the styling context'); } -} \ No newline at end of file +} diff --git a/packages/core/src/render3/styling/shared.ts b/packages/core/src/render3/styling/shared.ts index 1e57632841ac2..20782d18ebfda 100644 --- a/packages/core/src/render3/styling/shared.ts +++ b/packages/core/src/render3/styling/shared.ts @@ -9,7 +9,7 @@ /** * The default directive styling index value for template-based bindings. * - * All host-level bindings (e.g. `hostStyleProp` and `hostStylingMap`) are + * All host-level bindings (e.g. `hostStyleProp` and `hostStyleMap`) are * assigned a directive styling index value based on the current directive * uniqueId and the directive super-class inheritance depth. But for template * bindings they always have the same directive styling index value. diff --git a/packages/core/src/util/ng_dev_mode.ts b/packages/core/src/util/ng_dev_mode.ts index cde6949f0fb2f..6f34ba24ab729 100644 --- a/packages/core/src/util/ng_dev_mode.ts +++ b/packages/core/src/util/ng_dev_mode.ts @@ -31,8 +31,10 @@ declare global { rendererMoveNode: number; rendererRemoveNode: number; rendererCreateComment: number; - stylingMap: number; - stylingMapCacheMiss: number; + styleMap: number; + styleMapCacheMiss: number; + classMap: number; + classMapCacheMiss: number; stylingProp: number; stylingPropCacheMiss: number; stylingApply: number; @@ -62,8 +64,10 @@ export function ngDevModeResetPerfCounters(): NgDevModePerfCounters { rendererMoveNode: 0, rendererRemoveNode: 0, rendererCreateComment: 0, - stylingMap: 0, - stylingMapCacheMiss: 0, + styleMap: 0, + styleMapCacheMiss: 0, + classMap: 0, + classMapCacheMiss: 0, stylingProp: 0, stylingPropCacheMiss: 0, stylingApply: 0, diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index 7982557a703e3..c366fa0b78a45 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -10,7 +10,7 @@ import {NgForOfContext} from '@angular/common'; import {ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV} from '@angular/core/src/render3/instructions/all'; import {ɵɵdefineComponent} from '../../src/render3/definition'; -import {RenderFlags, ɵɵbind, ɵɵelement, ɵɵelementAttribute, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵelementStylingMap, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index'; +import {RenderFlags, ɵɵbind, ɵɵelement, ɵɵelementAttribute, ɵɵelementClassMap, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵelementStyleMap, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index'; import {AttributeMarker} from '../../src/render3/interfaces/node'; import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; @@ -1063,7 +1063,7 @@ describe('instructions', () => { it('should add style', () => { const fixture = new TemplateFixture(createDivWithStyle, () => {}, 1); fixture.update(() => { - ɵɵelementStylingMap(0, null, {'background-color': 'red'}); + ɵɵelementStyleMap(0, {'background-color': 'red'}); ɵɵelementStylingApply(0); }); expect(fixture.html).toEqual('
'); @@ -1078,7 +1078,7 @@ describe('instructions', () => { sanitizerInterceptor); fixture.update(() => { - ɵɵelementStylingMap(0, null, { + ɵɵelementStyleMap(0, { 'background-image': 'background-image', 'background': 'background', 'border-image': 'border-image', @@ -1107,7 +1107,7 @@ describe('instructions', () => { it('should add class', () => { const fixture = new TemplateFixture(createDivWithStyling, () => {}, 1); fixture.update(() => { - ɵɵelementStylingMap(0, 'multiple classes'); + ɵɵelementClassMap(0, 'multiple classes'); ɵɵelementStylingApply(0); }); expect(fixture.html).toEqual('
'); diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index 03a10e0c57ea4..7f52454a6a2c8 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -10,8 +10,8 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; import {RendererType2} from '../../src/render/api'; import {getLContext} from '../../src/render3/context_discovery'; -import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵtemplateRefExtractor} from '../../src/render3/index'; -import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdirectiveInject, ɵɵelement, ɵɵelementAttribute, ɵɵelementClassProp, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementHostAttrs, ɵɵelementHostClassProp, ɵɵelementHostStyleProp, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementHostStylingMap, ɵɵelementProperty, ɵɵelementStart, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵelementStylingMap, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV, ɵɵprojection, ɵɵprojectionDef, ɵɵreference, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all'; +import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵelementClassMap, ɵɵelementHostClassMap, ɵɵelementHostStyleMap, ɵɵelementStyleMap, ɵɵtemplateRefExtractor} from '../../src/render3/index'; +import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdirectiveInject, ɵɵelement, ɵɵelementAttribute, ɵɵelementClassProp, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementHostAttrs, ɵɵelementHostClassProp, ɵɵelementHostStyleProp, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementProperty, ɵɵelementStart, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV, ɵɵprojection, ɵɵprojectionDef, ɵɵreference, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all'; import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; @@ -1727,7 +1727,7 @@ describe('render3 integration test', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, 'cucumber grape'); + ɵɵelementClassMap(0, 'cucumber grape'); ɵɵelementStylingApply(0); } }, 1, 0, [DirWithClassDirective]); @@ -1748,7 +1748,7 @@ describe('render3 integration test', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, null, {width: '200px', height: '500px'}); + ɵɵelementStyleMap(0, {width: '200px', height: '500px'}); ɵɵelementStylingApply(0); } }, 1, 0, [DirWithStyleDirective]); @@ -1993,7 +1993,8 @@ describe('render3 integration test', () => { ɵɵelementHostStyling(); } if (rf & RenderFlags.Update) { - ɵɵelementHostStylingMap(ctx.classesExp, ctx.stylesExp); + ɵɵelementHostStyleMap(ctx.stylesExp); + ɵɵelementHostClassMap(ctx.classesExp); ɵɵelementHostStylingApply(); } } @@ -2020,7 +2021,7 @@ describe('render3 integration test', () => { ɵɵelementHostStyling(); } if (rf & RenderFlags.Update) { - ɵɵelementHostStylingMap(null, ctx.stylesExp); + ɵɵelementHostStyleMap(ctx.stylesExp); ɵɵelementHostStylingApply(); } } @@ -2039,7 +2040,8 @@ describe('render3 integration test', () => { ɵɵelementStyling(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, ctx.classesExp, ctx.stylesExp); + ɵɵelementStyleMap(0, ctx.stylesExp); + ɵɵelementClassMap(0, ctx.classesExp); ɵɵelementStylingApply(0); } }, 1, 0, [Dir1WithStyling, Dir2WithStyling]); @@ -2116,7 +2118,7 @@ describe('render3 integration test', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, ɵɵinterpolation2('-', ctx.name, '-', ctx.age, '-')); + ɵɵelementClassMap(0, ɵɵinterpolation2('-', ctx.name, '-', ctx.age, '-')); ɵɵelementStylingApply(0); } }, 1, 2); diff --git a/packages/core/test/render3/styling/class_and_style_bindings_spec.ts b/packages/core/test/render3/styling/class_and_style_bindings_spec.ts index 6613c9d8770b5..1f4b5687dcec6 100644 --- a/packages/core/test/render3/styling/class_and_style_bindings_spec.ts +++ b/packages/core/test/render3/styling/class_and_style_bindings_spec.ts @@ -9,7 +9,7 @@ import {createLView, createTView} from '@angular/core/src/render3/instructions/s import {createRootContext} from '../../../src/render3/component'; import {getLContext} from '../../../src/render3/context_discovery'; -import {ɵɵdefineComponent, ɵɵdefineDirective, ɵɵelementClassProp, ɵɵelementEnd, ɵɵelementHostClassProp, ɵɵelementHostStyleProp, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementStart, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵelementStylingMap, ɵɵnamespaceSVG} from '../../../src/render3/index'; +import {ɵɵdefineComponent, ɵɵdefineDirective, ɵɵelementClassMap, ɵɵelementClassProp, ɵɵelementEnd, ɵɵelementHostClassProp, ɵɵelementHostStyleProp, ɵɵelementHostStyling, ɵɵelementHostStylingApply, ɵɵelementStart, ɵɵelementStyleMap, ɵɵelementStyleProp, ɵɵelementStyling, ɵɵelementStylingApply, ɵɵnamespaceSVG} from '../../../src/render3/index'; import {RenderFlags} from '../../../src/render3/interfaces/definition'; import {AttributeMarker, TAttributes} from '../../../src/render3/interfaces/node'; import {BindingStore, BindingType, PlayState, Player, PlayerContext, PlayerFactory, PlayerHandler} from '../../../src/render3/interfaces/player'; @@ -17,7 +17,7 @@ import {RElement, Renderer3, domRendererFactory3} from '../../../src/render3/int import {StylingContext, StylingFlags, StylingIndex} from '../../../src/render3/interfaces/styling'; import {CONTEXT, LView, LViewFlags, RootContext} from '../../../src/render3/interfaces/view'; import {addPlayer, getPlayers} from '../../../src/render3/players'; -import {ClassAndStylePlayerBuilder, compareLogSummaries, directiveOwnerPointers, generateConfigSummary, getDirectiveIndexFromEntry, initializeStaticContext, isContextDirty, patchContextWithStaticAttrs, renderStyling as _renderStyling, setContextDirty, updateClassProp, updateContextWithBindings, updateStyleProp, updateStylingMap} from '../../../src/render3/styling/class_and_style_bindings'; +import {ClassAndStylePlayerBuilder, compareLogSummaries, directiveOwnerPointers, generateConfigSummary, getDirectiveIndexFromEntry, initializeStaticContext, isContextDirty, patchContextWithStaticAttrs, renderStyling as _renderStyling, setContextDirty, updateClassMap, updateClassProp, updateContextWithBindings, updateStyleMap, updateStyleProp} from '../../../src/render3/styling/class_and_style_bindings'; import {CorePlayerHandler} from '../../../src/render3/styling/core_player_handler'; import {registerHostDirective} from '../../../src/render3/styling/host_instructions_queue'; import {BoundPlayerFactory, bindPlayerFactory} from '../../../src/render3/styling/player_factory'; @@ -32,6 +32,13 @@ describe('style and class based bindings', () => { let element: RElement|null = null; beforeEach(() => { element = document.createElement('div') as any; }); + function updateStyleAndClassMaps( + context: StylingContext, classes: {} | string | null, styles?: {} | null, + directiveIndex?: number) { + updateStyleMap(context, styles || null, directiveIndex); + updateClassMap(context, classes, directiveIndex); + } + function createMockViewData(playerHandler: PlayerHandler, context: StylingContext): LView { const rootContext = createRootContext(requestAnimationFrame.bind(window), playerHandler || null); @@ -139,11 +146,11 @@ describe('style and class based bindings', () => { } function updateClasses(context: StylingContext, classes: string | {[key: string]: any} | null) { - updateStylingMap(context, classes, null); + updateStyleAndClassMaps(context, classes, null); } function updateStyles(context: StylingContext, styles: {[key: string]: any} | null) { - updateStylingMap(context, null, styles); + updateStyleAndClassMaps(context, null, styles); } function cleanStyle(a: number = 0, b: number = 0): number { return _clean(a, b, false, false); } @@ -389,7 +396,7 @@ describe('style and class based bindings', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, null, ctx.myStyles); + ɵɵelementStyleMap(0, ctx.myStyles); ɵɵelementStyleProp(0, 0, ctx.myWidth); ɵɵelementStylingApply(0); } @@ -1470,9 +1477,9 @@ describe('style and class based bindings', () => { const ctx = allocStylingContext(element, template); let s1, s2, s3; - updateStylingMap(ctx, null, s1 = {width: '100px', height: '99px'}, dir1); - updateStylingMap(ctx, null, s2 = {width: '200px', opacity: '0.5'}, dir2); - updateStylingMap(ctx, null, s3 = {width: '300px', height: '999px'}, dir3); + updateStyleAndClassMaps(ctx, null, s1 = {width: '100px', height: '99px'}, dir1); + updateStyleAndClassMaps(ctx, null, s2 = {width: '200px', opacity: '0.5'}, dir2); + updateStyleAndClassMaps(ctx, null, s3 = {width: '300px', height: '999px'}, dir3); expect(ctx[StylingIndex.CachedMultiStyles]).toEqual([ 3, @@ -1526,9 +1533,9 @@ describe('style and class based bindings', () => { 2, ]); - updateStylingMap(ctx, null, {opacity: '0', width: null}, dir1); - updateStylingMap(ctx, null, {width: '200px', opacity: '0.5'}, dir2); - updateStylingMap(ctx, null, {width: '300px', height: '999px'}, dir3); + updateStyleAndClassMaps(ctx, null, {opacity: '0', width: null}, dir1); + updateStyleAndClassMaps(ctx, null, {width: '200px', opacity: '0.5'}, dir2); + updateStyleAndClassMaps(ctx, null, {width: '300px', height: '999px'}, dir3); assertContextOnlyValues(ctx, [ // #10 @@ -1562,9 +1569,10 @@ describe('style and class based bindings', () => { 3, ]); - updateStylingMap(ctx, null, null, dir1); - updateStylingMap(ctx, null, {width: '500px', opacity: '0.2'}, dir2); - updateStylingMap(ctx, null, {width: '300px', height: '999px', color: 'red'}, dir3); + updateStyleAndClassMaps(ctx, null, null, dir1); + updateStyleAndClassMaps(ctx, null, {width: '500px', opacity: '0.2'}, dir2); + updateStyleAndClassMaps( + ctx, null, {width: '300px', height: '999px', color: 'red'}, dir3); assertContextOnlyValues(ctx, [ // #10 @@ -1619,9 +1627,9 @@ describe('style and class based bindings', () => { const ctx = allocStylingContext(element, template); let c1, c2, c3; - updateStylingMap(ctx, c1 = {red: true, orange: true}, null, dir1); - updateStylingMap(ctx, c2 = 'black red', null, dir2); - updateStylingMap(ctx, c3 = 'silver green', null, dir3); + updateStyleAndClassMaps(ctx, c1 = {red: true, orange: true}, null, dir1); + updateStyleAndClassMaps(ctx, c2 = 'black red', null, dir2); + updateStyleAndClassMaps(ctx, c3 = 'silver green', null, dir3); expect(ctx[StylingIndex.CachedMultiClasses]).toEqual([ 5, 0, 18, null, 0, 0, 18, c1, 2, 0, 26, c2, 1, 0, 30, c3, 2 @@ -1671,9 +1679,9 @@ describe('style and class based bindings', () => { 3, ]); - updateStylingMap(ctx, c1 = {orange: true}, null, dir1); - updateStylingMap(ctx, c2 = 'black red', null, dir2); - updateStylingMap(ctx, c3 = 'green', null, dir3); + updateStyleAndClassMaps(ctx, c1 = {orange: true}, null, dir1); + updateStyleAndClassMaps(ctx, c2 = 'black red', null, dir2); + updateStyleAndClassMaps(ctx, c3 = 'green', null, dir3); assertContextOnlyValues(ctx, [ // #10 @@ -1719,9 +1727,9 @@ describe('style and class based bindings', () => { 1, ]); - updateStylingMap(ctx, c1 = 'green', null, dir1); - updateStylingMap(ctx, c2 = null, null, dir2); - updateStylingMap(ctx, c3 = 'red', null, dir3); + updateStyleAndClassMaps(ctx, c1 = 'green', null, dir1); + updateStyleAndClassMaps(ctx, c2 = null, null, dir2); + updateStyleAndClassMaps(ctx, c3 = 'red', null, dir3); assertContextOnlyValues(ctx, [ // #10 @@ -1848,7 +1856,7 @@ describe('style and class based bindings', () => { const foreignDir = 2; expect(() => { - updateStylingMap(ctx, 'foo', null, foreignDir); + updateStyleAndClassMaps(ctx, 'foo', null, foreignDir); }).toThrowError('The provided directive is not registered with the styling context'); }); }); @@ -1862,7 +1870,7 @@ describe('style and class based bindings', () => { let styles: any = {'font-size': ''}; updateStyleProp(stylingContext, 0, ''); - updateStylingMap(stylingContext, null, styles); + updateStyleAndClassMaps(stylingContext, null, styles); getStyles(stylingContext); expect(store.getValues()).toEqual({'font-size': '', 'color': ''}); @@ -1871,7 +1879,7 @@ describe('style and class based bindings', () => { registerHostDirective(stylingContext, otherDirective); updateStyleProp(stylingContext, 0, 'red'); - updateStylingMap(stylingContext, null, styles = {'font-size': '20px'}); + updateStyleAndClassMaps(stylingContext, null, styles = {'font-size': '20px'}); getStyles(stylingContext); expect(store.getValues()).toEqual({'font-size': '', 'color': ''}); @@ -1880,7 +1888,7 @@ describe('style and class based bindings', () => { expect(store.getValues()).toEqual({'font-size': '20px', color: 'red'}); updateStyleProp(stylingContext, 0, ''); - updateStylingMap(stylingContext, null, styles = {}); + updateStyleAndClassMaps(stylingContext, null, styles = {}); getStyles(stylingContext, otherDirective); expect(store.getValues()).toEqual({'font-size': null, color: ''}); @@ -1958,10 +1966,10 @@ describe('style and class based bindings', () => { const stylingContext = createStylingContext(null, null, null, ['baz']); expect(getClasses(stylingContext)).toEqual({}); - updateStylingMap(stylingContext, 'foo bar baz'); + updateStyleAndClassMaps(stylingContext, 'foo bar baz'); expect(getClasses(stylingContext)).toEqual({'foo': true, 'bar': true, 'baz': true}); - updateStylingMap(stylingContext, 'foo car'); + updateStyleAndClassMaps(stylingContext, 'foo car'); updateClassProp(stylingContext, 0, true); expect(getClasses(stylingContext)) .toEqual({'foo': true, 'car': true, 'bar': false, 'baz': true}); @@ -2036,7 +2044,7 @@ describe('style and class based bindings', () => { expect(getStylesAndClasses(stylingContext)).toEqual([{}, {}]); let cachedStyleMap: any = {width: '200px', opacity: '0.5'}; - updateStylingMap(stylingContext, 'tall round', cachedStyleMap); + updateStyleAndClassMaps(stylingContext, 'tall round', cachedStyleMap); assertContext(stylingContext, [ element, masterConfig(26, true), // @@ -2117,7 +2125,7 @@ describe('style and class based bindings', () => { let cachedClassMap = {tall: true, wide: true}; cachedStyleMap = {width: '500px'}; - updateStylingMap(stylingContext, cachedClassMap, cachedStyleMap); + updateStyleAndClassMaps(stylingContext, cachedClassMap, cachedStyleMap); updateStyleProp(stylingContext, 0, '300px'); assertContext(stylingContext, [ @@ -2198,7 +2206,7 @@ describe('style and class based bindings', () => { {width: '300px', opacity: null}, ]); - updateStylingMap(stylingContext, {wide: false}); + updateStyleAndClassMaps(stylingContext, {wide: false}); expect(getStylesAndClasses(stylingContext)).toEqual([ {wide: false, tall: false, round: false}, {width: '100px', opacity: null} @@ -2212,7 +2220,7 @@ describe('style and class based bindings', () => { const stylesMap = {width: '200px'}; const classesMap = {foo: true}; - updateStylingMap(stylingContext, classesMap, stylesMap); + updateStyleAndClassMaps(stylingContext, classesMap, stylesMap); // apply the styles getStylesAndClasses(stylingContext); @@ -2239,7 +2247,7 @@ describe('style and class based bindings', () => { stylesMap.width = '300px'; classesMap.foo = false; - updateStylingMap(stylingContext, classesMap, stylesMap); + updateStyleAndClassMaps(stylingContext, classesMap, stylesMap); // apply the styles getStylesAndClasses(stylingContext); @@ -2269,7 +2277,7 @@ describe('style and class based bindings', () => { const getClasses = trackClassesFactory(); const classes = 'apple orange banana'; - updateStylingMap(stylingContext, classes); + updateStyleAndClassMaps(stylingContext, classes); // apply the styles expect(getClasses(stylingContext)).toEqual({apple: true, orange: true, banana: true}); @@ -2307,7 +2315,7 @@ describe('style and class based bindings', () => { stylingContext[14 + StylingIndex.ValueOffset] = false; stylingContext[18 + StylingIndex.ValueOffset] = false; - updateStylingMap(stylingContext, classes); + updateStyleAndClassMaps(stylingContext, classes); // apply the styles expect(getClasses(stylingContext)).toEqual({apple: true, orange: true, banana: true}); @@ -2320,7 +2328,7 @@ describe('style and class based bindings', () => { let classes: any = {red: false}; updateClassProp(stylingContext, 0, false); - updateStylingMap(stylingContext, classes); + updateStyleAndClassMaps(stylingContext, classes); // apply the styles getClasses(stylingContext, true); @@ -2328,14 +2336,14 @@ describe('style and class based bindings', () => { classes = {red: true}; updateClassProp(stylingContext, 0, true); - updateStylingMap(stylingContext, classes); + updateStyleAndClassMaps(stylingContext, classes); getClasses(stylingContext); expect(store.getValues()).toEqual({red: true, blue: true}); classes = {red: false}; updateClassProp(stylingContext, 0, false); - updateStylingMap(stylingContext, classes); + updateStyleAndClassMaps(stylingContext, classes); getClasses(stylingContext); expect(store.getValues()).toEqual({red: false, blue: false}); @@ -2367,7 +2375,7 @@ describe('style and class based bindings', () => { }, styles); - updateStylingMap(context, classFactory, styleFactory); + updateStyleAndClassMaps(context, classFactory, styleFactory); expect(classResult).toBeFalsy(); renderStyles(context); @@ -2392,15 +2400,15 @@ describe('style and class based bindings', () => { return new MockPlayer(); }; - updateStylingMap(context, null, bindPlayerFactory(buildFn, {width: '100px'})); + updateStyleAndClassMaps(context, null, bindPlayerFactory(buildFn, {width: '100px'})); renderStyles(context); expect(count).toEqual(1); - updateStylingMap(context, null, bindPlayerFactory(buildFn, {height: '100px'})); + updateStyleAndClassMaps(context, null, bindPlayerFactory(buildFn, {height: '100px'})); renderStyles(context); expect(count).toEqual(2); - updateStylingMap( + updateStyleAndClassMaps( context, null, bindPlayerFactory(buildFn, {height: '200px', width: '200px'})); renderStyles(context); expect(count).toEqual(3); @@ -2415,15 +2423,16 @@ describe('style and class based bindings', () => { return new MockPlayer(); }; - updateStylingMap(context, bindPlayerFactory(buildFn, {myClass: true})); + updateStyleAndClassMaps(context, bindPlayerFactory(buildFn, {myClass: true})); renderStyles(context); expect(count).toEqual(1); - updateStylingMap(context, bindPlayerFactory(buildFn, {otherClass: true})); + updateStyleAndClassMaps(context, bindPlayerFactory(buildFn, {otherClass: true})); renderStyles(context); expect(count).toEqual(2); - updateStylingMap(context, bindPlayerFactory(buildFn, {myClass: false, otherClass: false})); + updateStyleAndClassMaps( + context, bindPlayerFactory(buildFn, {myClass: false, otherClass: false})); renderStyles(context); expect(count).toEqual(3); }); @@ -2452,7 +2461,7 @@ describe('style and class based bindings', () => { const classPlayerBuilder = new ClassAndStylePlayerBuilder(classFactory, element as HTMLElement, BindingType.Class); - updateStylingMap(context, classFactory, styleFactory); + updateStyleAndClassMaps(context, classFactory, styleFactory); expect(context[StylingIndex.PlayerContext]).toEqual([ 5, classPlayerBuilder, null, stylePlayerBuilder, null ]); @@ -2518,7 +2527,7 @@ describe('style and class based bindings', () => { const classMapPlayerBuilder = new ClassAndStylePlayerBuilder( classMapFactory, element as HTMLElement, BindingType.Class); - updateStylingMap(context, classMapFactory, styleMapFactory); + updateStyleAndClassMaps(context, classMapFactory, styleMapFactory); const widthFactory = bindPlayerFactory(styleBuildFn, '100px'); const barFactory = bindPlayerFactory(classBuildFn, true); @@ -2604,7 +2613,7 @@ describe('style and class based bindings', () => { expect(context[StylingIndex.PlayerContext]).toEqual(null); let mapFactory = bindPlayerFactory(buildFn, {width: '200px'}); - updateStylingMap(context, null, mapFactory); + updateStyleAndClassMaps(context, null, mapFactory); renderStyles(context, false, undefined, lView); expect(players.length).toEqual(1); @@ -2612,7 +2621,7 @@ describe('style and class based bindings', () => { expect(p1.state).toEqual(PlayState.Pending); mapFactory = bindPlayerFactory(buildFn, {width: '100px'}); - updateStylingMap(context, null, mapFactory); + updateStyleAndClassMaps(context, null, mapFactory); renderStyles(context, false, undefined, lView); expect(players.length).toEqual(1); @@ -2684,7 +2693,7 @@ describe('style and class based bindings', () => { const classMapWithPlayerFactory = bindPlayerFactory(buildClassFn, cachedClassMap); const styleMapPlayerBuilder = makePlayerBuilder(styleMapWithPlayerFactory, false); const classMapPlayerBuilder = makePlayerBuilder(classMapWithPlayerFactory, true); - updateStylingMap(context, classMapWithPlayerFactory, styleMapWithPlayerFactory); + updateStyleAndClassMaps(context, classMapWithPlayerFactory, styleMapWithPlayerFactory); const colorWithPlayerFactory = bindPlayerFactory(buildStyleFn, 'red'); const fooWithPlayerFactory = bindPlayerFactory(buildClassFn, true); @@ -2754,7 +2763,7 @@ describe('style and class based bindings', () => { 0, ]); - updateStylingMap(context, cachedClassMap, cachedStyleMap); + updateStyleAndClassMaps(context, cachedClassMap, cachedStyleMap); const colorWithoutPlayerFactory = 'blue'; const fooWithoutPlayerFactory = false; @@ -2836,7 +2845,7 @@ describe('style and class based bindings', () => { let styleFactory = bindPlayerFactory(buildStyleFn, {opacity: '1'}) as BoundPlayerFactory; let classFactory = bindPlayerFactory(buildClassFn, 'bar') as BoundPlayerFactory; - updateStylingMap(context, classFactory, styleFactory); + updateStyleAndClassMaps(context, classFactory, styleFactory); expect(styleCalls).toEqual(0); expect(classCalls).toEqual(0); @@ -2849,18 +2858,18 @@ describe('style and class based bindings', () => { expect(classCalls).toEqual(1); styleFactory = bindPlayerFactory(buildStyleFn, {opacity: '0.5'}) as BoundPlayerFactory; - updateStylingMap(context, classFactory, styleFactory); + updateStyleAndClassMaps(context, classFactory, styleFactory); renderStyles(context, false, undefined, lView); expect(styleCalls).toEqual(2); expect(classCalls).toEqual(1); classFactory = bindPlayerFactory(buildClassFn, 'foo') as BoundPlayerFactory; - updateStylingMap(context, classFactory, styleFactory); + updateStyleAndClassMaps(context, classFactory, styleFactory); renderStyles(context, false, undefined, lView); expect(styleCalls).toEqual(2); expect(classCalls).toEqual(2); - updateStylingMap(context, 'foo', {opacity: '0.5'}); + updateStyleAndClassMaps(context, 'foo', {opacity: '0.5'}); renderStyles(context, false, undefined, lView); expect(styleCalls).toEqual(2); expect(classCalls).toEqual(2); @@ -2883,7 +2892,7 @@ describe('style and class based bindings', () => { }; const mapFactory = bindPlayerFactory(mapBuildFn, {color: 'black'}); - updateStylingMap(context, null, mapFactory); + updateStyleAndClassMaps(context, null, mapFactory); updateStyleProp(context, 0, 'green'); renderStyles(context, false, undefined, lView); @@ -2907,7 +2916,7 @@ describe('style and class based bindings', () => { propPlayer = styleMapPlayer = null; - updateStylingMap(context, null, null); + updateStyleAndClassMaps(context, null, null); renderStyles(context, false, undefined, lView); expect(propPlayer).toBeFalsy(); @@ -2929,7 +2938,7 @@ describe('style and class based bindings', () => { }; let factory = bindPlayerFactory<{[key: string]: any}>(buildFn, {width: '200px'}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(previousPlayer).toEqual(null); @@ -2937,7 +2946,7 @@ describe('style and class based bindings', () => { factory = bindPlayerFactory(buildFn, {height: '200px'}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(previousPlayer !.value).toEqual({width: '200px'}); @@ -2959,7 +2968,7 @@ describe('style and class based bindings', () => { }; let factory = bindPlayerFactory(buildFn, {foo: true}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(currentPlayer).toBeTruthy(); @@ -2969,7 +2978,7 @@ describe('style and class based bindings', () => { previousPlayer = currentPlayer = null; factory = bindPlayerFactory(buildFn, {bar: true}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(currentPlayer).toBeTruthy(); @@ -3000,13 +3009,13 @@ describe('style and class based bindings', () => { let factory = bindPlayerFactory<{[key: string]: any}>( buildFn, {width: '200px', height: '100px', opacity: '1'}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(values !).toEqual({width: '200px-safe!', height: '100px-safe!', opacity: '1'}); factory = bindPlayerFactory(buildFn, {width: 'auto'}); - updateStylingMap(context, null, factory); + updateStyleAndClassMaps(context, null, factory); renderStyles(context, false, undefined, lView); expect(values !).toEqual({width: 'auto-safe!', height: null, opacity: null}); @@ -3035,20 +3044,21 @@ describe('style and class based bindings', () => { const styleMapFactory = bindPlayerFactory(styleBuildFn, {opacity: '1'}); const classMapFactory = bindPlayerFactory(classBuildFn, {map: true}); - updateStylingMap(context, classMapFactory, styleMapFactory); + updateStyleAndClassMaps(context, classMapFactory, styleMapFactory); updateStyleProp(context, 0, bindPlayerFactory(styleBuildFn, '100px') as any); updateClassProp(context, 0, bindPlayerFactory(classBuildFn, true) as any); updateClassProp(context, 1, bindPlayerFactory(classBuildFn, true) as any); renderStyles(context, false, undefined, lView); handler.flushPlayers(); + expect(players.length).toEqual(5); const [p1, p2, p3, p4, p5] = players; expect(p1.state).toEqual(PlayState.Running); expect(p2.state).toEqual(PlayState.Running); expect(p3.state).toEqual(PlayState.Running); expect(p4.state).toEqual(PlayState.Running); - updateStylingMap(context, {bar: true}, {height: '200px'}); + updateStyleAndClassMaps(context, {bar: true}, {height: '200px'}); updateStyleProp(context, 0, '200px'); updateClassProp(context, 0, false); expect(p1.state).toEqual(PlayState.Running); @@ -3100,7 +3110,8 @@ describe('style and class based bindings', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, classMapFactory, styleMapFactory); + ɵɵelementStyleMap(0, styleMapFactory); + ɵɵelementClassMap(0, classMapFactory); ɵɵelementStyleProp(0, 0, widthFactory); ɵɵelementClassProp(0, 0, fooFactory); ɵɵelementStylingApply(0); @@ -3173,7 +3184,8 @@ describe('style and class based bindings', () => { ɵɵelementEnd(); } if (rf & RenderFlags.Update) { - ɵɵelementStylingMap(0, classMapFactory, styleMapFactory); + ɵɵelementStyleMap(0, styleMapFactory); + ɵɵelementClassMap(0, classMapFactory); ɵɵelementStyleProp(0, 0, widthFactory); ɵɵelementClassProp(0, 0, fooFactory); ɵɵelementStylingApply(0); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 31e4dedadfa9e..12109c6af9d21 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -795,6 +795,10 @@ export declare function ɵɵelement(index: number, name: string, attrs?: TAttrib export declare function ɵɵelementAttribute(index: number, name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string): void; +export declare function ɵɵelementClassMap(index: number, classes: { + [styleName: string]: any; +} | NO_CHANGE | string | null): void; + export declare function ɵɵelementClassProp(index: number, classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void; export declare function ɵɵelementContainerEnd(): void; @@ -805,36 +809,36 @@ export declare function ɵɵelementEnd(): void; export declare function ɵɵelementHostAttrs(attrs: TAttributes): void; +export declare function ɵɵelementHostClassMap(classes: { + [key: string]: any; +} | string | NO_CHANGE | null): void; + export declare function ɵɵelementHostClassProp(classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void; +export declare function ɵɵelementHostStyleMap(styles: { + [styleName: string]: any; +} | NO_CHANGE | null): void; + export declare function ɵɵelementHostStyleProp(styleIndex: number, value: string | number | String | PlayerFactory | null, suffix?: string | null, forceOverride?: boolean): void; export declare function ɵɵelementHostStyling(classBindingNames?: string[] | null, styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null): void; export declare function ɵɵelementHostStylingApply(): void; -export declare function ɵɵelementHostStylingMap(classes: { - [key: string]: any; -} | string | NO_CHANGE | null, styles?: { - [styleName: string]: any; -} | NO_CHANGE | null): void; - export declare function ɵɵelementProperty(index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): void; export declare function ɵɵelementStart(index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void; +export declare function ɵɵelementStyleMap(index: number, styles: { + [styleName: string]: any; +} | NO_CHANGE | null): void; + export declare function ɵɵelementStyleProp(index: number, styleIndex: number, value: string | number | String | PlayerFactory | null, suffix?: string | null, forceOverride?: boolean): void; export declare function ɵɵelementStyling(classBindingNames?: string[] | null, styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null): void; export declare function ɵɵelementStylingApply(index: number): void; -export declare function ɵɵelementStylingMap(index: number, classes: { - [key: string]: any; -} | string | NO_CHANGE | null, styles?: { - [styleName: string]: any; -} | NO_CHANGE | null): void; - export declare function ɵɵembeddedViewEnd(): void; export declare function ɵɵembeddedViewStart(viewBlockId: number, consts: number, vars: number): RenderFlags;