Skip to content

Commit 92a87d2

Browse files
committed
fix(core): ensure host bindings in inherited directives use correct LView slots
Previously, when a directive extended another directive and both had host bindings using instructions with relative offsets (like `pureFunction`), they would share the same `bindingRoot` in the `LView`.
1 parent 86bbc94 commit 92a87d2

2 files changed

Lines changed: 46 additions & 2 deletions

File tree

packages/core/src/render3/features/inherit_definition_feature.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import {TAttributes} from '../interfaces/node';
2323
import {isComponentDef} from '../interfaces/type_checks';
2424
import {mergeHostAttrs} from '../util/attrs_utils';
25+
import {getBindingRoot, getCurrentDirectiveIndex, setBindingRootForHostBindings} from '../state';
2526
import {stringifyForError} from '../util/stringify_utils';
2627

2728
export function getSuperType(
@@ -76,7 +77,7 @@ export function ɵɵInheritDefinitionFeature(
7677

7778
// Merge hostBindings
7879
const superHostBindings = superDef.hostBindings;
79-
superHostBindings && inheritHostBindings(definition, superHostBindings);
80+
superHostBindings && inheritHostBindings(definition, superHostBindings, superDef.hostVars);
8081

8182
// Merge queries
8283
const superViewQuery = superDef.viewQuery;
@@ -208,12 +209,19 @@ function inheritContentQueries(
208209
function inheritHostBindings(
209210
definition: WritableDef,
210211
superHostBindings: HostBindingsFunction<any>,
212+
superHostVars: number,
211213
) {
212214
const prevHostBindings = definition.hostBindings;
213215
if (prevHostBindings) {
214216
definition.hostBindings = (rf: RenderFlags, ctx: any) => {
215217
superHostBindings(rf, ctx);
216-
prevHostBindings(rf, ctx);
218+
const oldBindRoot = getBindingRoot();
219+
setBindingRootForHostBindings(oldBindRoot + superHostVars, getCurrentDirectiveIndex());
220+
try {
221+
prevHostBindings(rf, ctx);
222+
} finally {
223+
setBindingRootForHostBindings(oldBindRoot, getCurrentDirectiveIndex());
224+
}
217225
};
218226
} else {
219227
definition.hostBindings = superHostBindings;

packages/core/test/acceptance/inherit_definition_feature_spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5964,4 +5964,40 @@ describe('inheritance', () => {
59645964
// TODO: sub has ViewChildren and super has ContentChildren on same property
59655965
// TODO: sub has ContentChild and super has ContentChildren on same property
59665966
});
5967+
5968+
it('should not overwrite LView slots when extending a directive with host bindings (issue #66263)', () => {
5969+
@Directive({
5970+
host: {
5971+
'[attr.parent]': '["P"][0]',
5972+
},
5973+
standalone: true,
5974+
})
5975+
class ParentDir {}
5976+
5977+
@Directive({
5978+
selector: 'some-dir',
5979+
host: {
5980+
'[attr.child]': '["C"][0]',
5981+
},
5982+
standalone: true,
5983+
})
5984+
class SomeDir extends ParentDir {}
5985+
5986+
@Component({
5987+
selector: 'app-root',
5988+
standalone: true,
5989+
imports: [SomeDir],
5990+
template: `
5991+
<some-dir></some-dir>
5992+
`,
5993+
})
5994+
class App {}
5995+
5996+
const fixture = TestBed.createComponent(App);
5997+
fixture.detectChanges();
5998+
5999+
const element = fixture.nativeElement.querySelector('some-dir');
6000+
expect(element.getAttribute('parent')).toBe('P');
6001+
expect(element.getAttribute('child')).toBe('C');
6002+
});
59676003
});

0 commit comments

Comments
 (0)