mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
feat(core): expose queries as signals (#54283)
This commit exposes authoring functions for queries as signals thus making those generally available. PR Close #54283
This commit is contained in:
parent
0d4e983c24
commit
e95ef2cbc6
20 changed files with 86 additions and 79 deletions
|
|
@ -20,11 +20,6 @@
|
|||
"packages/core/src/change_detection/change_detector_ref.ts",
|
||||
"packages/core/src/render3/view_ref.ts"
|
||||
],
|
||||
[
|
||||
"packages/core/src/change_detection/change_detector_ref.ts",
|
||||
"packages/core/src/render3/view_ref.ts",
|
||||
"packages/core/src/linker/view_ref.ts"
|
||||
],
|
||||
[
|
||||
"packages/core/src/change_detection/differs/default_iterable_differ.ts",
|
||||
"packages/core/src/change_detection/differs/iterable_differs.ts"
|
||||
|
|
|
|||
|
|
@ -322,6 +322,9 @@ export type ContentChild = Query;
|
|||
// @public
|
||||
export const ContentChild: ContentChildDecorator;
|
||||
|
||||
// @public
|
||||
export const contentChild: ContentChildFunction;
|
||||
|
||||
// @public
|
||||
export interface ContentChildDecorator {
|
||||
(selector: ProviderToken<unknown> | Function | string, opts?: {
|
||||
|
|
@ -337,12 +340,44 @@ export interface ContentChildDecorator {
|
|||
}): ContentChild;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface ContentChildFunction {
|
||||
<LocatorT>(locator: ProviderToken<LocatorT> | string, opts?: {
|
||||
descendants?: boolean;
|
||||
}): Signal<LocatorT | undefined>;
|
||||
// (undocumented)
|
||||
<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
descendants?: boolean;
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadT | undefined>;
|
||||
required: {
|
||||
<LocatorT>(locator: ProviderToken<LocatorT> | string, opts?: {
|
||||
descendants?: boolean;
|
||||
}): Signal<LocatorT>;
|
||||
<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
descendants?: boolean;
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadT>;
|
||||
};
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ContentChildren = Query;
|
||||
|
||||
// @public
|
||||
export const ContentChildren: ContentChildrenDecorator;
|
||||
|
||||
// @public (undocumented)
|
||||
export function contentChildren<LocatorT>(locator: ProviderToken<LocatorT> | string, opts?: {
|
||||
descendants?: boolean;
|
||||
}): Signal<ReadonlyArray<LocatorT>>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function contentChildren<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
descendants?: boolean;
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadonlyArray<ReadT>>;
|
||||
|
||||
// @public
|
||||
export interface ContentChildrenDecorator {
|
||||
(selector: ProviderToken<unknown> | Function | string, opts?: {
|
||||
|
|
@ -1598,6 +1633,9 @@ export type ViewChild = Query;
|
|||
// @public
|
||||
export const ViewChild: ViewChildDecorator;
|
||||
|
||||
// @public
|
||||
export const viewChild: ViewChildFunction;
|
||||
|
||||
// @public
|
||||
export interface ViewChildDecorator {
|
||||
(selector: ProviderToken<unknown> | Function | string, opts?: {
|
||||
|
|
@ -1611,12 +1649,35 @@ export interface ViewChildDecorator {
|
|||
}): ViewChild;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface ViewChildFunction {
|
||||
<LocatorT>(locator: ProviderToken<LocatorT> | string): Signal<LocatorT | undefined>;
|
||||
// (undocumented)
|
||||
<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadT | undefined>;
|
||||
required: {
|
||||
<LocatorT>(locator: ProviderToken<LocatorT> | string): Signal<LocatorT>;
|
||||
<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadT>;
|
||||
};
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ViewChildren = Query;
|
||||
|
||||
// @public
|
||||
export const ViewChildren: ViewChildrenDecorator;
|
||||
|
||||
// @public (undocumented)
|
||||
export function viewChildren<LocatorT>(locator: ProviderToken<LocatorT> | string): Signal<ReadonlyArray<LocatorT>>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function viewChildren<LocatorT, ReadT>(locator: ProviderToken<LocatorT> | string, opts: {
|
||||
read: ProviderToken<ReadT>;
|
||||
}): Signal<ReadonlyArray<ReadT>>;
|
||||
|
||||
// @public
|
||||
export interface ViewChildrenDecorator {
|
||||
(selector: ProviderToken<unknown> | Function | string, opts?: {
|
||||
|
|
|
|||
|
|
@ -13,3 +13,4 @@ export {InputFunction} from './authoring/input/input';
|
|||
export {InputOptions, InputOptionsWithoutTransform, InputOptionsWithTransform, InputSignal, InputSignalWithTransform, ɵINPUT_SIGNAL_BRAND_WRITE_TYPE} from './authoring/input/input_signal';
|
||||
export {ɵUnwrapDirectiveSignalInputs} from './authoring/input/input_type_checking';
|
||||
export {output as ɵoutput, OutputEmitter as ɵOutputEmitter, OutputOptions as ɵOutputOptions} from './authoring/output';
|
||||
export {ContentChildFunction, ViewChildFunction} from './authoring/queries';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ProviderToken} from '../di';
|
||||
import {ProviderToken} from '../di/provider_token';
|
||||
import {createMultiResultQuerySignalFn, createSingleResultOptionalQuerySignalFn, createSingleResultRequiredQuerySignalFn} from '../render3/query_reactive';
|
||||
import {Signal} from '../render3/reactivity/api';
|
||||
|
||||
|
|
@ -34,18 +34,6 @@ export interface ViewChildFunction {
|
|||
* Initializes a view child query. Consider using `viewChild.required` for queries that should
|
||||
* always match.
|
||||
*
|
||||
* @usageNotes
|
||||
* Create a child query in your component by declaring a
|
||||
* class field and initializing it with the `viewChild()` function.
|
||||
*
|
||||
* ```ts
|
||||
* @Component({template: '<div #el></div><my-component #cmp />'})
|
||||
* export class TestComponent {
|
||||
* divEl = viewChild<ElementRef>('el'); // Signal<ElementRef|undefined>
|
||||
* cmp = viewChild(MyComponent); // Signal<MyComponent|undefined>
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @developerPreview
|
||||
*/
|
||||
<LocatorT>(locator: ProviderToken<LocatorT>|string): Signal<LocatorT|undefined>;
|
||||
|
|
@ -55,18 +43,6 @@ export interface ViewChildFunction {
|
|||
/**
|
||||
* Initializes a view child query that is expected to always match an element.
|
||||
*
|
||||
* @usageNotes
|
||||
* Create a required child query in your component by declaring a
|
||||
* class field and initializing it with the `viewChild()` function.
|
||||
*
|
||||
* ```ts
|
||||
* @Component({template: '<div #el></div><my-component #cmp />'})
|
||||
* export class TestComponent {
|
||||
* divElRequired = viewChild.required<ElementRef>('el'); // Signal<ElementRef>
|
||||
* cmpRequired = viewChild.required(MyComponent); // Signal<MyComponent>
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @developerPreview
|
||||
*/
|
||||
required: {
|
||||
|
|
@ -160,18 +136,6 @@ export interface ContentChildFunction {
|
|||
* Initializes a content child query.
|
||||
*
|
||||
* Consider using `contentChild.required` for queries that should always match.
|
||||
*
|
||||
* @usageNotes
|
||||
* Create a child query in your component by declaring a
|
||||
* class field and initializing it with the `contentChild()` function.
|
||||
*
|
||||
* ```ts
|
||||
* @Component({...})
|
||||
* export class TestComponent {
|
||||
* headerEl = contentChild<ElementRef>('h'); // Signal<ElementRef|undefined>
|
||||
* header = contentChild(MyHeader); // Signal<MyHeader|undefined>
|
||||
* }
|
||||
* ```
|
||||
* @developerPreview
|
||||
*/
|
||||
<LocatorT>(locator: ProviderToken<LocatorT>|string, opts?: {descendants?: boolean}):
|
||||
|
|
@ -183,17 +147,6 @@ export interface ContentChildFunction {
|
|||
/**
|
||||
* Initializes a content child query that is always expected to match.
|
||||
*
|
||||
* @usageNotes
|
||||
* Create a child query in your component by declaring a
|
||||
* class field and initializing it with the `contentChild()` function.
|
||||
*
|
||||
* ```ts
|
||||
* @Component({...})
|
||||
* export class TestComponent {
|
||||
* headerElElRequired = contentChild.required<ElementRef>('h'); // Signal<ElementRef>
|
||||
* headerRequired = contentChild.required(MyHeader); // Signal<MyHeader>
|
||||
* }
|
||||
* ```
|
||||
* @developerPreview
|
||||
*/
|
||||
required: {
|
||||
|
|
|
|||
|
|
@ -13,10 +13,11 @@
|
|||
*/
|
||||
|
||||
export * from './authoring';
|
||||
// Input is exported separately as this file is exempted from JSCompiler's
|
||||
// conformance requirement for inferred const exports.
|
||||
// See: https://docs.google.com/document/d/1RXb1wYwsbJotO1KBgSDsAtKpduGmIHod9ADxuXcAvV4/edit?tab=t.0
|
||||
// Input and query authoring functions are exported separately as this file is exempted from
|
||||
// JSCompiler's conformance requirement for inferred const exports. See:
|
||||
// https://docs.google.com/document/d/1RXb1wYwsbJotO1KBgSDsAtKpduGmIHod9ADxuXcAvV4/edit?tab=t.0
|
||||
export {input} from './authoring/input/input';
|
||||
export {contentChild, contentChildren, viewChild, viewChildren} from './authoring/queries';
|
||||
|
||||
export * from './metadata';
|
||||
export * from './version';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {ProviderToken} from '../../di';
|
||||
import {ProviderToken} from '../../di/provider_token';
|
||||
import {QueryFlags} from '../interfaces/query';
|
||||
import {createContentQuery, createViewQuery} from '../query';
|
||||
import {bindQueryToSignal} from '../query_reactive';
|
||||
|
|
|
|||
|
|
@ -6,17 +6,12 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// TODO: update imports
|
||||
import {Component, computed} from '@angular/core';
|
||||
import {viewChild} from '@angular/core/src/authoring/queries';
|
||||
import {getComponentDef} from '@angular/core/src/render3/definition';
|
||||
import {Component, computed, viewChild} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
describe('queries as signals', () => {
|
||||
describe('view', () => {
|
||||
// TODO: Enable when `viewChild` is exposed publicly. Right now, compiler will
|
||||
// not detect `viewChild` as it does not originate from a `@angular/core` import.
|
||||
xit('view child', () => {
|
||||
it('view child', () => {
|
||||
@Component({
|
||||
selector: 'test-cmp',
|
||||
standalone: true,
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@
|
|||
*/
|
||||
|
||||
|
||||
import {Component, computed, ContentChild, ContentChildren, Directive, ElementRef, ViewChild, ViewChildren} from '@angular/core';
|
||||
// TODO: update imports to the exported authoring functions when those are public
|
||||
import {contentChild, contentChildren, viewChild, viewChildren} from '@angular/core/src/authoring/queries';
|
||||
import {Component, computed, ContentChild, contentChild, ContentChildren, contentChildren, Directive, ElementRef, ViewChild, viewChild, ViewChildren, viewChildren} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
@ -1709,6 +1709,9 @@
|
|||
{
|
||||
"name": "init_queries"
|
||||
},
|
||||
{
|
||||
"name": "init_queries2"
|
||||
},
|
||||
{
|
||||
"name": "init_queries_signals"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
"name": "HelloWorldModule"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@
|
|||
"name": "HydrationFeatureKind"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"name": "EnvironmentInjector"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@
|
|||
"name": "INITIAL_VALUE"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@
|
|||
"name": "GenericBrowserDomAdapter"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR2"
|
||||
"name": "INJECTOR"
|
||||
},
|
||||
{
|
||||
"name": "INJECTOR_DEF_TYPES"
|
||||
|
|
|
|||
Loading…
Reference in a new issue