diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index 8b300f8245..492b9470be 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -28,23 +28,41 @@ export const MONKEY_PATCH_KEY_NAME = '__ngContext__'; * of the context. */ export interface LContext { - /** The component's parent view data */ + /** + * The component's parent view data. + */ lViewData: LViewData; - /** The index instance of the LNode */ + /** + * The index instance of the LNode. + */ lNodeIndex: number; - /** The instance of the DOM node that is attached to the lNode */ + /** + * The instance of the DOM node that is attached to the lNode. + */ native: RElement; - /** The instance of the Component node */ + /** + * The instance of the Component node. + */ component: {}|null|undefined; - /** The list of indices for the active directives that exist on this element */ + /** + * The list of indices for the active directives that exist on this element. + */ directiveIndices: number[]|null|undefined; - /** The list of active directives that exist on this element */ - directives: Array<{}>|null|undefined; + /** + * The list of active directives that exist on this element. + */ + directives: any[]|null|undefined; + + /** + * The map of local references (local reference name => element or directive instance) that exist + * on this element. + */ + localRefs: {[key: string]: any}|null|undefined; } /** Returns the matching `LContext` data for a given DOM node, directive or component instance. @@ -172,6 +190,7 @@ function createLContext(lViewData: LViewData, lNodeIndex: number, native: REleme component: undefined, directiveIndices: undefined, directives: undefined, + localRefs: undefined, }; } @@ -395,6 +414,28 @@ export function discoverDirectives(lViewData: LViewData, indices: number[]): num return directives; } +/** + * Returns a map of local references (local reference name => element or directive instance) that + * exist on a given element. + */ +export function discoverLocalRefs(lViewData: LViewData, lNodeIndex: number): {[key: string]: any}| + null { + const tNode = lViewData[TVIEW].data[lNodeIndex] as TNode; + if (tNode && tNode.localNames) { + const result: {[key: string]: any} = {}; + for (let i = 0; i < tNode.localNames.length; i += 2) { + const localRefName = tNode.localNames[i]; + const directiveIndex = tNode.localNames[i + 1] as number; + result[localRefName] = directiveIndex === -1 ? + getLNodeFromViewData(lViewData, lNodeIndex) !.native : + lViewData[DIRECTIVES] ![directiveIndex]; + } + return result; + } + + return null; +} + function getDirectiveStartIndex(tNode: TNode): number { // the tNode instances store a flag value which then has a // pointer which tells the starting index of where all the diff --git a/packages/core/src/render3/discovery_utils.ts b/packages/core/src/render3/discovery_utils.ts index 31d18edcfc..38f57d1381 100644 --- a/packages/core/src/render3/discovery_utils.ts +++ b/packages/core/src/render3/discovery_utils.ts @@ -8,7 +8,7 @@ import {Injector} from '../di/injector'; import {assertDefined} from './assert'; -import {LContext, discoverDirectiveIndices, discoverDirectives, getContext, isComponentInstance, readPatchedLViewData} from './context_discovery'; +import {LContext, discoverDirectiveIndices, discoverDirectives, discoverLocalRefs, getContext, isComponentInstance, readPatchedLViewData} from './context_discovery'; import {LElementNode, TNode, TNodeFlags} from './interfaces/node'; import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view'; @@ -141,3 +141,16 @@ export function getRootView(componentOrView: LViewData | {}): LViewData { } return lViewData; } + +/** + * Retrieve map of local references (local reference name => element or directive instance). + */ +export function getLocalRefs(target: {}): {[key: string]: any} { + const context = loadContext(target) !; + + if (context.localRefs === undefined) { + context.localRefs = discoverLocalRefs(context.lViewData, context.lNodeIndex); + } + + return context.localRefs || {}; +} \ No newline at end of file diff --git a/packages/core/test/render3/discovery_utils_spec.ts b/packages/core/test/render3/discovery_utils_spec.ts index eec9ca2a59..d8203603bb 100644 --- a/packages/core/test/render3/discovery_utils_spec.ts +++ b/packages/core/test/render3/discovery_utils_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ import {StaticInjector} from '../../src/di/injector'; -import {getComponent, getDirectives, getHostComponent, getInjector, getRootComponents} from '../../src/render3/discovery_utils'; +import {getComponent, getDirectives, getHostComponent, getInjector, getLocalRefs, getRootComponents} from '../../src/render3/discovery_utils'; import {RenderFlags, defineComponent, defineDirective} from '../../src/render3/index'; -import {element} from '../../src/render3/instructions'; +import {element, elementEnd, elementStart, elementStyling, elementStylingApply} from '../../src/render3/instructions'; import {ComponentFixture} from './render_util'; @@ -266,4 +266,76 @@ describe('discovery utils', () => { expect(getInjector(fixture.hostElement)).toEqual(null); }); }); + + describe('getLocalRefs', () => { + it('should return a map of local refs for an element', () => { + + class MyDir { + static ngDirectiveDef = defineDirective({ + type: MyDir, + selectors: [['', 'myDir', '']], + exportAs: 'myDir', + factory: () => new MyDir() + }); + } + + class Comp { + static ngComponentDef = defineComponent({ + type: Comp, + selectors: [['comp']], + factory: () => new Comp(), + consts: 3, + vars: 0, + template: (rf: RenderFlags, ctx: Comp) => { + if (rf & RenderFlags.Create) { + //