From 14bcb51ae5af845367c657da6331600bec847b4c Mon Sep 17 00:00:00 2001 From: aminesbdev Date: Sun, 9 Aug 2026 13:09:57 +0200 Subject: [PATCH] docs: add view queries and content projection reference to developer skill --- skills/dev-skills/angular-developer/SKILL.md | 1 + .../references/queries-and-projection.md | 172 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 skills/dev-skills/angular-developer/references/queries-and-projection.md diff --git a/skills/dev-skills/angular-developer/SKILL.md b/skills/dev-skills/angular-developer/SKILL.md index 6ab0e3d77009..4c0314540153 100644 --- a/skills/dev-skills/angular-developer/SKILL.md +++ b/skills/dev-skills/angular-developer/SKILL.md @@ -49,6 +49,7 @@ When working with Angular components, consult the following references based on - **Inputs**: Signal-based inputs, transforms, and model inputs. Read [inputs.md](references/inputs.md) - **Outputs**: Signal-based outputs and custom event best practices. Read [outputs.md](references/outputs.md) - **Host Elements**: Host bindings and attribute injection. Read [host-elements.md](references/host-elements.md) +- **View Queries and Content Projection**: Signal-based queries (viewChild, contentChild) and content projection with fallback content. Read [queries-and-projection.md](references/queries-and-projection.md) If you require deeper documentation not found in the references above, read the documentation at `https://angular.dev/guide/components`. diff --git a/skills/dev-skills/angular-developer/references/queries-and-projection.md b/skills/dev-skills/angular-developer/references/queries-and-projection.md new file mode 100644 index 000000000000..6a69ea5169f0 --- /dev/null +++ b/skills/dev-skills/angular-developer/references/queries-and-projection.md @@ -0,0 +1,172 @@ +# View Queries and Content Projection + +View queries and content projection allow components to access, interact with, and dynamically insert nested elements or components in their views. + +## View Queries (`viewChild`, `viewChildren`) + +Use signal-based queries to access child elements or components in the component's own template. Signal queries are reactive, readonly signals that automatically update when the DOM changes. + +### Querying a Single Element or Component (`viewChild`) + +Use `viewChild` to find the first matching child. + +```ts +import {Component, ElementRef, viewChild} from '@angular/core'; + +@Component({ + selector: 'app-custom-input', + template: ` + + `, +}) +export class CustomInput { + // Query by template reference variable + readonly inputEl = viewChild>('inputField'); + + focusInput() { + // The signal value might be undefined if queried before the view is initialized + this.inputEl()?.nativeElement.focus(); + } +} +``` + +- **Required Queries**: Use `viewChild.required` if you expect the child to always be present. It returns a signal that directly throws an error if read before it is available or if it is missing. + ```ts + readonly inputEl = viewChild.required>('inputField'); + ``` +- **Querying Components**: You can query by component class name. + ```ts + readonly childComponent = viewChild(ChildComponent); + ``` + +### Querying Multiple Elements or Components (`viewChildren`) + +Use `viewChildren` to query all matching items. It returns a signal containing a read-only array of matches. + +```ts +import {Component, viewChildren} from '@angular/core'; +import {TabComponent} from './tab.component'; + +@Component({ + selector: 'app-tab-group', + template: ` + Content 1 + Content 2 + `, +}) +export class TabGroup { + readonly tabs = viewChildren(TabComponent); + + ngAfterViewInit() { + console.log(`Number of tabs: ${this.tabs().length}`); + } +} +``` + +### Query Options + +You can pass an options object to configure the query: +- `read`: Read a different token from the matched element (e.g. `ElementRef` or a specific directive instance). + ```ts + readonly child = viewChild(ChildComponent, {read: ElementRef}); + ``` + +--- + +## Content Queries (`contentChild`, `contentChildren`) + +Use content queries to access elements or components that are projected into the component's template via ``. + +```ts +import {Component, contentChild, ElementRef} from '@angular/core'; + +@Component({ + selector: 'app-card', + template: ` +
+ +
+ `, +}) +export class Card { + // Query projected element with template ref '#cardHeader' + readonly header = contentChild('cardHeader'); +} +``` + +- Content queries resolve during content initialization, before view queries. +- Like view queries, you can use `.required` and configuration options like `read`. + +--- + +## Content Projection + +Content projection allows you to insert HTML or component templates from a parent component into a child component. + +### Single-slot Projection + +Use a plain `` tag to project all children into a single location. + +```html + + +``` + +Usage: +```html +Click Me! +``` + +### Multi-slot Projection + +Use the `select` attribute on `` to target specific elements based on CSS selectors (attributes, classes, or element names). + +```html + +
+ +
+
+ +
+
+ +
+``` + +Usage: +```html + + My Website Header +

Main content goes here.

+
Copyright Info
+
+``` + +### Fallback/Default Content + +Since **Angular 18**, you can provide default fallback content inside `` that will render if no content matches the slot. + +```html + +
+
+ Default Title +
+
+ +
+
+``` + +--- + +## Recommended Patterns + +- **Prefer Signal-based Queries**: Use `viewChild`, `viewChildren`, `contentChild`, and `contentChildren` instead of legacy decorators (`@ViewChild`, `@ViewChildren`, `@ContentChild`, `@ContentChildren`). +- **Reactive Derivations**: Since signal queries return signals, you can compose them inside `computed` or monitor them in `effect` blocks without needing lifecycle hooks like `ngAfterViewInit`. +- **Use `.required` for Safe Reads**: Prefer `.required` when the element is guaranteed to be in the template, eliminating type checks for `undefined`. +- **Prefer Host Property for Element Access**: If you only need to modify attributes/styles/classes on the component's host element itself, use the `host` property in `@Component` metadata instead of querying the host element via `ElementRef`. +- **Avoid Direct DOM Manipulation**: Always prefer binding data reactively or using Angular APIs rather than directly manipulating element DOM properties via `nativeElement`.