{"record":{"id":"e05160ff71532907","repo":"angular/components","slug":"dom-portal-content-must-be-attached-to-a-parent-no-e05160","errorCode":null,"errorMessage":"DOM portal content must be attached to a parent node.","messagePattern":"DOM portal content must be attached to a parent node\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cdk/portal/portal-directives.ts","lineNumber":182,"sourceCode":"    super.setDisposeFn(() => this._viewContainerRef.clear());\n\n    this._attachedPortal = portal;\n    this._attachedRef = viewRef;\n    this.attached.emit(viewRef);\n\n    return viewRef;\n  }\n\n  /**\n   * Attaches the given DomPortal to this PortalHost by moving all of the portal content into it.\n   * @param portal Portal to be attached.\n   * @deprecated To be turned into a method.\n   * @breaking-change 10.0.0\n   */\n  override attachDomPortal = (portal: DomPortal) => {\n    const element = portal.element;\n    if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n      throw Error('DOM portal content must be attached to a parent node.');\n    }\n\n    // Anchor used to save the element's previous position so\n    // that we can restore it when the portal is detached.\n    const anchorNode = this._document.createComment('dom-portal');\n\n    portal.setAttachedHost(this);\n    element.parentNode!.insertBefore(anchorNode, element);\n    this._getRootNode().appendChild(element);\n    this._attachedPortal = portal;\n\n    super.setDisposeFn(() => {\n      if (anchorNode.parentNode) {\n        anchorNode.parentNode!.replaceChild(element, anchorNode);\n      }\n    });\n  };\n","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/cdk/portal/portal-directives.ts#L164-L200","documentation":"Same check as DomPortalOutlet, but in the CdkPortalOutlet directive: a DomPortal's element must have a parentNode when `attachDomPortal` runs, since the outlet uses an anchor comment to restore the element's original DOM position on detach.","triggerScenarios":"Binding an element without a parent to a `<ng-template cdkPortalOutlet>` via a DomPortal, e.g. `outlet.attach(new DomPortal(detachedEl))`, including elements created in component code or parsed from strings.","commonSituations":"Angular app rendering detached elements created with renderer.createElement; passing content extracted from a detached template; host bindings that clear the element's parent before the portal attaches; SSR/hydration edge cases where the node is not yet in the tree.","solutions":["Ensure the source element is inserted in the DOM before constructing the DomPortal","Attach the portal only after view init (ngAfterViewInit) when the element is in the tree","Switch to TemplatePortal/ComponentPortal for non-DOM-hosted content","Add an `el.isConnected` guard before calling attach"],"exampleFix":"// before\nconst portal = new DomPortal(this.detachedDiv);\nthis.outlet.attach(portal); // throws\n// after\nngAfterViewInit() {\n  if (!this.detachedDiv.parentNode) { this.hostRef.nativeElement.appendChild(this.detachedDiv); }\n  this.outlet.attach(new DomPortal(this.detachedDiv));\n}","handlingStrategy":"validation","validationCode":"ngAfterViewInit() {\n  if (this.sourceEl?.isConnected && this.outlet && !this.outlet.hasAttached()) {\n    this.outlet.attach(new DomPortal(this.sourceEl));\n  }\n}","typeGuard":"function isAttachedToDom(el: Node | null | undefined): el is Node {\n  return !!el && el.isConnected && el.parentNode != null;\n}","tryCatchPattern":"try {\n  outlet.attachDomPortal(portal);\n} catch (e) {\n  if (e.message.includes('must be attached to a parent node')) {\n    outlet._document.body.appendChild(portal.element);\n    outlet.attachDomPortal(portal);\n  } else { throw e; }\n}","preventionTips":["Attach DOM portals only after view init when nodes are in the tree","Verify parentNode exists before calling attach","Avoid binding detached nodes to cdkPortalOutlet inputs","Use TemplatePortal when the content originates from Angular templates"],"tags":["angular","cdk","portal","dom"],"backgroundTag":"detached-dom-portal","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}