refactor(ivy): remove content query creation from directive factories (#24811)
PR Close #24811
This commit is contained in:
parent
328971ffcc
commit
0399c6972a
|
@ -39,6 +39,7 @@ export {
|
|||
T as ɵT,
|
||||
V as ɵV,
|
||||
Q as ɵQ,
|
||||
Qr as ɵQr,
|
||||
d as ɵd,
|
||||
P as ɵP,
|
||||
b as ɵb,
|
||||
|
@ -69,6 +70,7 @@ export {
|
|||
cR as ɵcR,
|
||||
cr as ɵcr,
|
||||
qR as ɵqR,
|
||||
ql as ɵql,
|
||||
e as ɵe,
|
||||
p as ɵp,
|
||||
pD as ɵpD,
|
||||
|
|
|
@ -48,7 +48,7 @@ export function defineComponent<T>(componentDefinition: {
|
|||
/**
|
||||
* Factory method used to create an instance of directive.
|
||||
*/
|
||||
factory: () => T | ({0: T} & any[]); /* trying to say T | [T, ...any] */
|
||||
factory: () => T;
|
||||
|
||||
/**
|
||||
* Static attributes to set on host element.
|
||||
|
@ -120,6 +120,14 @@ export function defineComponent<T>(componentDefinition: {
|
|||
*/
|
||||
hostBindings?: (directiveIndex: number, elementIndex: number) => void;
|
||||
|
||||
/**
|
||||
* Function to create instances of content queries associated with a given directive.
|
||||
*/
|
||||
contentQueries?: (() => void);
|
||||
|
||||
/** Refreshes content queries associated with directives in a given view */
|
||||
contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void);
|
||||
|
||||
/**
|
||||
* Defines the name that can be used in the template to assign this directive to a variable.
|
||||
*
|
||||
|
@ -216,6 +224,8 @@ export function defineComponent<T>(componentDefinition: {
|
|||
factory: componentDefinition.factory,
|
||||
template: componentDefinition.template || null !,
|
||||
hostBindings: componentDefinition.hostBindings || null,
|
||||
contentQueries: componentDefinition.contentQueries || null,
|
||||
contentQueriesRefresh: componentDefinition.contentQueriesRefresh || null,
|
||||
attributes: componentDefinition.attributes || null,
|
||||
inputs: invertObject(componentDefinition.inputs, declaredInputs),
|
||||
declaredInputs: declaredInputs,
|
||||
|
@ -448,6 +458,14 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
|
|||
*/
|
||||
hostBindings?: (directiveIndex: number, elementIndex: number) => void;
|
||||
|
||||
/**
|
||||
* Function to create instances of content queries associated with a given directive.
|
||||
*/
|
||||
contentQueries?: (() => void);
|
||||
|
||||
/** Refreshes content queries associated with directives in a given view */
|
||||
contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void);
|
||||
|
||||
/**
|
||||
* Defines the name that can be used in the template to assign this directive to a variable.
|
||||
*
|
||||
|
|
|
@ -19,7 +19,7 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_Vie
|
|||
import {Type} from '../type';
|
||||
|
||||
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
|
||||
import {addToViewTree, assertPreviousIsParent, createEmbeddedViewNode, createLContainer, createLNodeObject, createTNode, getDirectiveInstance, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
||||
import {addToViewTree, assertPreviousIsParent, createEmbeddedViewNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getRenderer, isComponent, renderEmbeddedTemplate, resolveDirective} from './instructions';
|
||||
import {VIEWS} from './interfaces/container';
|
||||
import {ComponentTemplate, DirectiveDefInternal, RenderFlags} from './interfaces/definition';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
|
@ -378,7 +378,7 @@ export function getOrCreateInjectable<T>(
|
|||
// and matches the given token, return the directive instance.
|
||||
const directiveDef = defs[i] as DirectiveDefInternal<any>;
|
||||
if (directiveDef.type === token && directiveDef.diPublic) {
|
||||
return getDirectiveInstance(node.view[DIRECTIVES] ![i]);
|
||||
return node.view[DIRECTIVES] ![i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,11 @@ export {
|
|||
query as Q,
|
||||
queryRefresh as qR,
|
||||
} from './query';
|
||||
export {
|
||||
registerContentQuery as Qr,
|
||||
loadQueryList as ql,
|
||||
} from './instructions';
|
||||
|
||||
export {
|
||||
pureFunction0 as f0,
|
||||
pureFunction1 as f1,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import './ng_dev_mode';
|
||||
|
||||
import {QueryList} from '../linker';
|
||||
import {Sanitizer} from '../sanitization/security';
|
||||
|
||||
import {assertDefined, assertEqual, assertLessThan, assertNotDefined, assertNotEqual} from './assert';
|
||||
|
@ -20,7 +21,7 @@ import {AttributeMarker, InitialInputData, InitialInputs, LContainerNode, LEleme
|
|||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||
import {LQueries} from './interfaces/query';
|
||||
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTEXT, CurrentMatchesList, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
|
||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, CurrentMatchesList, DIRECTIVES, FLAGS, HEADER_OFFSET, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RootContext, SANITIZER, TAIL, TData, TVIEW, TView} from './interfaces/view';
|
||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||
import {appendChild, appendProjectedNode, canInsertNativeNode, createTextNode, findComponentHost, getChildLNode, getLViewChild, getNextLNode, getParentLNode, insertView, removeView} from './node_manipulation';
|
||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||
|
@ -29,6 +30,7 @@ import {isDifferent, stringify} from './util';
|
|||
import {ViewRef} from './view_ref';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||
* component's host node (LElement) as the value. This is used in methods like detectChanges to
|
||||
|
@ -266,9 +268,11 @@ function refreshView() {
|
|||
tView.firstTemplatePass = firstTemplatePass = false;
|
||||
|
||||
setHostBindings(tView.hostBindings);
|
||||
refreshContentQueries(tView);
|
||||
refreshChildComponents(tView.components);
|
||||
}
|
||||
|
||||
|
||||
/** Sets the host bindings for the current view. */
|
||||
export function setHostBindings(bindings: number[] | null): void {
|
||||
if (bindings != null) {
|
||||
|
@ -281,6 +285,18 @@ export function setHostBindings(bindings: number[] | null): void {
|
|||
}
|
||||
}
|
||||
|
||||
/** Refreshes content queries for all directives in the given view. */
|
||||
function refreshContentQueries(tView: TView): void {
|
||||
if (tView.contentQueries != null) {
|
||||
for (let i = 0; i < tView.contentQueries.length; i += 2) {
|
||||
const directiveDefIdx = tView.contentQueries[i];
|
||||
const directiveDef = tView.directives ![directiveDefIdx];
|
||||
|
||||
directiveDef.contentQueriesRefresh !(directiveDefIdx, tView.contentQueries[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Refreshes child components in the current view. */
|
||||
function refreshChildComponents(components: number[] | null): void {
|
||||
if (components != null) {
|
||||
|
@ -315,7 +331,8 @@ export function createLViewData<T>(
|
|||
renderer, // renderer
|
||||
sanitizer || null, // sanitizer
|
||||
null, // tail
|
||||
-1 // containerIndex
|
||||
-1, // containerIndex
|
||||
null, // contentQueries
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -882,6 +899,7 @@ export function createTView(
|
|||
pipeDestroyHooks: null,
|
||||
cleanup: null,
|
||||
hostBindings: null,
|
||||
contentQueries: null,
|
||||
components: null,
|
||||
directiveRegistry: typeof directives === 'function' ? directives() : directives,
|
||||
pipeRegistry: typeof pipes === 'function' ? pipes() : pipes,
|
||||
|
@ -1472,7 +1490,7 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
|
|||
//////////////////////////
|
||||
|
||||
/**
|
||||
* Create a directive.
|
||||
* Create a directive and their associated content queries.
|
||||
*
|
||||
* NOTE: directives can be created in order other than the index order. They can also
|
||||
* be retrieved before they are created in which case the value will be null.
|
||||
|
@ -1481,28 +1499,32 @@ export function textBinding<T>(index: number, value: T | NO_CHANGE): void {
|
|||
* @param directiveDef DirectiveDef object which contains information about the template.
|
||||
*/
|
||||
export function directiveCreate<T>(
|
||||
index: number, directive: T,
|
||||
directiveDefIdx: number, directive: T,
|
||||
directiveDef: DirectiveDefInternal<T>| ComponentDefInternal<T>): T {
|
||||
const instance = baseDirectiveCreate(index, directive, directiveDef);
|
||||
const instance = baseDirectiveCreate(directiveDefIdx, directive, directiveDef);
|
||||
|
||||
ngDevMode && assertDefined(previousOrParentNode.tNode, 'previousOrParentNode.tNode');
|
||||
const tNode = previousOrParentNode.tNode;
|
||||
|
||||
const isComponent = (directiveDef as ComponentDefInternal<T>).template;
|
||||
if (isComponent) {
|
||||
addComponentLogic(index, directive, directiveDef as ComponentDefInternal<T>);
|
||||
addComponentLogic(directiveDefIdx, directive, directiveDef as ComponentDefInternal<T>);
|
||||
}
|
||||
|
||||
if (firstTemplatePass) {
|
||||
// Init hooks are queued now so ngOnInit is called in host components before
|
||||
// any projected components.
|
||||
queueInitHooks(index, directiveDef.onInit, directiveDef.doCheck, tView);
|
||||
queueInitHooks(directiveDefIdx, directiveDef.onInit, directiveDef.doCheck, tView);
|
||||
|
||||
if (directiveDef.hostBindings) queueHostBindingForCheck(index);
|
||||
if (directiveDef.hostBindings) queueHostBindingForCheck(directiveDefIdx);
|
||||
}
|
||||
|
||||
if (tNode && tNode.attrs) {
|
||||
setInputsFromAttrs(index, instance, directiveDef.inputs, tNode);
|
||||
setInputsFromAttrs(directiveDefIdx, instance, directiveDef.inputs, tNode);
|
||||
}
|
||||
|
||||
if (directiveDef.contentQueries) {
|
||||
directiveDef.contentQueries();
|
||||
}
|
||||
|
||||
return instance;
|
||||
|
@ -1918,7 +1940,7 @@ export function componentRefresh<T>(directiveIndex: number, adjustedElementIndex
|
|||
// Only attached CheckAlways components or attached, dirty OnPush components should be checked
|
||||
if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) {
|
||||
ngDevMode && assertDataInRange(directiveIndex, directives !);
|
||||
detectChangesInternal(hostView, element, getDirectiveInstance(directives ![directiveIndex]));
|
||||
detectChangesInternal(hostView, element, directives ![directiveIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2537,6 +2559,15 @@ export function loadDirective<T>(index: number): T {
|
|||
return directives ![index];
|
||||
}
|
||||
|
||||
export function loadQueryList<T>(queryListIdx: number): QueryList<T> {
|
||||
ngDevMode && assertDefined(
|
||||
viewData[CONTENT_QUERIES],
|
||||
'Content QueryList array should be defined if reading a query.');
|
||||
ngDevMode && assertDataInRange(queryListIdx, viewData[CONTENT_QUERIES] !);
|
||||
|
||||
return viewData[CONTENT_QUERIES] ![queryListIdx];
|
||||
}
|
||||
|
||||
/** Gets the current binding value and increments the binding index. */
|
||||
export function consumeBinding(): any {
|
||||
ngDevMode && assertDataInRange(viewData[BINDING_INDEX]);
|
||||
|
@ -2586,10 +2617,22 @@ export function getTView(): TView {
|
|||
return tView;
|
||||
}
|
||||
|
||||
export function getDirectiveInstance<T>(instanceOrArray: T | [T]): T {
|
||||
// Directives with content queries store an array in directives[directiveIndex]
|
||||
// with the instance as the first index
|
||||
return Array.isArray(instanceOrArray) ? instanceOrArray[0] : instanceOrArray;
|
||||
/**
|
||||
* Registers a QueryList, associated with a content query, for later refresh (part of a view
|
||||
* refresh).
|
||||
*/
|
||||
export function registerContentQuery<Q>(queryList: QueryList<Q>): void {
|
||||
const savedContentQueriesLength =
|
||||
(viewData[CONTENT_QUERIES] || (viewData[CONTENT_QUERIES] = [])).push(queryList);
|
||||
if (firstTemplatePass) {
|
||||
const currentDirectiveIndex = directives !.length - 1;
|
||||
const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []);
|
||||
const lastSavedDirectiveIndex =
|
||||
tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 2] : -1;
|
||||
if (currentDirectiveIndex !== lastSavedDirectiveIndex) {
|
||||
tViewContentQueries.push(currentDirectiveIndex, savedContentQueriesLength - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function assertPreviousIsParent() {
|
||||
|
|
|
@ -122,6 +122,14 @@ export interface DirectiveDef<T, Selector extends string> {
|
|||
*/
|
||||
factory(): T|[T];
|
||||
|
||||
/**
|
||||
* Function to create instances of content queries associated with a given directive.
|
||||
*/
|
||||
contentQueries: (() => void)|null;
|
||||
|
||||
/** Refreshes content queries associated with directives in a given view */
|
||||
contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null;
|
||||
|
||||
/** Refreshes host bindings on the associated directive. */
|
||||
hostBindings: ((directiveIndex: number, elementIndex: number) => void)|null;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import {Injector} from '../../di/injector';
|
||||
import {QueryList} from '../../linker';
|
||||
import {Sanitizer} from '../../sanitization/security';
|
||||
|
||||
import {LContainer} from './container';
|
||||
|
@ -16,7 +17,7 @@ import {LQueries} from './query';
|
|||
import {Renderer3} from './renderer';
|
||||
|
||||
/** Size of LViewData's header. Necessary to adjust for it when setting slots. */
|
||||
export const HEADER_OFFSET = 15;
|
||||
export const HEADER_OFFSET = 16;
|
||||
|
||||
// Below are constants for LViewData indices to help us look up LViewData members
|
||||
// without having to remember the specific indices.
|
||||
|
@ -36,6 +37,7 @@ export const RENDERER = 11;
|
|||
export const SANITIZER = 12;
|
||||
export const TAIL = 13;
|
||||
export const CONTAINER_INDEX = 14;
|
||||
export const CONTENT_QUERIES = 15;
|
||||
|
||||
/**
|
||||
* `LViewData` stores all of the information needed to process the instructions as
|
||||
|
@ -153,6 +155,13 @@ export interface LViewData extends Array<any> {
|
|||
* in multiple containers, so the parent cannot be shared between view instances).
|
||||
*/
|
||||
[CONTAINER_INDEX]: number;
|
||||
|
||||
/**
|
||||
* Stores QueryLists associated with content queries of a directive. This data structure is
|
||||
* filled-in as part of a directive creation process and is later used to retrieve a QueryList to
|
||||
* be refreshed.
|
||||
*/
|
||||
[CONTENT_QUERIES]: QueryList<any>[]|null;
|
||||
}
|
||||
|
||||
/** Flags associated with an LView (saved in LViewData[FLAGS]) */
|
||||
|
@ -413,6 +422,15 @@ export interface TView {
|
|||
* they will be fed into instructions that expect the raw index (e.g. elementProperty)
|
||||
*/
|
||||
hostBindings: number[]|null;
|
||||
|
||||
|
||||
/**
|
||||
* A list of indices for child directives that have content queries.
|
||||
*
|
||||
* Even indices: Directive indices
|
||||
* Odd indices: Starting index of content queries (stored in CONTENT_QUERIES) for this directive
|
||||
*/
|
||||
contentQueries: number[]|null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -158,9 +158,6 @@
|
|||
{
|
||||
"name": "getChildLNode"
|
||||
},
|
||||
{
|
||||
"name": "getDirectiveInstance"
|
||||
},
|
||||
{
|
||||
"name": "getLViewChild"
|
||||
},
|
||||
|
@ -197,6 +194,9 @@
|
|||
{
|
||||
"name": "refreshChildComponents"
|
||||
},
|
||||
{
|
||||
"name": "refreshContentQueries"
|
||||
},
|
||||
{
|
||||
"name": "refreshDynamicEmbeddedViews"
|
||||
},
|
||||
|
|
|
@ -446,9 +446,6 @@
|
|||
{
|
||||
"name": "getCurrentSanitizer"
|
||||
},
|
||||
{
|
||||
"name": "getDirectiveInstance"
|
||||
},
|
||||
{
|
||||
"name": "getLViewChild"
|
||||
},
|
||||
|
@ -632,6 +629,9 @@
|
|||
{
|
||||
"name": "refreshChildComponents"
|
||||
},
|
||||
{
|
||||
"name": "refreshContentQueries"
|
||||
},
|
||||
{
|
||||
"name": "refreshDynamicEmbeddedViews"
|
||||
},
|
||||
|
|
|
@ -108,18 +108,17 @@ describe('queries', () => {
|
|||
static ngComponentDef = $r3$.ɵdefineComponent({
|
||||
type: ContentQueryComponent,
|
||||
selectors: [['content-query-component']],
|
||||
factory: function ContentQueryComponent_Factory() {
|
||||
return [
|
||||
new ContentQueryComponent(), $r3$.ɵQ(null, SomeDirective, false),
|
||||
$r3$.ɵQ(null, SomeDirective, false)
|
||||
];
|
||||
factory: function ContentQueryComponent_Factory() { return new ContentQueryComponent(); },
|
||||
contentQueries: function ContentQueryComponent_ContentQueries() {
|
||||
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, false));
|
||||
$r3$.ɵQr($r3$.ɵQ(null, SomeDirective, false));
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(
|
||||
dirIndex: $number$, elIndex: $number$) {
|
||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(
|
||||
dirIndex: $number$, queryStartIndex: $number$) {
|
||||
let $tmp$: any;
|
||||
const $instance$ = $r3$.ɵd<any[]>(dirIndex)[0];
|
||||
$r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[1]) && ($instance$.someDir = $tmp$.first);
|
||||
$r3$.ɵqR($tmp$ = $r3$.ɵd<any[]>(dirIndex)[2]) && ($instance$.someDirList = $tmp$);
|
||||
const $instance$ = $r3$.ɵd<ContentQueryComponent>(dirIndex);
|
||||
$r3$.ɵqR($tmp$ = $r3$.ɵql<any>(queryStartIndex)) && ($instance$.someDir = $tmp$.first);
|
||||
$r3$.ɵqR($tmp$ = $r3$.ɵql<any>(queryStartIndex + 1)) && ($instance$.someDirList = $tmp$);
|
||||
},
|
||||
template: function ContentQueryComponent_Template(
|
||||
rf: $number$, ctx: $ContentQueryComponent$) {
|
||||
|
@ -153,7 +152,7 @@ describe('queries', () => {
|
|||
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵE(0, 'content-query-component');
|
||||
contentQueryComp = $r3$.ɵd<any[]>(0)[0];
|
||||
contentQueryComp = $r3$.ɵd<ContentQueryComponent>(0);
|
||||
$r3$.ɵEe(1, 'div', $e2_attrs$);
|
||||
$r3$.ɵe();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
|
|||
import {EventEmitter} from '../..';
|
||||
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
|
||||
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges, injectViewContainerRef} from '../../src/render3/index';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
|
||||
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, loadQueryList, registerContentQuery} from '../../src/render3/instructions';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
import {query, queryRefresh} from '../../src/render3/query';
|
||||
|
||||
|
@ -1684,6 +1684,48 @@ describe('query', () => {
|
|||
|
||||
describe('content', () => {
|
||||
|
||||
it('should support content queries for directives', () => {
|
||||
let withContentInstance: WithContentDirective;
|
||||
|
||||
class WithContentDirective {
|
||||
// @ContentChildren('foo') foos;
|
||||
// TODO(issue/24571): remove '!'.
|
||||
foos !: QueryList<ElementRef>;
|
||||
|
||||
static ngComponentDef = defineDirective({
|
||||
type: WithContentDirective,
|
||||
selectors: [['', 'with-content', '']],
|
||||
factory: () => new WithContentDirective(),
|
||||
contentQueries:
|
||||
() => { registerContentQuery(query(null, ['foo'], true, QUERY_READ_FROM_NODE)); },
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
withContentInstance = loadDirective<WithContentDirective>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(withContentInstance.foos = tmp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <div with-content>
|
||||
* <span #foo></span>
|
||||
* </div>
|
||||
* class Cmpt {
|
||||
* }
|
||||
*/
|
||||
const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'div', [AttributeMarker.SelectOnly, 'with-content']);
|
||||
{ element(1, 'span', null, ['foo', '']); }
|
||||
elementEnd();
|
||||
}
|
||||
}, [WithContentDirective]);
|
||||
|
||||
const fixture = new ComponentFixture(AppComponent);
|
||||
expect(withContentInstance !.foos.length).toBe(1);
|
||||
});
|
||||
|
||||
// https://stackblitz.com/edit/angular-wlenwd?file=src%2Fapp%2Fapp.component.ts
|
||||
it('should support view and content queries matching the same element', () => {
|
||||
let withContentComponentInstance: WithContentComponent;
|
||||
|
@ -1696,18 +1738,17 @@ describe('query', () => {
|
|||
static ngComponentDef = defineComponent({
|
||||
type: WithContentComponent,
|
||||
selectors: [['with-content']],
|
||||
factory: () => {
|
||||
return [new WithContentComponent(), query(null, ['foo'], true, QUERY_READ_FROM_NODE)];
|
||||
},
|
||||
factory: () => new WithContentComponent(),
|
||||
contentQueries:
|
||||
() => { registerContentQuery(query(null, ['foo'], true, QUERY_READ_FROM_NODE)); },
|
||||
template: (rf: RenderFlags, ctx: WithContentComponent) => {
|
||||
// intentionally left empty, don't need anything for this test
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(
|
||||
dirIndex: number, elIndex: number) {
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
withContentComponentInstance = loadDirective<any[]>(dirIndex)[0];
|
||||
queryRefresh(tmp = loadDirective<any[]>(dirIndex)[1]) &&
|
||||
(withContentComponentInstance.foos = tmp as QueryList<any>);
|
||||
withContentComponentInstance = loadDirective<WithContentComponent>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(withContentComponentInstance.foos = tmp);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1760,19 +1801,17 @@ describe('query', () => {
|
|||
type: QueryDirective,
|
||||
selectors: [['', 'query', '']],
|
||||
exportAs: 'query',
|
||||
factory: () => {
|
||||
factory: () => new QueryDirective(),
|
||||
contentQueries: () => {
|
||||
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
|
||||
// QueryList<ElementRef>;
|
||||
return [
|
||||
new QueryDirective(), query(null, ['foo', 'bar', 'baz'], true, QUERY_READ_FROM_NODE)
|
||||
];
|
||||
registerContentQuery(query(null, ['foo', 'bar', 'baz'], true, QUERY_READ_FROM_NODE));
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(
|
||||
dirIndex: number, elIndex: number) {
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
const instance = loadDirective<any[]>(dirIndex)[0];
|
||||
queryRefresh(tmp = loadDirective<any[]>(dirIndex)[1]) &&
|
||||
(instance.fooBars = tmp as QueryList<any>);
|
||||
const instance = loadDirective<QueryDirective>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(instance.fooBars = tmp);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1804,8 +1843,8 @@ describe('query', () => {
|
|||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
outInstance = (<any>load(1))[0] as QueryDirective;
|
||||
inInstance = (<any>load(5))[0] as QueryDirective;
|
||||
outInstance = load<QueryDirective>(1);
|
||||
inInstance = load<QueryDirective>(5);
|
||||
}
|
||||
},
|
||||
[QueryDirective]);
|
||||
|
@ -1823,18 +1862,16 @@ describe('query', () => {
|
|||
type: ShallowQueryDirective,
|
||||
selectors: [['', 'shallow-query', '']],
|
||||
exportAs: 'shallow-query',
|
||||
factory: () => {
|
||||
// @ContentChildren('foo', {descendants: false}) fooBars: QueryList<ElementRef>;
|
||||
return [
|
||||
new ShallowQueryDirective(), query(null, ['foo'], false, QUERY_READ_FROM_NODE)
|
||||
];
|
||||
factory: () => new ShallowQueryDirective(),
|
||||
contentQueries: () => {
|
||||
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
||||
registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE));
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(
|
||||
dirIndex: number, elIndex: number) {
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
const instance = loadDirective<any[]>(dirIndex)[0];
|
||||
queryRefresh(tmp = loadDirective<any[]>(dirIndex)[1]) &&
|
||||
(instance.foos = tmp as QueryList<any>);
|
||||
const instance = loadDirective<ShallowQueryDirective>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(instance.foos = tmp);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1845,16 +1882,16 @@ describe('query', () => {
|
|||
type: DeepQueryDirective,
|
||||
selectors: [['', 'deep-query', '']],
|
||||
exportAs: 'deep-query',
|
||||
factory: () => {
|
||||
// @ContentChildren('foo', {descendants: true}) fooBars: QueryList<ElementRef>;
|
||||
return [new DeepQueryDirective(), query(null, ['foo'], true, QUERY_READ_FROM_NODE)];
|
||||
factory: () => new DeepQueryDirective(),
|
||||
contentQueries: () => {
|
||||
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
||||
registerContentQuery(query(null, ['foo'], true, QUERY_READ_FROM_NODE));
|
||||
},
|
||||
hostBindings: function ContentQueryComponent_HostBindings(
|
||||
dirIndex: number, elIndex: number) {
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
const instance = loadDirective<any[]>(dirIndex)[0];
|
||||
queryRefresh(tmp = loadDirective<any[]>(dirIndex)[1]) &&
|
||||
(instance.foos = tmp as QueryList<any>);
|
||||
const instance = loadDirective<DeepQueryDirective>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(instance.foos = tmp);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1878,8 +1915,8 @@ describe('query', () => {
|
|||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
shallowInstance = (<any>load(1))[0] as ShallowQueryDirective;
|
||||
deepInstance = (<any>load(2))[0] as DeepQueryDirective;
|
||||
shallowInstance = load<ShallowQueryDirective>(1);
|
||||
deepInstance = load<DeepQueryDirective>(2);
|
||||
}
|
||||
},
|
||||
[ShallowQueryDirective, DeepQueryDirective]);
|
||||
|
|
Loading…
Reference in New Issue