angular/components · error · Error

Cannot attach component portal to outlet without an Applicat

Error message

Cannot attach component portal to outlet without an ApplicationRef.

What it means

BasePortalOutlet/DomPortalOutlet can attach a ComponentPortal only if it has an ApplicationRef (needed to create and run change detection for the component). When the outlet was constructed without an ApplicationRef (only an injector/viewContainerRef) and the portal is a ComponentPortal, this dev-mode check throws.

Source

Thrown at src/cdk/portal/dom-portal-outlet.ts:69

    // When the ViewContainerRef is missing, we use the factory to create the component directly
    // and then manually attach the view to the application.
    if (portal.viewContainerRef) {
      const injector = portal.injector || portal.viewContainerRef.injector;
      const ngModuleRef = injector.get(NgModuleRef, null, {optional: true}) || undefined;

      componentRef = portal.viewContainerRef.createComponent(portal.component, {
        index: portal.viewContainerRef.length,
        injector,
        ngModuleRef,
        projectableNodes: portal.projectableNodes || undefined,
        bindings: portal.bindings || undefined,
        directives: portal.directives || undefined,
      });

      this.setDisposeFn(() => componentRef.destroy());
    } else {
      if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this._appRef) {
        throw Error('Cannot attach component portal to outlet without an ApplicationRef.');
      }
      const appRef = this._appRef!;

      const elementInjector = portal.injector || this._defaultInjector || Injector.NULL;
      const environmentInjector = elementInjector.get(EnvironmentInjector, appRef.injector);
      componentRef = createComponent(portal.component, {
        elementInjector,
        environmentInjector,
        projectableNodes: portal.projectableNodes || undefined,
        bindings: portal.bindings || undefined,
        directives: portal.directives || undefined,
      });

      appRef.attachView(componentRef.hostView);
      this.setDisposeFn(() => {
        // Verify that the ApplicationRef has registered views before trying to detach a host view.
        // This check also protects the `detachView` from being called on a destroyed ApplicationRef.
        if (appRef.viewCount > 0) {

View on GitHub (pinned to 0411926e7d)

Solutions

  1. Pass an ApplicationRef when constructing the outlet: `new DomPortalOutlet(host, injector, injector.get(ApplicationRef), injector.get(DOCUMENT))`
  2. Attach a TemplatePortal or DomPortal instead if you only need DOM content
  3. Use a ViewContainerRef-based outlet (CdkPortalOutlet directive) which can create components without ApplicationRef
  4. Ensure your DI environment resolves ApplicationRef (not outside Angular's injector)

Example fix

// before
const outlet = new DomPortalOutlet(hostEl, injector, undefined, document);
outlet.attachComponentPortal(new ComponentPortal(MyComp)); // throws
// after
const appRef = injector.get(ApplicationRef);
const outlet = new DomPortalOutlet(hostEl, injector, appRef, document);
outlet.attachComponentPortal(new ComponentPortal(MyComp));
Defensive patterns

Strategy: validation

Validate before calling

const appRef = injector.get(ApplicationRef, null);
if (appRef) {
  const outlet = new DomPortalOutlet(host, injector, appRef, injector.get(DOCUMENT));
  outlet.attachComponentPortal(portal);
}

Type guard

function supportsComponentPortals(outlet: DomPortalOutlet): boolean {
  return (outlet as unknown as {_appRef?: unknown})._appRef != null;
}

Try / catch

try {
  outlet.attachComponentPortal(portal);
} catch (e) {
  if (e.message.includes('without an ApplicationRef')) {
    outlet.attachTemplatePortal(new TemplatePortal(tpl, vcr)); // fallback to template portal
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling `outlet.attachComponentPortal(portal)` on a DomPortalOutlet constructed as `new DomPortalOutlet(hostEl, injector, null, doc)` (no ApplicationRef), or on a CdkPortalOutlet in a context with no ApplicationRef available.

Common situations: Manually constructing DomPortalOutlet for dynamic UI (tooltips, dialogs) and passing undefined for the ApplicationRef parameter; migrating Angular versions where createComponent requires an EnvironmentInjector/ApplicationRef; using the outlet purely for DOM/Template portals then switching to a ComponentPortal.

Related errors


AI-assisted analysis of angular/components@0411926e7d (2026-08-31). Data as JSON: /api/errors/2d209a50351c85b6. Report an issue: GitHub.