feat(ivy): add ability to inspect local refs through context discovery (#26117)
PR Close #26117
This commit is contained in:
parent
325e8010e9
commit
5f6900ecc0
|
@ -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
|
||||
|
|
|
@ -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 || {};
|
||||
}
|
|
@ -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) {
|
||||
// <div myDir #elRef #dirRef="myDir">
|
||||
element(0, 'div', ['myDir'], ['elRef', '', 'dirRef', 'myDir']);
|
||||
}
|
||||
},
|
||||
directives: [MyDir]
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(Comp);
|
||||
fixture.update();
|
||||
|
||||
const divEl = fixture.hostElement.querySelector('div') !;
|
||||
const localRefs = getLocalRefs(divEl);
|
||||
|
||||
expect(localRefs.elRef.tagName.toLowerCase()).toBe('div');
|
||||
expect(localRefs.dirRef.constructor).toBe(MyDir);
|
||||
});
|
||||
|
||||
it('should return a map of local refs for an element with styling context', () => {
|
||||
|
||||
class Comp {
|
||||
static ngComponentDef = defineComponent({
|
||||
type: Comp,
|
||||
selectors: [['comp']],
|
||||
factory: () => new Comp(),
|
||||
consts: 2,
|
||||
vars: 0,
|
||||
template: (rf: RenderFlags, ctx: Comp) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
// <div #elRef class="fooClass">
|
||||
elementStart(0, 'div', null, ['elRef', '']);
|
||||
elementStyling(['fooClass']);
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementStylingApply(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(Comp);
|
||||
fixture.update();
|
||||
|
||||
const divEl = fixture.hostElement.querySelector('div') !;
|
||||
const localRefs = getLocalRefs(divEl);
|
||||
|
||||
expect(localRefs.elRef.tagName.toLowerCase()).toBe('div');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue