fix(ivy): support static ContentChild queries (#28811)
This commit adds support for the `static: true` flag in `ContentChild` queries. Prior to this commit, all `ContentChild` queries were resolved after change detection ran. This is a problem for backwards compatibility because View Engine also supported "static" queries which would resolve before change detection. Now if users add a `static: true` option, the query will be resolved in creation mode (before change detection runs). For example: ```ts @ContentChild(TemplateRef, {static: true}) template !: TemplateRef; ``` This feature will come in handy for components that need to create components dynamically. PR Close #28811
This commit is contained in:

committed by
Igor Minar

parent
a4638d5a81
commit
3c1a1620e3
@ -82,6 +82,7 @@ export {
|
||||
queryRefresh as ɵqueryRefresh,
|
||||
viewQuery as ɵviewQuery,
|
||||
staticViewQuery as ɵstaticViewQuery,
|
||||
staticContentQuery as ɵstaticContentQuery,
|
||||
loadViewQuery as ɵloadViewQuery,
|
||||
contentQuery as ɵcontentQuery,
|
||||
loadContentQuery as ɵloadContentQuery,
|
||||
|
@ -128,6 +128,7 @@ export {
|
||||
loadViewQuery,
|
||||
contentQuery,
|
||||
loadContentQuery,
|
||||
staticContentQuery
|
||||
} from './query';
|
||||
|
||||
export {
|
||||
|
@ -65,6 +65,8 @@ const enum BindingDirection {
|
||||
*/
|
||||
export function refreshDescendantViews(lView: LView) {
|
||||
const tView = lView[TVIEW];
|
||||
const creationMode = isCreationMode(lView);
|
||||
|
||||
// This needs to be set before children are processed to support recursive components
|
||||
tView.firstTemplatePass = false;
|
||||
|
||||
@ -73,7 +75,7 @@ export function refreshDescendantViews(lView: LView) {
|
||||
|
||||
// If this is a creation pass, we should not call lifecycle hooks or evaluate bindings.
|
||||
// This will be done in the update pass.
|
||||
if (!isCreationMode(lView)) {
|
||||
if (!creationMode) {
|
||||
const checkNoChangesMode = getCheckNoChangesMode();
|
||||
|
||||
executeInitHooks(lView, tView, checkNoChangesMode);
|
||||
@ -90,6 +92,13 @@ export function refreshDescendantViews(lView: LView) {
|
||||
setHostBindings(tView, lView);
|
||||
}
|
||||
|
||||
// We resolve content queries specifically marked as `static` in creation mode. Dynamic
|
||||
// content queries are resolved during change detection (i.e. update mode), after embedded
|
||||
// views are refreshed (see block above).
|
||||
if (creationMode && tView.staticContentQueries) {
|
||||
refreshContentQueries(tView, lView);
|
||||
}
|
||||
|
||||
refreshChildComponents(tView.components);
|
||||
}
|
||||
|
||||
@ -785,6 +794,7 @@ export function createTView(
|
||||
expandoInstructions: null,
|
||||
firstTemplatePass: true,
|
||||
staticViewQueries: false,
|
||||
staticContentQueries: false,
|
||||
initHooks: null,
|
||||
checkHooks: null,
|
||||
contentHooks: null,
|
||||
|
@ -384,6 +384,14 @@ export interface TView {
|
||||
*/
|
||||
staticViewQueries: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not there are any static content queries tracked on this view.
|
||||
*
|
||||
* We store this so we know whether or not we should do a content query
|
||||
* refresh after creation mode to collect static query results.
|
||||
*/
|
||||
staticContentQueries: boolean;
|
||||
|
||||
/**
|
||||
* The index where the viewQueries section of `LView` begins. This section contains
|
||||
* view queries defined for a component/directive.
|
||||
|
@ -89,6 +89,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||
'ɵqueryRefresh': r3.queryRefresh,
|
||||
'ɵviewQuery': r3.viewQuery,
|
||||
'ɵstaticViewQuery': r3.staticViewQuery,
|
||||
'ɵstaticContentQuery': r3.staticContentQuery,
|
||||
'ɵloadViewQuery': r3.loadViewQuery,
|
||||
'ɵcontentQuery': r3.contentQuery,
|
||||
'ɵloadContentQuery': r3.loadContentQuery,
|
||||
|
@ -442,7 +442,7 @@ export function loadViewQuery<T>(): T {
|
||||
*/
|
||||
export function contentQuery<T>(
|
||||
directiveIndex: number, predicate: Type<any>| string[], descend: boolean,
|
||||
// TODO: "read" should be an AbstractType (FW-486)
|
||||
// TODO(FW-486): "read" should be an AbstractType
|
||||
read: any): QueryList<T> {
|
||||
const lView = getLView();
|
||||
const tView = lView[TVIEW];
|
||||
@ -459,6 +459,28 @@ export function contentQuery<T>(
|
||||
return contentQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a QueryList, associated with a static content query, for later refresh
|
||||
* (part of a view refresh).
|
||||
*
|
||||
* @param directiveIndex Current directive index
|
||||
* @param predicate The type for which the query will search
|
||||
* @param descend Whether or not to descend into children
|
||||
* @param read What to save in the query
|
||||
* @returns QueryList<T>
|
||||
*/
|
||||
export function staticContentQuery<T>(
|
||||
directiveIndex: number, predicate: Type<any>| string[], descend: boolean,
|
||||
// TODO(FW-486): "read" should be an AbstractType
|
||||
read: any): void {
|
||||
const queryList = contentQuery(directiveIndex, predicate, descend, read) as QueryList_<T>;
|
||||
const tView = getLView()[TVIEW];
|
||||
queryList._static = true;
|
||||
if (!tView.staticContentQueries) {
|
||||
tView.staticContentQueries = true;
|
||||
}
|
||||
}
|
||||
|
||||
export function loadContentQuery<T>(): QueryList<T> {
|
||||
const lView = getLView();
|
||||
ngDevMode &&
|
||||
|
Reference in New Issue
Block a user