* Recursively match the current TNode against the predicate, and goes on with the next ones. * * @param tNode the current TNode * @param lView the LView of this TNode * @param predicate the predicate to match * @param matches the list of positive matches * @param elementsOnly whether only elem
( tNode: TNode, lView: LView, predicate: Predicate<DebugElement> | Predicate<DebugNode>, matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any, )
| 477 | * @param rootNativeNode the root native node on which predicate should not be matched |
| 478 | */ |
| 479 | function _queryNodeChildren( |
| 480 | tNode: TNode, |
| 481 | lView: LView, |
| 482 | predicate: Predicate<DebugElement> | Predicate<DebugNode>, |
| 483 | matches: DebugElement[] | DebugNode[], |
| 484 | elementsOnly: boolean, |
| 485 | rootNativeNode: any, |
| 486 | ) { |
| 487 | ngDevMode && assertTNodeForLView(tNode, lView); |
| 488 | const nativeNode = getNativeByTNodeOrNull(tNode, lView); |
| 489 | // For each type of TNode, specific logic is executed. |
| 490 | if (tNode.type & (TNodeType.AnyRNode | TNodeType.ElementContainer)) { |
| 491 | // Case 1: the TNode is an element |
| 492 | // The native node has to be checked. |
| 493 | _addQueryMatch(nativeNode, predicate, matches, elementsOnly, rootNativeNode); |
| 494 | if (isComponentHost(tNode)) { |
| 495 | // If the element is the host of a component, then all nodes in its view have to be processed. |
| 496 | // Note: the component's content (tNode.child) will be processed from the insertion points. |
| 497 | const componentView = getComponentLViewByIndex(tNode.index, lView); |
| 498 | if (componentView && componentView[TVIEW].firstChild) { |
| 499 | _queryNodeChildren( |
| 500 | componentView[TVIEW].firstChild!, |
| 501 | componentView, |
| 502 | predicate, |
| 503 | matches, |
| 504 | elementsOnly, |
| 505 | rootNativeNode, |
| 506 | ); |
| 507 | } |
| 508 | } else { |
| 509 | if (tNode.child) { |
| 510 | // Otherwise, its children have to be processed. |
| 511 | _queryNodeChildren(tNode.child, lView, predicate, matches, elementsOnly, rootNativeNode); |
| 512 | } |
| 513 | |
| 514 | // We also have to query the DOM directly in order to catch elements inserted through |
| 515 | // Renderer2. Note that this is __not__ optimal, because we're walking similar trees multiple |
| 516 | // times. ViewEngine could do it more efficiently, because all the insertions go through |
| 517 | // Renderer2, however that's not the case in Ivy. This approach is being used because: |
| 518 | // 1. Matching the ViewEngine behavior would mean potentially introducing a dependency |
| 519 | // from `Renderer2` to Ivy which could bring Ivy code into ViewEngine. |
| 520 | // 2. It allows us to capture nodes that were inserted directly via the DOM. |
| 521 | nativeNode && _queryNativeNodeDescendants(nativeNode, predicate, matches, elementsOnly); |
| 522 | } |
| 523 | // In all cases, if a dynamic container exists for this node, each view inside it has to be |
| 524 | // processed. |
| 525 | const nodeOrContainer = lView[tNode.index]; |
| 526 | if (isLContainer(nodeOrContainer)) { |
| 527 | _queryNodeChildrenInContainer( |
| 528 | nodeOrContainer, |
| 529 | predicate, |
| 530 | matches, |
| 531 | elementsOnly, |
| 532 | rootNativeNode, |
| 533 | ); |
| 534 | } |
| 535 | } else if (tNode.type & TNodeType.Container) { |
| 536 | // Case 2: the TNode is a container |
no test coverage detected
searching dependent graphs…