fix(ivy): handling className as an input properly (#33188)
Prior to this commit, all `className` inputs were not set because the runtime code assumed that the `classMap` instruction is only generated for `[class]` bindings. However the `[className]` binding also produces the same `classMap`, thus the code needs to distinguish between `class` and `className`. This commit adds extra logic to select the right input name and also throws an error in case `[class]` and `[className]` bindings are used on the same element simultaneously. PR Close #33188
This commit is contained in:

committed by
Matias Niemelä

parent
08cb2fa80f
commit
6f203c9575
@ -19,7 +19,7 @@ import {assertNodeType} from '../node_assert';
|
||||
import {appendChild} from '../node_manipulation';
|
||||
import {decreaseElementDepthCount, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getSelectedIndex, increaseElementDepthCount, setIsNotParent, setPreviousOrParentTNode} from '../state';
|
||||
import {setUpAttributes} from '../util/attrs_utils';
|
||||
import {getInitialStylingValue, hasClassInput, hasStyleInput} from '../util/styling_utils';
|
||||
import {getInitialStylingValue, hasClassInput, hasStyleInput, selectClassBasedInputName} from '../util/styling_utils';
|
||||
import {getNativeByTNode, getTNode} from '../util/view_utils';
|
||||
|
||||
import {createDirectivesInstances, elementCreate, executeContentQueries, getOrCreateTNode, renderInitialStyling, resolveDirectives, saveResolvedLocalsInData, setInputsForProperty} from './shared';
|
||||
@ -132,7 +132,8 @@ export function ɵɵelementEnd(): void {
|
||||
}
|
||||
|
||||
if (hasClassInput(tNode)) {
|
||||
setDirectiveStylingInput(tNode.classes, lView, tNode.inputs !['class']);
|
||||
const inputName: string = selectClassBasedInputName(tNode.inputs !);
|
||||
setDirectiveStylingInput(tNode.classes, lView, tNode.inputs ![inputName]);
|
||||
}
|
||||
|
||||
if (hasStyleInput(tNode)) {
|
||||
|
@ -853,7 +853,7 @@ function initializeInputAndOutputAliases(tView: TView, tNode: TNode): void {
|
||||
}
|
||||
|
||||
if (inputsStore !== null) {
|
||||
if (inputsStore.hasOwnProperty('class')) {
|
||||
if (inputsStore.hasOwnProperty('class') || inputsStore.hasOwnProperty('className')) {
|
||||
tNode.flags |= TNodeFlags.hasClassInput;
|
||||
}
|
||||
if (inputsStore.hasOwnProperty('style')) {
|
||||
|
@ -19,7 +19,7 @@ import {activateStylingMapFeature} from '../styling/map_based_bindings';
|
||||
import {attachStylingDebugObject} from '../styling/styling_debug';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {renderStringify} from '../util/misc_utils';
|
||||
import {addItemToStylingMap, allocStylingMapArray, allocTStylingContext, allowDirectStyling, concatString, forceClassesAsString, forceStylesAsString, getInitialStylingValue, getStylingMapArray, hasClassInput, hasStyleInput, hasValueChanged, isContextLocked, isHostStylingActive, isStylingContext, normalizeIntoStylingMap, patchConfig, setValue, stylingMapToString} from '../util/styling_utils';
|
||||
import {addItemToStylingMap, allocStylingMapArray, allocTStylingContext, allowDirectStyling, concatString, forceClassesAsString, forceStylesAsString, getInitialStylingValue, getStylingMapArray, hasClassInput, hasStyleInput, hasValueChanged, isContextLocked, isHostStylingActive, isStylingContext, normalizeIntoStylingMap, patchConfig, selectClassBasedInputName, setValue, stylingMapToString} from '../util/styling_utils';
|
||||
import {getNativeByTNode, getTNode} from '../util/view_utils';
|
||||
|
||||
|
||||
@ -402,7 +402,7 @@ function updateDirectiveInputValue(
|
||||
// directive input(s) in the event that it is falsy during the
|
||||
// first update pass.
|
||||
if (newValue || isContextLocked(context, false)) {
|
||||
const inputName = isClassBased ? 'class' : 'style';
|
||||
const inputName: string = isClassBased ? selectClassBasedInputName(tNode.inputs !) : 'style';
|
||||
const inputs = tNode.inputs ![inputName] !;
|
||||
const initialValue = getInitialStylingValue(context);
|
||||
const value = normalizeStylingDirectiveInputValue(initialValue, newValue, isClassBased);
|
||||
|
@ -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 {TNode, TNodeFlags} from '../interfaces/node';
|
||||
import {PropertyAliases, TNode, TNodeFlags} from '../interfaces/node';
|
||||
import {LStylingData, StylingMapArray, StylingMapArrayIndex, TStylingConfig, TStylingContext, TStylingContextIndex, TStylingContextPropConfigFlags} from '../interfaces/styling';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
|
||||
@ -433,3 +433,9 @@ export function normalizeIntoStylingMap(
|
||||
|
||||
return stylingMapArr;
|
||||
}
|
||||
|
||||
// TODO (matsko|AndrewKushnir): refactor this once we figure out how to generate separate
|
||||
// `input('class') + classMap()` instructions.
|
||||
export function selectClassBasedInputName(inputs: PropertyAliases): string {
|
||||
return inputs.hasOwnProperty('class') ? 'class' : 'className';
|
||||
}
|
Reference in New Issue
Block a user