MCPcopy Create free account
hub / github.com/angular/angular / calcPathForNode

Function calcPathForNode

packages/core/src/hydration/node_lookup_utils.ts:356–431  ·  view source on GitHub ↗
(
  tNode: TNode,
  lView: LView,
  excludedParentNodes: Set<number> | null,
)

Source from the content-addressed store, hash-verified

354 * instructions needs to be generated for a TNode.
355 */
356export function calcPathForNode(
357 tNode: TNode,
358 lView: LView,
359 excludedParentNodes: Set<number> | null,
360): string {
361 let parentTNode = tNode.parent;
362 let parentIndex: number | string;
363 let parentRNode: RNode;
364 let referenceNodeName: string;
365
366 // Skip over all parent nodes that are disconnected from the DOM, such nodes
367 // can not be used as anchors.
368 //
369 // This might happen in certain content projection-based use-cases, where
370 // a content of an element is projected and used, when a parent element
371 // itself remains detached from DOM. In this scenario we try to find a parent
372 // element that is attached to DOM and can act as an anchor instead.
373 //
374 // It can also happen that the parent node should be excluded, for example,
375 // because it belongs to an i18n block, which requires paths which aren't
376 // relative to other views in an i18n block.
377 while (
378 parentTNode !== null &&
379 (isDisconnectedNode(parentTNode, lView) || excludedParentNodes?.has(parentTNode.index))
380 ) {
381 parentTNode = parentTNode.parent;
382 }
383
384 if (parentTNode === null || !(parentTNode.type & TNodeType.AnyRNode)) {
385 // If there is no parent TNode or a parent TNode does not represent an RNode
386 // (i.e. not a DOM node), use component host element as a reference node.
387 parentIndex = referenceNodeName = REFERENCE_NODE_HOST;
388 parentRNode = lView[DECLARATION_COMPONENT_VIEW][HOST]!;
389 } else {
390 // Use parent TNode as a reference node.
391 parentIndex = parentTNode.index;
392 parentRNode = unwrapRNode(lView[parentIndex]);
393 referenceNodeName = renderStringify(parentIndex - HEADER_OFFSET);
394 }
395 let rNode = unwrapRNode(lView[tNode.index]);
396 if (tNode.type & (TNodeType.AnyContainer | TNodeType.Icu)) {
397 // For <ng-container> nodes, instead of serializing a reference
398 // to the anchor comment node, serialize a location of the first
399 // DOM element. Paired with the container size (serialized as a part
400 // of `ngh.containers`), it should give enough information for runtime
401 // to hydrate nodes in this container.
402 const firstRNode = getFirstNativeNode(lView, tNode);
403
404 // If container is not empty, use a reference to the first element,
405 // otherwise, rNode would point to an anchor comment node.
406 if (firstRNode) {
407 rNode = firstRNode;
408 }
409 }
410 let path: string | null = calcPathBetween(parentRNode as Node, rNode as Node, referenceNodeName);
411 if (path === null && parentRNode !== rNode) {
412 // Searching for a path between elements within a host node failed.
413 // Trying to find a path to an element starting from the `document.body` instead.

Callers 1

appendSerializedNodePathFunction · 0.90

Calls 7

unwrapRNodeFunction · 0.90
renderStringifyFunction · 0.90
getFirstNativeNodeFunction · 0.90
nodeNotFoundErrorFunction · 0.90
calcPathBetweenFunction · 0.85
isDisconnectedNodeFunction · 0.70
hasMethod · 0.65

Tested by

no test coverage detected