Skip to content

fix(platform-browser): avoid false NG05106 errors on insertBefore - #70423

Open
lazerg wants to merge 1 commit into
angular:mainfrom
lazerg:fix/issue-70418-insert-before-parent-identity
Open

fix(platform-browser): avoid false NG05106 errors on insertBefore#70423
lazerg wants to merge 1 commit into
angular:mainfrom
lazerg:fix/issue-70418-insert-before-parent-identity

Conversation

@lazerg

@lazerg lazerg commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

DefaultDomRenderer2.insertBefore checks that refChild.parentNode is the parent it is about to insert into and throws NG05106 when it is not. parentNode only guarantees the parent node itself though, not one particular object for it, so an implementation may hand out more than one wrapper for the same element. happy-dom does that for <form> and <select>, whose constructors return a Proxy while children attached before the element was connected keep a reference to the raw instance. A component whose template root is a form then throws on insertions the native call would have completed.

Run the native call first and inspect the reference node only after it throws, so the descriptive error still replaces the opaque NotFoundError in both cases the guard was written for.

Fixes #70418

@pullapprove
pullapprove Bot requested a review from crisbeto August 27, 2026 08:02
@angular-robot angular-robot Bot added the area: core Issues related to the framework runtime label Aug 27, 2026
@ngbot ngbot Bot added this to the Backlog milestone Aug 27, 2026
@lazerg
lazerg force-pushed the fix/issue-70418-insert-before-parent-identity branch from 80b6011 to 8f4d9fa Compare August 27, 2026 08:16
@lazerg lazerg changed the title fix(platform-browser): only report a missing insertBefore reference node when the insert fails fix(platform-browser): avoid false NG05106 errors on insertBefore Aug 27, 2026
parent.appendChild(refChild);

// some DOM implementations hand out more than one object for the same element
const wrappedParent = new Proxy(parent, {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proxy trap is heavier to read, looking at the implementation we only need to pass an object who's shape would go against === comparison, I think this should work (haven't checked locally):

it('inserts a child even when refChild.parentNode is not the passed-in parent object', () => {
  // some DOM implementations hand out more than one object for the same element
  const realParent = document.createElement('div');
  const refChild = document.createElement('span');
  const newChild = document.createElement('div');
  realParent.appendChild(refChild);

  const parentAlias = {
    tagName: 'DIV',
    insertBefore: (n: Node, r: Node) => realParent.insertBefore(n, r),
  };

  renderer.insertBefore(parentAlias, newChild, refChild);

  expect(newChild.parentNode).toBe(realParent);
  expect(newChild.nextSibling).toBe(refChild);
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, applied in cbc65b9. I ran it locally first: it fails on the old code with NG05106 and passes with the fix, on both Chromium and Firefox. It is also the stricter check, since a plain object breaks loudly if the renderer ever reads more than insertBefore off the parent.

@arturovt arturovt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JeanMeche LGTM for me overall, left a comment to simplify the unit test.

The guard added for NG05106 compares `refChild.parentNode` with the target
parent by object identity, but `parentNode` is only specified to return the
parent node, not one particular object for it. DOM implementations that hand
out more than one object per element then hit the guard on inserts the native
call would have completed. Run the native call first and describe the failure
only once it actually throws.
@lazerg
lazerg force-pushed the fix/issue-70418-insert-before-parent-identity branch from 8f4d9fa to cbc65b9 Compare August 27, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Issues related to the framework runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NG05106 false positive: insertBefore guard compares parentNode by object identity

2 participants