fix(ivy): bindings should be checked in components created dynamically by root component' (#26864)
PR Close #26864
This commit is contained in:
parent
aadbc8a9d3
commit
911bfef04c
|
@ -421,6 +421,7 @@ function renderComponentOrTemplate<T>(
|
||||||
// Element was stored at 0 in data and directive was stored at 0 in directives
|
// Element was stored at 0 in data and directive was stored at 0 in directives
|
||||||
// in renderComponent()
|
// in renderComponent()
|
||||||
setHostBindings(getTView(), hostView);
|
setHostBindings(getTView(), hostView);
|
||||||
|
refreshDynamicEmbeddedViews(hostView);
|
||||||
componentRefresh(HEADER_OFFSET, false);
|
componentRefresh(HEADER_OFFSET, false);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1828,7 +1829,7 @@ export function containerRefreshEnd(): void {
|
||||||
* Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes them
|
* Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes them
|
||||||
* by executing an associated template function.
|
* by executing an associated template function.
|
||||||
*/
|
*/
|
||||||
function refreshDynamicEmbeddedViews(lViewData: LViewData) {
|
export function refreshDynamicEmbeddedViews(lViewData: LViewData) {
|
||||||
for (let current = getLViewChild(lViewData); current !== null; current = current[NEXT]) {
|
for (let current = getLViewChild(lViewData); current !== null; current = current[NEXT]) {
|
||||||
// Note: current can be an LViewData or an LContainer instance, but here we are only interested
|
// Note: current can be an LViewData or an LContainer instance, but here we are only interested
|
||||||
// in LContainer. We can tell it's an LContainer because its length is less than the LViewData
|
// in LContainer. We can tell it's an LContainer because its length is less than the LViewData
|
||||||
|
|
|
@ -1771,16 +1771,6 @@ describe('ViewContainerRef', () => {
|
||||||
|
|
||||||
describe('view engine compatibility', () => {
|
describe('view engine compatibility', () => {
|
||||||
|
|
||||||
// https://stackblitz.com/edit/angular-xxpffd?file=src%2Findex.html
|
|
||||||
it('should allow injecting VCRef into the root (bootstrapped) component', () => {
|
|
||||||
|
|
||||||
const DynamicComponent =
|
|
||||||
createComponent('dynamic-cmpt', function(rf: RenderFlags, parent: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
text(0, 'inserted dynamically');
|
|
||||||
}
|
|
||||||
}, 1, 0);
|
|
||||||
|
|
||||||
@Component({selector: 'app', template: ''})
|
@Component({selector: 'app', template: ''})
|
||||||
class AppCmpt {
|
class AppCmpt {
|
||||||
static ngComponentDef = defineComponent({
|
static ngComponentDef = defineComponent({
|
||||||
|
@ -1793,20 +1783,31 @@ describe('ViewContainerRef', () => {
|
||||||
template: (rf: RenderFlags, cmp: AppCmpt) => {}
|
template: (rf: RenderFlags, cmp: AppCmpt) => {}
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(private _vcRef: ViewContainerRef, private _cfResolver: ComponentFactoryResolver) {
|
||||||
private _vcRef: ViewContainerRef, private _cfResolver: ComponentFactoryResolver) {}
|
}
|
||||||
|
|
||||||
insert() {
|
insert(comp: any) {
|
||||||
this._vcRef.createComponent(this._cfResolver.resolveComponentFactory(DynamicComponent));
|
this._vcRef.createComponent(this._cfResolver.resolveComponentFactory(comp));
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() { this._vcRef.clear(); }
|
clear() { this._vcRef.clear(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackblitz.com/edit/angular-xxpffd?file=src%2Findex.html
|
||||||
|
it('should allow injecting VCRef into the root (bootstrapped) component', () => {
|
||||||
|
|
||||||
|
const DynamicComponent =
|
||||||
|
createComponent('dynamic-cmpt', function(rf: RenderFlags, parent: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
text(0, 'inserted dynamically');
|
||||||
|
}
|
||||||
|
}, 1, 0);
|
||||||
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(AppCmpt);
|
const fixture = new ComponentFixture(AppCmpt);
|
||||||
expect(fixture.outerHtml).toBe('<div host="mark"></div>');
|
expect(fixture.outerHtml).toBe('<div host="mark"></div>');
|
||||||
|
|
||||||
fixture.component.insert();
|
fixture.component.insert(DynamicComponent);
|
||||||
fixture.update();
|
fixture.update();
|
||||||
expect(fixture.outerHtml)
|
expect(fixture.outerHtml)
|
||||||
.toBe('<div host="mark"></div><dynamic-cmpt>inserted dynamically</dynamic-cmpt>');
|
.toBe('<div host="mark"></div><dynamic-cmpt>inserted dynamically</dynamic-cmpt>');
|
||||||
|
@ -1815,5 +1816,45 @@ describe('ViewContainerRef', () => {
|
||||||
fixture.update();
|
fixture.update();
|
||||||
expect(fixture.outerHtml).toBe('<div host="mark"></div>');
|
expect(fixture.outerHtml).toBe('<div host="mark"></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should check bindings for components dynamically created by root component', () => {
|
||||||
|
class DynamicCompWithBindings {
|
||||||
|
checkCount = 0;
|
||||||
|
|
||||||
|
ngDoCheck() { this.checkCount++; }
|
||||||
|
|
||||||
|
/** check count: {{ checkCount }} */
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: DynamicCompWithBindings,
|
||||||
|
selectors: [['dynamic-cmpt-with-bindings']],
|
||||||
|
factory: () => new DynamicCompWithBindings(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 1,
|
||||||
|
template: (rf: RenderFlags, ctx: DynamicCompWithBindings) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
text(0);
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
textBinding(0, interpolation1('check count: ', ctx.checkCount, ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(AppCmpt);
|
||||||
|
expect(fixture.outerHtml).toBe('<div host="mark"></div>');
|
||||||
|
|
||||||
|
fixture.component.insert(DynamicCompWithBindings);
|
||||||
|
fixture.update();
|
||||||
|
expect(fixture.outerHtml)
|
||||||
|
.toBe(
|
||||||
|
'<div host="mark"></div><dynamic-cmpt-with-bindings>check count: 1</dynamic-cmpt-with-bindings>');
|
||||||
|
|
||||||
|
fixture.update();
|
||||||
|
expect(fixture.outerHtml)
|
||||||
|
.toBe(
|
||||||
|
'<div host="mark"></div><dynamic-cmpt-with-bindings>check count: 2</dynamic-cmpt-with-bindings>');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue