fix(ivy): ensure map-based interpolation works with other map-based sources (#33236)
Prior to this fix if a map-based class or style binding wrote its values onto an elemenent, the internal styling context would not register the binding if the initial value as a `NO_CHANGE` value. This situation occurs if a directive takes control of the `class` or `style` input values and then returns a `NO_CHANGE` value if the initial value is empty. This patch ensures that all bindings are always registered with the `TStylingContext` data-structure even if their initial value is an instance of `NO_CHANGE`. PR Close #33236
This commit is contained in:
parent
d5b59009d4
commit
7b64680670
|
@ -60,7 +60,12 @@ export function updateClassViaContext(
|
||||||
const isMapBased = !prop;
|
const isMapBased = !prop;
|
||||||
const state = getStylingState(element, directiveIndex);
|
const state = getStylingState(element, directiveIndex);
|
||||||
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.classesIndex++;
|
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.classesIndex++;
|
||||||
if (value !== NO_CHANGE) {
|
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
||||||
|
|
||||||
|
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngClass])
|
||||||
|
// then we still need to register the binding within the context so that the context
|
||||||
|
// is aware of the binding before it gets locked.
|
||||||
|
if (!isContextLocked(context, hostBindingsMode) || value !== NO_CHANGE) {
|
||||||
const updated = updateBindingData(
|
const updated = updateBindingData(
|
||||||
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate,
|
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate,
|
||||||
false);
|
false);
|
||||||
|
@ -95,7 +100,12 @@ export function updateStyleViaContext(
|
||||||
const isMapBased = !prop;
|
const isMapBased = !prop;
|
||||||
const state = getStylingState(element, directiveIndex);
|
const state = getStylingState(element, directiveIndex);
|
||||||
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;
|
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;
|
||||||
if (value !== NO_CHANGE) {
|
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
||||||
|
|
||||||
|
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngStyle])
|
||||||
|
// then we still need to register the binding within the context so that the context
|
||||||
|
// is aware of the binding before it gets locked.
|
||||||
|
if (!isContextLocked(context, hostBindingsMode) || value !== NO_CHANGE) {
|
||||||
const sanitizationRequired = isMapBased ?
|
const sanitizationRequired = isMapBased ?
|
||||||
true :
|
true :
|
||||||
(sanitizer ? sanitizer(prop !, null, StyleSanitizeMode.ValidateProperty) : false);
|
(sanitizer ? sanitizer(prop !, null, StyleSanitizeMode.ValidateProperty) : false);
|
||||||
|
|
|
@ -2292,6 +2292,23 @@ describe('styling', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
}).toThrowError(/ExpressionChangedAfterItHasBeenCheckedError/);
|
}).toThrowError(/ExpressionChangedAfterItHasBeenCheckedError/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should properly merge class interpolation with class-based directives', () => {
|
||||||
|
@Component(
|
||||||
|
{template: `<div class="zero {{one}}" [class.two]="true" [ngClass]="'three'"></div>`})
|
||||||
|
class MyComp {
|
||||||
|
one = 'one';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture =
|
||||||
|
TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('zero');
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('one');
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('two');
|
||||||
|
expect(fixture.debugElement.nativeElement.innerHTML).toContain('three');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertStyleCounters(countForSet: number, countForRemove: number) {
|
function assertStyleCounters(countForSet: number, countForRemove: number) {
|
||||||
|
|
Loading…
Reference in New Issue