Programmatically render/destroy components from non-host component (Angular)

Discussão em 'Angular' iniciado por Ilya Konrad, Junho 19, 2025.

  1. Ilya Konrad

    Ilya Konrad Guest

    The task is to create a fully dynamic and independent component (Tooltip) that could be programmatically rendered/destroyed in a certain place in the DOM (Dashboard) by a non-host component (Calendar). It is a tooltip shown on hover inside of Calendar (or over the calendar to be precise). It can't be added to the DOM as a child of Calendar though due to certain CSS limitations with position: fixed + overflow: auto.

    Here's the basic structure I want:

    <app-dashboard>
    <app-whatever>
    <app-random>
    <app-calendar>I programmatically add a tooltip to my distant ancestor on hover</app-calendar>
    </app-random>
    </app-whatever>

    <app-tooltip>I am programmatically rendered and destroyed</app-tooltip>
    <app-dashboard>


    After searching the internet and the docs, I now think I have to use createComponent() inside Calendar component.

    I've tried to use the standalone createComponent() function as well as viewContainer.createComponent(). The latter doesn't allow to set a host element.

    The former allows for that, but it has another issue: when I destroy Tooltip using this.tooltipInstance.destroy(), it deletes the host element too.

    Here's my setup:

    <app-dashboard>
    <app-wrapper>
    <app-section>
    <app-calendar>I programmatically add a tooltip to my distant ancestor on hover</app-calendar>
    </app-section>
    </app-wrapper>

    <!-- I am wiped out out on mouse leave :( -->
    <div class="event-tooltip-host">
    <app-tooltip>I am programmatically rendered and destroyed</app-tooltip>
    </div>
    <app-dashboard>


    eventMouseEnter({ event, el }) {
    this.tooltipInstance = createComponent(TooltipComponent, {
    environmentInjector: this.injector,
    hostElement: document.querySelector('.event-tooltip-host')!,
    bindings: [inputBinding('event', () => event), inputBinding('element', () => el)]
    })

    this.appRef.attachView(this.tooltipInstance.hostView)
    this.tooltipInstance.changeDetectorRef.detectChanges()
    }

    eventMouseLeave() {
    this.appRef.detachView(this.tooltipInstance.hostView)
    this.tooltipInstance.destroy()
    }


    It appears impossible to fully control dynamic rendering of a component back and forth from within a totally random component.

    My backup plan is to do it from Dashboard component via some app-level actions which I can listen to in any component, but I would really expect Angular to have a better way to do it.

    So, the question is how do I avoid destroying the wrapper, <div class="event-tooltip-host">, and only destroy <app-tooltip>?

    Continue reading...

Compartilhe esta Página