fix(ivy): init hooks should be called before host bindings (#26802)
PR Close #26802
This commit is contained in:
parent
df6a8b28de
commit
ea0a99610d
@ -78,11 +78,13 @@ export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | nu
|
|||||||
if (rf !== RenderFlags.Create) {
|
if (rf !== RenderFlags.Create) {
|
||||||
const creationMode = getCreationMode();
|
const creationMode = getCreationMode();
|
||||||
const checkNoChangesMode = getCheckNoChangesMode();
|
const checkNoChangesMode = getCheckNoChangesMode();
|
||||||
setHostBindings(tView, viewData);
|
|
||||||
|
|
||||||
if (!checkNoChangesMode) {
|
if (!checkNoChangesMode) {
|
||||||
executeInitHooks(viewData, tView, creationMode);
|
executeInitHooks(viewData, tView, creationMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHostBindings(tView, viewData);
|
||||||
|
|
||||||
refreshDynamicEmbeddedViews(viewData);
|
refreshDynamicEmbeddedViews(viewData);
|
||||||
|
|
||||||
// Content query results must be refreshed before content hooks are called.
|
// Content query results must be refreshed before content hooks are called.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {EventEmitter} from '@angular/core';
|
import {EventEmitter} from '@angular/core';
|
||||||
|
|
||||||
import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature} from '../../src/render3/index';
|
import {AttributeMarker, defineComponent, template, defineDirective, ProvidersFeature, NgOnChangesFeature} from '../../src/render3/index';
|
||||||
import {bind, directiveInject, element, elementEnd, elementProperty, elementStart, load, text, textBinding} from '../../src/render3/instructions';
|
import {bind, directiveInject, element, elementEnd, elementProperty, elementStart, load, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
||||||
@ -218,6 +218,72 @@ describe('host bindings', () => {
|
|||||||
expect(hostBindingDiv.id).toEqual('bar');
|
expect(hostBindingDiv.id).toEqual('bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support host bindings that rely on values from init hooks', () => {
|
||||||
|
class InitHookComp {
|
||||||
|
// @Input()
|
||||||
|
inputValue = '';
|
||||||
|
|
||||||
|
changesValue = '';
|
||||||
|
initValue = '';
|
||||||
|
checkValue = '';
|
||||||
|
|
||||||
|
ngOnChanges() { this.changesValue = 'changes'; }
|
||||||
|
|
||||||
|
ngOnInit() { this.initValue = 'init'; }
|
||||||
|
|
||||||
|
ngDoCheck() { this.checkValue = 'check'; }
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return `${this.inputValue}-${this.changesValue}-${this.initValue}-${this.checkValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: InitHookComp,
|
||||||
|
selectors: [['init-hook-comp']],
|
||||||
|
factory: () => new InitHookComp(),
|
||||||
|
template: (rf: RenderFlags, ctx: InitHookComp) => {},
|
||||||
|
consts: 0,
|
||||||
|
vars: 0,
|
||||||
|
hostVars: 1,
|
||||||
|
features: [NgOnChangesFeature],
|
||||||
|
hostBindings: (dirIndex: number, elIndex: number) => {
|
||||||
|
const ctx = load(dirIndex) as InitHookComp;
|
||||||
|
elementProperty(elIndex, 'title', bind(ctx.value));
|
||||||
|
},
|
||||||
|
inputs: {inputValue: 'inputValue'}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** <init-hook-comp [inputValue]="value"></init-hook-comp> */
|
||||||
|
class App {
|
||||||
|
value = 'input';
|
||||||
|
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: App,
|
||||||
|
selectors: [['app']],
|
||||||
|
factory: () => new App(),
|
||||||
|
template: (rf: RenderFlags, ctx: App) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'init-hook-comp');
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
elementProperty(0, 'inputValue', bind(ctx.value));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
consts: 1,
|
||||||
|
vars: 1,
|
||||||
|
directives: [InitHookComp]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(App);
|
||||||
|
const initHookComp = fixture.hostElement.querySelector('init-hook-comp') as HTMLElement;
|
||||||
|
expect(initHookComp.title).toEqual('input-changes-init-check');
|
||||||
|
|
||||||
|
fixture.component.value = 'input2';
|
||||||
|
fixture.update();
|
||||||
|
expect(initHookComp.title).toEqual('input2-changes-init-check');
|
||||||
|
});
|
||||||
|
|
||||||
it('should support host bindings on second template pass', () => {
|
it('should support host bindings on second template pass', () => {
|
||||||
/** <div hostBindingDir></div> */
|
/** <div hostBindingDir></div> */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user