Skip to content

Commit

Permalink
feat(core): expose queries as signals (#54283)
Browse files Browse the repository at this point in the history
This commit exposes authoring functions for queries as signals
thus making those generally available.

PR Close #54283
  • Loading branch information
pkozlowski-opensource authored and thePunderWoman committed Feb 6, 2024
1 parent 0d4e983 commit e95ef2c
Show file tree
Hide file tree
Showing 20 changed files with 86 additions and 79 deletions.
5 changes: 0 additions & 5 deletions goldens/circular-deps/packages.json
Expand Up @@ -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"
Expand Down
61 changes: 61 additions & 0 deletions goldens/public-api/core/index.md
Expand Up @@ -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?: {
Expand All @@ -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?: {
Expand Down Expand Up @@ -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?: {
Expand All @@ -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?: {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/authoring.ts
Expand Up @@ -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';
49 changes: 1 addition & 48 deletions packages/core/src/authoring/queries.ts
Expand Up @@ -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';

Expand Down Expand Up @@ -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>;
Expand All @@ -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: {
Expand Down Expand Up @@ -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}):
Expand All @@ -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: {
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/core.ts
Expand Up @@ -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';
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/instructions/queries_signals.ts
Expand Up @@ -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';
Expand Down
Expand Up @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions packages/core/test/acceptance/query_signal_spec.ts
Expand Up @@ -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';

Expand Down
Expand Up @@ -240,7 +240,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -264,7 +264,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -168,7 +168,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
5 changes: 4 additions & 1 deletion packages/core/test/bundling/defer/bundle.golden_symbols.json
Expand Up @@ -198,7 +198,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down Expand Up @@ -1709,6 +1709,9 @@
{
"name": "init_queries"
},
{
"name": "init_queries2"
},
{
"name": "init_queries_signals"
},
Expand Down
Expand Up @@ -246,7 +246,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -231,7 +231,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -111,7 +111,7 @@
"name": "HelloWorldModule"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -195,7 +195,7 @@
"name": "HydrationFeatureKind"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -12,7 +12,7 @@
"name": "EnvironmentInjector"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -255,7 +255,7 @@
"name": "INITIAL_VALUE"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -150,7 +150,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down
Expand Up @@ -171,7 +171,7 @@
"name": "GenericBrowserDomAdapter"
},
{
"name": "INJECTOR2"
"name": "INJECTOR"
},
{
"name": "INJECTOR_DEF_TYPES"
Expand Down

0 comments on commit e95ef2c

Please sign in to comment.