/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { ChangeDetectionStrategy } from '../../change_detection/constants'; import { Injector } from '../../di/injector'; import { assertEqual } from '../../util/assert'; import { assertLView } from '../assert'; import { discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext, readPatchedLView } from '../context_discovery'; import { getComponentDef, getDirectiveDef } from '../definition'; import { NodeInjector } from '../di'; import { buildDebugNode } from '../instructions/lview_debug'; import { isLView } from '../interfaces/type_checks'; import { CLEANUP, CONTEXT, FLAGS, T_HOST, TVIEW } from '../interfaces/view'; import { getLViewParent, getRootContext } from './view_traversal_utils'; import { getTNode, unwrapRNode } from './view_utils'; /** * Retrieves the component instance associated with a given DOM element. * * @usageNotes * Given the following DOM structure: * * ```html * *
* *
*
* ``` * * Calling `getComponent` on `` will return the instance of `ChildComponent` * associated with this DOM element. * * Calling the function on `` will return the `MyApp` instance. * * * @param element DOM element from which the component should be retrieved. * @returns Component instance associated with the element or `null` if there * is no component associated with it. * * @publicApi * @globalApi ng */ export function getComponent(element) { ngDevMode && assertDomElement(element); const context = getLContext(element); if (context === null) return null; if (context.component === undefined) { const lView = context.lView; if (lView === null) { return null; } context.component = getComponentAtNodeIndex(context.nodeIndex, lView); } return context.component; } /** * If inside an embedded view (e.g. `*ngIf` or `*ngFor`), retrieves the context of the embedded * view that the element is part of. Otherwise retrieves the instance of the component whose view * owns the element (in this case, the result is the same as calling `getOwningComponent`). * * @param element Element for which to get the surrounding component instance. * @returns Instance of the component that is around the element or null if the element isn't * inside any component. * * @publicApi * @globalApi ng */ export function getContext(element) { assertDomElement(element); const context = getLContext(element); const lView = context ? context.lView : null; return lView === null ? null : lView[CONTEXT]; } /** * Retrieves the component instance whose view contains the DOM element. * * For example, if `` is used in the template of `` * (i.e. a `ViewChild` of ``), calling `getOwningComponent` on `` * would return ``. * * @param elementOrDir DOM element, component or directive instance * for which to retrieve the root components. * @returns Component instance whose view owns the DOM element or null if the element is not * part of a component view. * * @publicApi * @globalApi ng */ export function getOwningComponent(elementOrDir) { const context = getLContext(elementOrDir); let lView = context ? context.lView : null; if (lView === null) return null; let parent; while (lView[TVIEW].type === 2 /* TViewType.Embedded */ && (parent = getLViewParent(lView))) { lView = parent; } return lView[FLAGS] & 256 /* LViewFlags.IsRoot */ ? null : lView[CONTEXT]; } /** * Retrieves all root components associated with a DOM element, directive or component instance. * Root components are those which have been bootstrapped by Angular. * * @param elementOrDir DOM element, component or directive instance * for which to retrieve the root components. * @returns Root components associated with the target object. * * @publicApi * @globalApi ng */ export function getRootComponents(elementOrDir) { const lView = readPatchedLView(elementOrDir); return lView !== null ? [getRootContext(lView)] : []; } /** * Retrieves an `Injector` associated with an element, component or directive instance. * * @param elementOrDir DOM element, component or directive instance for which to * retrieve the injector. * @returns Injector associated with the element, component or directive instance. * * @publicApi * @globalApi ng */ export function getInjector(elementOrDir) { const context = getLContext(elementOrDir); const lView = context ? context.lView : null; if (lView === null) return Injector.NULL; const tNode = lView[TVIEW].data[context.nodeIndex]; return new NodeInjector(tNode, lView); } /** * Retrieve a set of injection tokens at a given DOM node. * * @param element Element for which the injection tokens should be retrieved. */ export function getInjectionTokens(element) { const context = getLContext(element); const lView = context ? context.lView : null; if (lView === null) return []; const tView = lView[TVIEW]; const tNode = tView.data[context.nodeIndex]; const providerTokens = []; const startIndex = tNode.providerIndexes & 1048575 /* TNodeProviderIndexes.ProvidersStartIndexMask */; const endIndex = tNode.directiveEnd; for (let i = startIndex; i < endIndex; i++) { let value = tView.data[i]; if (isDirectiveDefHack(value)) { // The fact that we sometimes store Type and sometimes DirectiveDef in this location is a // design flaw. We should always store same type so that we can be monomorphic. The issue // is that for Components/Directives we store the def instead the type. The correct behavior // is that we should always be storing injectable type in this location. value = value.type; } providerTokens.push(value); } return providerTokens; } /** * Retrieves directive instances associated with a given DOM node. Does not include * component instances. * * @usageNotes * Given the following DOM structure: * * ```html * * * * * ``` * * Calling `getDirectives` on `