fix(ivy): support host bindings on dynamically created components (#25765)
PR Close #25765
This commit is contained in:
parent
1e3460be0b
commit
34be51898d
@ -18,11 +18,11 @@ import {Type} from '../type';
|
|||||||
|
|
||||||
import {assertComponentType, assertDefined} from './assert';
|
import {assertComponentType, assertDefined} from './assert';
|
||||||
import {LifecycleHooksFeature, createRootContext} from './component';
|
import {LifecycleHooksFeature, createRootContext} from './component';
|
||||||
import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions';
|
import {adjustBlueprintForNewNode, baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, queueHostBindingForCheck, renderEmbeddedTemplate, setHostBindings} from './instructions';
|
||||||
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
|
||||||
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
import {LElementNode, TNode, TNodeType} from './interfaces/node';
|
||||||
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {BINDING_INDEX, CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
|
||||||
import {RootViewRef, ViewRef} from './view_ref';
|
import {RootViewRef, ViewRef} from './view_ref';
|
||||||
|
|
||||||
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
|
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
|
||||||
@ -138,6 +138,9 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
|
|
||||||
// Create directive instance with factory() and store at index 0 in directives array
|
// Create directive instance with factory() and store at index 0 in directives array
|
||||||
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef);
|
component = baseDirectiveCreate(0, this.componentDef.factory(), this.componentDef);
|
||||||
|
if (this.componentDef.hostBindings) {
|
||||||
|
queueHostBindingForCheck(0, this.componentDef.hostVars);
|
||||||
|
}
|
||||||
rootContext.components.push(component);
|
rootContext.components.push(component);
|
||||||
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
initChangeDetectorIfExisting(elementNode.nodeInjector, component, elementNode.data !);
|
||||||
(elementNode.data as LViewData)[CONTEXT] = component;
|
(elementNode.data as LViewData)[CONTEXT] = component;
|
||||||
@ -146,6 +149,8 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
||||||
LifecycleHooksFeature(component, this.componentDef);
|
LifecycleHooksFeature(component, this.componentDef);
|
||||||
|
|
||||||
|
setHostBindings(rootView[TVIEW].hostBindings);
|
||||||
|
|
||||||
// Transform the arrays of native nodes into a LNode structure that can be consumed by the
|
// Transform the arrays of native nodes into a LNode structure that can be consumed by the
|
||||||
// projection instruction. This is needed to support the reprojection of these nodes.
|
// projection instruction. This is needed to support the reprojection of these nodes.
|
||||||
if (projectableNodes) {
|
if (projectableNodes) {
|
||||||
|
@ -1705,4 +1705,65 @@ describe('ViewContainerRef', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('host bindings', () => {
|
||||||
|
|
||||||
|
it('should support host bindings on dynamically created components', () => {
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
{selector: 'host-bindings', host: {'id': 'attribute', '[title]': 'title'}, template: ``})
|
||||||
|
class HostBindingCmpt {
|
||||||
|
title = 'initial';
|
||||||
|
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: HostBindingCmpt,
|
||||||
|
selectors: [['host-bindings']],
|
||||||
|
factory: () => new HostBindingCmpt(),
|
||||||
|
consts: 0,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, cmp: HostBindingCmpt) => {},
|
||||||
|
hostVars: 1,
|
||||||
|
attributes: ['id', 'attribute'],
|
||||||
|
hostBindings: function(dirIndex, elIndex) {
|
||||||
|
const cmptInstance = loadDirective<HostBindingCmpt>(dirIndex);
|
||||||
|
elementProperty(elIndex, 'title', bind(cmptInstance.title));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: `
|
||||||
|
<ng-template vcref></ng-template>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class AppCmpt {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: AppCmpt,
|
||||||
|
selectors: [['app']],
|
||||||
|
factory: () => new AppCmpt(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, cmp: AppCmpt) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
template(0, null, 0, 0, null, ['vcref', '']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: [HostBindingCmpt, DirectiveWithVCRef]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(AppCmpt);
|
||||||
|
expect(fixture.html).toBe('');
|
||||||
|
|
||||||
|
const componentRef = directiveInstance !.vcref.createComponent(
|
||||||
|
directiveInstance !.cfr.resolveComponentFactory(HostBindingCmpt));
|
||||||
|
expect(fixture.html).toBe('<host-bindings id="attribute" title="initial"></host-bindings>');
|
||||||
|
|
||||||
|
|
||||||
|
componentRef.instance.title = 'changed';
|
||||||
|
fixture.update();
|
||||||
|
expect(fixture.html).toBe('<host-bindings id="attribute" title="changed"></host-bindings>');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user