diff --git a/adev/src/content/reference/errors/NG0951.md b/adev/src/content/reference/errors/NG0951.md new file mode 100644 index 00000000000..ff94b45c860 --- /dev/null +++ b/adev/src/content/reference/errors/NG0951.md @@ -0,0 +1,23 @@ +@name Child query result is required but no value is available. +@category runtime +@shortDescription Required child query result was accessed before query results were calculated or query has no matches. + +@description +Required child query (`contentChild.required` or `viewChild.required`) result was accessed before query results were calculated or query has no matches. + +This can happen in two distinct situations: +* query results were accessed before a given query could collect results; +* a query was executed but didn't match any nodes and has no results as a consequence. + +Content queries and view queries each calculate their results at different points in time: +* `contentChild` results are available after a _host_ view (template where a directive declaring a query is used) is created; +* `viewChild` results are available after a template of a component declaring a query is created. + +Accessing query results before they're available results in the error described on this page. Most notably, query results are _never_ available in a constructor of the component or directive declaring a query. + +## Fixing the error + +`contentChild` query results can be accessed in the `AfterContentChecked` lifecycle hook, or later. +`viewChild` query results can be accessed in the `AfterViewChecked` lifecycle hook, or later. + +Make sure that a required query matches at least one node and has results at all. You can verify this by accessing query results in the lifecycle hooks listed above. diff --git a/aio/content/errors/NG0951.md b/aio/content/errors/NG0951.md new file mode 100644 index 00000000000..ff94b45c860 --- /dev/null +++ b/aio/content/errors/NG0951.md @@ -0,0 +1,23 @@ +@name Child query result is required but no value is available. +@category runtime +@shortDescription Required child query result was accessed before query results were calculated or query has no matches. + +@description +Required child query (`contentChild.required` or `viewChild.required`) result was accessed before query results were calculated or query has no matches. + +This can happen in two distinct situations: +* query results were accessed before a given query could collect results; +* a query was executed but didn't match any nodes and has no results as a consequence. + +Content queries and view queries each calculate their results at different points in time: +* `contentChild` results are available after a _host_ view (template where a directive declaring a query is used) is created; +* `viewChild` results are available after a template of a component declaring a query is created. + +Accessing query results before they're available results in the error described on this page. Most notably, query results are _never_ available in a constructor of the component or directive declaring a query. + +## Fixing the error + +`contentChild` query results can be accessed in the `AfterContentChecked` lifecycle hook, or later. +`viewChild` query results can be accessed in the `AfterViewChecked` lifecycle hook, or later. + +Make sure that a required query matches at least one node and has results at all. You can verify this by accessing query results in the lifecycle hooks listed above. diff --git a/goldens/public-api/core/errors.md b/goldens/public-api/core/errors.md index 3e8e0b5d055..b1f8a40e7ef 100644 --- a/goldens/public-api/core/errors.md +++ b/goldens/public-api/core/errors.md @@ -123,6 +123,8 @@ export const enum RuntimeErrorCode { // (undocumented) REQUIRED_INPUT_NO_VALUE = -950, // (undocumented) + REQUIRED_QUERY_NO_VALUE = -951, + // (undocumented) RUNTIME_DEPS_INVALID_IMPORTED_TYPE = 1000, // (undocumented) RUNTIME_DEPS_ORPHAN_COMPONENT = 1001, diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 9a02a4881e1..c4f4b8eda5e 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -116,8 +116,9 @@ export const enum RuntimeErrorCode { COMPONENT_ID_COLLISION = -912, IMAGE_PERFORMANCE_WARNING = -913, - // Signal inputs + // Signal integration errors REQUIRED_INPUT_NO_VALUE = -950, + REQUIRED_QUERY_NO_VALUE = -951, // Runtime dependency tracker errors RUNTIME_DEPS_INVALID_IMPORTED_TYPE = 1000, diff --git a/packages/core/src/render3/query_reactive.ts b/packages/core/src/render3/query_reactive.ts index 7fb9e1d5306..059e97a3e3e 100644 --- a/packages/core/src/render3/query_reactive.ts +++ b/packages/core/src/render3/query_reactive.ts @@ -8,7 +8,7 @@ import {ComputedNode, createComputed, SIGNAL} from '@angular/core/primitives/signals'; -import {RuntimeError} from '../errors'; +import {RuntimeError, RuntimeErrorCode} from '../errors'; import {unwrapElementRef} from '../linker/element_ref'; import {QueryList} from '../linker/query_list'; import {EMPTY_ARRAY} from '../util/empty'; @@ -48,9 +48,10 @@ function createQuerySignalFn(firstOnly: boolean, required: boolean) { const value = refreshSignalQuery(node, firstOnly); - if (value === undefined && required) { - // TODO: add error code add proper message - throw new RuntimeError(0, 'no query results yet!'); + if (required && value === undefined) { + throw new RuntimeError( + RuntimeErrorCode.REQUIRED_QUERY_NO_VALUE, + ngDevMode && 'Child query result is required but no value is available.'); } return value; diff --git a/packages/core/test/acceptance/query_signal_spec.ts b/packages/core/test/acceptance/query_signal_spec.ts index 74f16428261..ba078f85c8f 100644 --- a/packages/core/test/acceptance/query_signal_spec.ts +++ b/packages/core/test/acceptance/query_signal_spec.ts @@ -66,7 +66,7 @@ describe('queries as signals', () => { const appCmpt = new AppComponent(); expect(() => { appCmpt.divEl(); - }).toThrowError('NG00: no query results yet!'); + }).toThrowError(/NG0951: Child query result is required but no value is available/); }); it('should query for multiple elements in a template', () => {