@anglr/select 17.2.0 → 18.0.0-beta.20260805050455
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/angular-developer/SKILL.md +130 -130
- package/.claude/skills/angular-developer/references/angular-animations.md +160 -160
- package/.claude/skills/angular-developer/references/angular-aria.md +410 -410
- package/.claude/skills/angular-developer/references/cli.md +86 -86
- package/.claude/skills/angular-developer/references/component-harnesses.md +59 -59
- package/.claude/skills/angular-developer/references/component-styling.md +91 -91
- package/.claude/skills/angular-developer/references/components.md +117 -117
- package/.claude/skills/angular-developer/references/creating-services.md +97 -97
- package/.claude/skills/angular-developer/references/data-resolvers.md +69 -69
- package/.claude/skills/angular-developer/references/define-routes.md +67 -67
- package/.claude/skills/angular-developer/references/defining-providers.md +72 -72
- package/.claude/skills/angular-developer/references/di-fundamentals.md +120 -120
- package/.claude/skills/angular-developer/references/e2e-testing.md +66 -66
- package/.claude/skills/angular-developer/references/effects.md +83 -83
- package/.claude/skills/angular-developer/references/hierarchical-injectors.md +43 -43
- package/.claude/skills/angular-developer/references/host-elements.md +80 -80
- package/.claude/skills/angular-developer/references/injection-context.md +63 -63
- package/.claude/skills/angular-developer/references/inputs.md +101 -101
- package/.claude/skills/angular-developer/references/linked-signal.md +59 -59
- package/.claude/skills/angular-developer/references/loading-strategies.md +61 -61
- package/.claude/skills/angular-developer/references/mcp.md +106 -106
- package/.claude/skills/angular-developer/references/migrations.md +30 -30
- package/.claude/skills/angular-developer/references/navigate-to-routes.md +69 -69
- package/.claude/skills/angular-developer/references/outputs.md +86 -86
- package/.claude/skills/angular-developer/references/reactive-forms.md +122 -122
- package/.claude/skills/angular-developer/references/rendering-strategies.md +44 -44
- package/.claude/skills/angular-developer/references/resource.md +77 -77
- package/.claude/skills/angular-developer/references/route-animations.md +56 -56
- package/.claude/skills/angular-developer/references/route-guards.md +52 -52
- package/.claude/skills/angular-developer/references/router-lifecycle.md +45 -45
- package/.claude/skills/angular-developer/references/router-testing.md +87 -87
- package/.claude/skills/angular-developer/references/show-routes-with-outlets.md +68 -68
- package/.claude/skills/angular-developer/references/signal-forms.md +897 -897
- package/.claude/skills/angular-developer/references/signals-overview.md +94 -94
- package/.claude/skills/angular-developer/references/tailwind-css.md +69 -69
- package/.claude/skills/angular-developer/references/template-driven-forms.md +114 -114
- package/.claude/skills/angular-developer/references/testing-fundamentals.md +66 -66
- package/.github/instructions/typescript/code-conventions.md +7 -7
- package/.github/instructions/typescript/comments.md +40 -40
- package/.github/instructions/typescript/formatting.md +41 -41
- package/.github/instructions/typescript/naming-conventions.md +6 -6
- package/es2022/extensions/src/extensions/getSearch.js.map +1 -1
- package/es2022/extensions/src/extensions/getSelectedOption.js.map +1 -1
- package/es2022/extensions/src/extensions/getSelectedOptions.js.map +1 -1
- package/es2022/extensions/src/extensions/getValue.js.map +1 -1
- package/es2022/extensions/src/extensions/setReadonly.js.map +1 -1
- package/es2022/extensions/src/extensions/setValue.js.map +1 -1
- package/es2022/extensions/src/index.js.map +1 -1
- package/es2022/src/components/index.js.map +1 -1
- package/es2022/src/components/option/option.component.js.map +1 -1
- package/es2022/src/components/optionGroup/optgroup.component.js.map +1 -1
- package/es2022/src/components/select/select.component.js +2 -2
- package/es2022/src/components/select/select.component.js.map +1 -1
- package/es2022/src/decorators/index.js.map +1 -1
- package/es2022/src/decorators/mergeOptionsAsSignal/mergeOptionsAsSignal.decorator.js.map +1 -1
- package/es2022/src/directives/highlightInstance/highlightInstance.directive.js.map +1 -1
- package/es2022/src/directives/highlightSearch/highlightSearch.directive.js.map +1 -1
- package/es2022/src/directives/highlightText/highlightText.directive.js.map +1 -1
- package/es2022/src/directives/index.js.map +1 -1
- package/es2022/src/directives/normalStateTagTemplate/normalStateTagTemplate.directive.js.map +1 -1
- package/es2022/src/directives/normalStateTemplate/normalStateTemplate.directive.js.map +1 -1
- package/es2022/src/directives/optionGroupTemplate/optionGroupTemplate.directive.js.map +1 -1
- package/es2022/src/directives/optionTemplate/optionTemplate.directive.js.map +1 -1
- package/es2022/src/directives/selectAbsolute/selectAbsolute.directive.js.map +1 -1
- package/es2022/src/directives/selectControlValueAccessor/selectControlValueAccessor.directive.js.map +1 -1
- package/es2022/src/directives/selectEdit/selectEdit.directive.js.map +1 -1
- package/es2022/src/directives/selectFormControl/selectFormControl.directive.js.map +1 -1
- package/es2022/src/directives/selectMultipleKeepPopup/selectMultipleKeepPopup.directive.js.map +1 -1
- package/es2022/src/directives/selectNoCarret/selectNoCarret.directive.js.map +1 -1
- package/es2022/src/directives/selectPlaceholder/selectPlaceholder.directive.js.map +1 -1
- package/es2022/src/directives/withDirectAccess/withDirectAccess.directive.js.map +1 -1
- package/es2022/src/index.js.map +1 -1
- package/es2022/src/interfaces/index.js.map +1 -1
- package/es2022/src/interfaces/initState/initState.interface.js.map +1 -1
- package/es2022/src/interfaces/keyboardAction/keyboardAction.interface.js.map +1 -1
- package/es2022/src/interfaces/normalStateContext/normalStateContext.interface.js.map +1 -1
- package/es2022/src/interfaces/normalStateTagContext/normalStateTagContext.interface.js.map +1 -1
- package/es2022/src/interfaces/optionsGatherer/optionsGatherer.interface.js.map +1 -1
- package/es2022/src/interfaces/pluginDescription/pluginDescription.interface.js.map +1 -1
- package/es2022/src/interfaces/pluginOptions/pluginOptions.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/index.js.map +1 -1
- package/es2022/src/interfaces/plugins/interactions/interactions.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/keyboardHandler/keyboardHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/keyboardHandler/simpleKeyboardHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/liveSearch/editLiveSearch.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/liveSearch/filterLiveSearch.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/liveSearch/liveSearch.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/normalState/editNormalState.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/normalState/normalState.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/normalState/simpleNormalState.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/optionsHandler/optionsHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/optionsHandler/simpleOptionsHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/popup/popup.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/popup/simplePopup.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/positioner/commonPositioner.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/positioner/popoverPositioner.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/positioner/positioner.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/readonlyState/readonlyState.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/valueHandler/dynamicValueHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/plugins/valueHandler/valueHandler.interface.js.map +1 -1
- package/es2022/src/interfaces/popupContext/popupContext.interface.js.map +1 -1
- package/es2022/src/interfaces/selectApi/selectApi.interface.js.map +1 -1
- package/es2022/src/interfaces/selectBusOptions/selectBusOptions.interface.js.map +1 -1
- package/es2022/src/interfaces/selectCssClasses/selectCssClasses.interface.js.map +1 -1
- package/es2022/src/interfaces/selectEvent/selectEvent.interface.js.map +1 -1
- package/es2022/src/interfaces/selectEvents/selectEvents.interface.js.map +1 -1
- package/es2022/src/interfaces/selectOption/selectOption.interface.js.map +1 -1
- package/es2022/src/interfaces/selectOptionGroup/selectOptionGroup.interface.js.map +1 -1
- package/es2022/src/interfaces/selectOptionState/selectOptionState.interface.js.map +1 -1
- package/es2022/src/interfaces/selectOptionStateSyntetic/selectOptionStateSyntetic.interface.js.map +1 -1
- package/es2022/src/interfaces/selectOptions/selectOptions.interface.js.map +1 -1
- package/es2022/src/interfaces/selectPlugin/selectPlugin.interface.js.map +1 -1
- package/es2022/src/interfaces/selectPluginTypes/selectPluginTypes.interface.js.map +1 -1
- package/es2022/src/interfaces/tempValue/tempValue.interface.js.map +1 -1
- package/es2022/src/interfaces/templateGatherer/templateGatherer.interface.js.map +1 -1
- package/es2022/src/interfaces/visualPluginOptions/visualPluginOptions.interface.js.map +1 -1
- package/es2022/src/misc/classes/codeOptionsGatherer/codeOptionsGatherer.interface.js.map +1 -1
- package/es2022/src/misc/classes/index.js.map +1 -1
- package/es2022/src/misc/classes/selectBus/selectBus.js.map +1 -1
- package/es2022/src/misc/classes/selectPluginInstances/selectPluginInstances.js.map +1 -1
- package/es2022/src/misc/enums.js.map +1 -1
- package/es2022/src/misc/providers.js.map +1 -1
- package/es2022/src/misc/tokens.js.map +1 -1
- package/es2022/src/misc/types.js.map +1 -1
- package/es2022/src/misc/utils.js.map +1 -1
- package/es2022/src/modules/index.js.map +1 -1
- package/es2022/src/modules/select.module.js.map +1 -1
- package/es2022/src/pipes/addNewOption/addNewOption.pipe.js.map +1 -1
- package/es2022/src/pipes/displayOptionValue/displayOptionValue.pipe.js.map +1 -1
- package/es2022/src/pipes/displayValue/displayValue.pipe.js.map +1 -1
- package/es2022/src/pipes/getPlugin/getPlugin.pipe.js.map +1 -1
- package/es2022/src/pipes/groupedListOptions/groupedListOptions.pipe.js.map +1 -1
- package/es2022/src/pipes/hasValue/hasValue.pipe.js.map +1 -1
- package/es2022/src/pipes/index.js.map +1 -1
- package/es2022/src/pipes/optionCssClasses/optionCssClasses.pipe.js.map +1 -1
- package/es2022/src/plugins/index.js.map +1 -1
- package/es2022/src/plugins/interactions/index.js.map +1 -1
- package/es2022/src/plugins/interactions/simpleInteractions/simpleInteractions.component.js.map +1 -1
- package/es2022/src/plugins/keyboardHandler/index.js.map +1 -1
- package/es2022/src/plugins/keyboardHandler/simpleKeyboardHandler/simpleKeyboardHandler.component.js.map +1 -1
- package/es2022/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.js +2 -2
- package/es2022/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.js.map +1 -1
- package/es2022/src/plugins/liveSearch/filterLiveSearch/filterLiveSearch.component.js.map +1 -1
- package/es2022/src/plugins/liveSearch/index.js.map +1 -1
- package/es2022/src/plugins/liveSearch/noLiveSearch/noLiveSearch.component.js.map +1 -1
- package/es2022/src/plugins/normalState/editNormalState/editNormalState.component.js +3 -2
- package/es2022/src/plugins/normalState/editNormalState/editNormalState.component.js.map +1 -1
- package/es2022/src/plugins/normalState/index.js.map +1 -1
- package/es2022/src/plugins/normalState/simpleNormalState/simpleNormalState.component.js +5 -6
- package/es2022/src/plugins/normalState/simpleNormalState/simpleNormalState.component.js.map +1 -1
- package/es2022/src/plugins/optionsHandler/index.js.map +1 -1
- package/es2022/src/plugins/optionsHandler/noOptionsHandler/noOptionsHandler.component.js.map +1 -1
- package/es2022/src/plugins/optionsHandler/optionsHandlerBase.js.map +1 -1
- package/es2022/src/plugins/optionsHandler/simpleOptionsHandler/simpleOptionsHandler.component.js.map +1 -1
- package/es2022/src/plugins/popup/index.js.map +1 -1
- package/es2022/src/plugins/popup/simplePopup/simplePopup.component.js +2 -2
- package/es2022/src/plugins/popup/simplePopup/simplePopup.component.js.map +1 -1
- package/es2022/src/plugins/positioner/commonPositioner/commonPositioner.component.js.map +1 -1
- package/es2022/src/plugins/positioner/index.js.map +1 -1
- package/es2022/src/plugins/positioner/noPositioner/noPositioner.component.js.map +1 -1
- package/es2022/src/plugins/positioner/popoverPositioner/popoverPositioner.component.js.map +1 -1
- package/es2022/src/plugins/valueHandler/dynamicValueHandler/dynamicValueHandler.component.js.map +1 -1
- package/es2022/src/plugins/valueHandler/index.js.map +1 -1
- package/es2022/src/plugins/valueHandler/staticValueHandler/staticValueHandler.component.js.map +1 -1
- package/package.json +125 -125
- package/src/components/select/select.component.css +5 -5
- package/src/interfaces/plugins/normalState/editNormalState.interface.d.ts +4 -0
- package/src/interfaces/plugins/normalState/editNormalState.interface.d.ts.map +1 -1
- package/src/interfaces/plugins/normalState/simpleNormalState.interface.d.ts +1 -5
- package/src/interfaces/plugins/normalState/simpleNormalState.interface.d.ts.map +1 -1
- package/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.html +19 -19
- package/src/plugins/normalState/editNormalState/editNormalState.component.d.ts.map +1 -1
- package/src/plugins/normalState/editNormalState/editNormalState.component.html +52 -50
- package/src/plugins/normalState/simpleNormalState/simpleNormalState.component.d.ts.map +1 -1
- package/src/plugins/normalState/simpleNormalState/simpleNormalState.component.html +36 -37
- package/src/plugins/popup/simplePopup/simplePopup.component.html +56 -56
- package/styles/components/_liveSearch.scss +32 -32
- package/styles/components/_normalState.scss +121 -116
- package/styles/components/_popup.scss +107 -107
- package/styles/components/_select.scss +14 -14
- package/styles/core/_defaultTheme.scss +105 -105
- package/styles/core/_misc.scss +34 -34
- package/styles/core/_mixins.scss +29 -29
- package/styles/index.scss +2 -2
- package/styles/themes/dark.scss +63 -63
- package/styles/themes/light.scss +64 -64
- package/version.bak +1 -1
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# Automatic Migrations & Code Modernization
|
|
2
|
-
|
|
3
|
-
When tasked with refactoring or modernizing an existing codebase, always prefer using the official automated schematics available in `@angular/core` over manual text replacement.
|
|
4
|
-
|
|
5
|
-
## Discovering Migrations
|
|
6
|
-
|
|
7
|
-
To view all available schematics for the installed version of the core framework, run:
|
|
8
|
-
`ng generate @angular/core: --help`
|
|
9
|
-
|
|
10
|
-
## Common Migration Schematics
|
|
11
|
-
|
|
12
|
-
Use the following commands to apply specific syntax updates. You can scope these commands to a specific project or directory using the `--project <name>` or `--path <dir>` flags.
|
|
13
|
-
|
|
14
|
-
| Feature to Modernize | Command to Execute |
|
|
15
|
-
| :------------------------ | :---------------------------------------------------------- |
|
|
16
|
-
| **Built-in Control Flow** | `ng generate @angular/core:control-flow` |
|
|
17
|
-
| **Signal-based Inputs** | `ng generate @angular/core:signal-input-migration` |
|
|
18
|
-
| **Signal Queries** | `ng generate @angular/core:signal-queries-migration` |
|
|
19
|
-
| **Functional Outputs** | `ng generate @angular/core:output-migration` |
|
|
20
|
-
| **`inject()` Function** | `ng generate @angular/core:inject` |
|
|
21
|
-
| **Self-Closing Tags** | `ng generate @angular/core:self-closing-tag` |
|
|
22
|
-
| **Standalone** | `ng generate @angular/core:standalone` (See workflow below) |
|
|
23
|
-
|
|
24
|
-
## Specialized Workflow: Migrating to Standalone
|
|
25
|
-
|
|
26
|
-
The Standalone migration is an interactive, multi-step refactoring. You **MUST** perform this in three discrete stages, verifying that the application builds and runs correctly after each stage completes:
|
|
27
|
-
|
|
28
|
-
1. **Phase 1**: Run `ng generate @angular/core:standalone` and select the option to **Convert all components, directives, and pipes to standalone**.
|
|
29
|
-
2. **Phase 2**: Verify the build with `ng build`. Run the command again and select **Remove unnecessary NgModule classes**.
|
|
30
|
-
3. **Phase 3**: Verify the build with `ng build`. Run the final pass and select **Bootstrap the project using standalone APIs**.
|
|
1
|
+
# Automatic Migrations & Code Modernization
|
|
2
|
+
|
|
3
|
+
When tasked with refactoring or modernizing an existing codebase, always prefer using the official automated schematics available in `@angular/core` over manual text replacement.
|
|
4
|
+
|
|
5
|
+
## Discovering Migrations
|
|
6
|
+
|
|
7
|
+
To view all available schematics for the installed version of the core framework, run:
|
|
8
|
+
`ng generate @angular/core: --help`
|
|
9
|
+
|
|
10
|
+
## Common Migration Schematics
|
|
11
|
+
|
|
12
|
+
Use the following commands to apply specific syntax updates. You can scope these commands to a specific project or directory using the `--project <name>` or `--path <dir>` flags.
|
|
13
|
+
|
|
14
|
+
| Feature to Modernize | Command to Execute |
|
|
15
|
+
| :------------------------ | :---------------------------------------------------------- |
|
|
16
|
+
| **Built-in Control Flow** | `ng generate @angular/core:control-flow` |
|
|
17
|
+
| **Signal-based Inputs** | `ng generate @angular/core:signal-input-migration` |
|
|
18
|
+
| **Signal Queries** | `ng generate @angular/core:signal-queries-migration` |
|
|
19
|
+
| **Functional Outputs** | `ng generate @angular/core:output-migration` |
|
|
20
|
+
| **`inject()` Function** | `ng generate @angular/core:inject` |
|
|
21
|
+
| **Self-Closing Tags** | `ng generate @angular/core:self-closing-tag` |
|
|
22
|
+
| **Standalone** | `ng generate @angular/core:standalone` (See workflow below) |
|
|
23
|
+
|
|
24
|
+
## Specialized Workflow: Migrating to Standalone
|
|
25
|
+
|
|
26
|
+
The Standalone migration is an interactive, multi-step refactoring. You **MUST** perform this in three discrete stages, verifying that the application builds and runs correctly after each stage completes:
|
|
27
|
+
|
|
28
|
+
1. **Phase 1**: Run `ng generate @angular/core:standalone` and select the option to **Convert all components, directives, and pipes to standalone**.
|
|
29
|
+
2. **Phase 2**: Verify the build with `ng build`. Run the command again and select **Remove unnecessary NgModule classes**.
|
|
30
|
+
3. **Phase 3**: Verify the build with `ng build`. Run the final pass and select **Bootstrap the project using standalone APIs**.
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
# Navigate to Routes
|
|
2
|
-
|
|
3
|
-
Angular provides both declarative and programmatic ways to navigate between routes.
|
|
4
|
-
|
|
5
|
-
## Declarative Navigation (`RouterLink`)
|
|
6
|
-
|
|
7
|
-
Use the `RouterLink` directive on anchor elements.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import {RouterLink, RouterLinkActive} from '@angular/router';
|
|
11
|
-
|
|
12
|
-
@Component({
|
|
13
|
-
imports: [RouterLink, RouterLinkActive],
|
|
14
|
-
template: `
|
|
15
|
-
<nav>
|
|
16
|
-
<a routerLink="/dashboard" routerLinkActive="active-link">Dashboard</a>
|
|
17
|
-
<a [routerLink]="['/user', userId]">Profile</a>
|
|
18
|
-
</nav>
|
|
19
|
-
`,
|
|
20
|
-
})
|
|
21
|
-
export class Nav {
|
|
22
|
-
userId = '123';
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
- **Absolute Paths**: Start with `/` (e.g., `/settings`).
|
|
27
|
-
- **Relative Paths**: No leading `/`. Use `../` to go up a level.
|
|
28
|
-
|
|
29
|
-
## Programmatic Navigation (`Router`)
|
|
30
|
-
|
|
31
|
-
Inject the `Router` service to navigate via TypeScript code.
|
|
32
|
-
|
|
33
|
-
### `router.navigate()`
|
|
34
|
-
|
|
35
|
-
Uses an array of commands.
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
private router = inject(Router);
|
|
39
|
-
private route = inject(ActivatedRoute);
|
|
40
|
-
|
|
41
|
-
// Standard navigation
|
|
42
|
-
this.router.navigate(['/profile']);
|
|
43
|
-
|
|
44
|
-
// With parameters
|
|
45
|
-
this.router.navigate(['/search'], {
|
|
46
|
-
queryParams: { q: 'angular' },
|
|
47
|
-
fragment: 'results'
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Relative navigation
|
|
51
|
-
this.router.navigate(['edit'], { relativeTo: this.route });
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### `router.navigateByUrl()`
|
|
55
|
-
|
|
56
|
-
Uses a string path. Ideal for absolute navigation or full URLs.
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
this.router.navigateByUrl('/products/123?view=details');
|
|
60
|
-
|
|
61
|
-
// Replace current entry in history
|
|
62
|
-
this.router.navigateByUrl('/login', {replaceUrl: true});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## URL Parameters
|
|
66
|
-
|
|
67
|
-
- **Route Params**: Part of the path (e.g., `/user/123`).
|
|
68
|
-
- **Query Params**: After the `?` (e.g., `/search?q=query`).
|
|
69
|
-
- **Matrix Params**: Scoped to a segment (e.g., `/products;category=books`).
|
|
1
|
+
# Navigate to Routes
|
|
2
|
+
|
|
3
|
+
Angular provides both declarative and programmatic ways to navigate between routes.
|
|
4
|
+
|
|
5
|
+
## Declarative Navigation (`RouterLink`)
|
|
6
|
+
|
|
7
|
+
Use the `RouterLink` directive on anchor elements.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {RouterLink, RouterLinkActive} from '@angular/router';
|
|
11
|
+
|
|
12
|
+
@Component({
|
|
13
|
+
imports: [RouterLink, RouterLinkActive],
|
|
14
|
+
template: `
|
|
15
|
+
<nav>
|
|
16
|
+
<a routerLink="/dashboard" routerLinkActive="active-link">Dashboard</a>
|
|
17
|
+
<a [routerLink]="['/user', userId]">Profile</a>
|
|
18
|
+
</nav>
|
|
19
|
+
`,
|
|
20
|
+
})
|
|
21
|
+
export class Nav {
|
|
22
|
+
userId = '123';
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Absolute Paths**: Start with `/` (e.g., `/settings`).
|
|
27
|
+
- **Relative Paths**: No leading `/`. Use `../` to go up a level.
|
|
28
|
+
|
|
29
|
+
## Programmatic Navigation (`Router`)
|
|
30
|
+
|
|
31
|
+
Inject the `Router` service to navigate via TypeScript code.
|
|
32
|
+
|
|
33
|
+
### `router.navigate()`
|
|
34
|
+
|
|
35
|
+
Uses an array of commands.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
private router = inject(Router);
|
|
39
|
+
private route = inject(ActivatedRoute);
|
|
40
|
+
|
|
41
|
+
// Standard navigation
|
|
42
|
+
this.router.navigate(['/profile']);
|
|
43
|
+
|
|
44
|
+
// With parameters
|
|
45
|
+
this.router.navigate(['/search'], {
|
|
46
|
+
queryParams: { q: 'angular' },
|
|
47
|
+
fragment: 'results'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Relative navigation
|
|
51
|
+
this.router.navigate(['edit'], { relativeTo: this.route });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `router.navigateByUrl()`
|
|
55
|
+
|
|
56
|
+
Uses a string path. Ideal for absolute navigation or full URLs.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
this.router.navigateByUrl('/products/123?view=details');
|
|
60
|
+
|
|
61
|
+
// Replace current entry in history
|
|
62
|
+
this.router.navigateByUrl('/login', {replaceUrl: true});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## URL Parameters
|
|
66
|
+
|
|
67
|
+
- **Route Params**: Part of the path (e.g., `/user/123`).
|
|
68
|
+
- **Query Params**: After the `?` (e.g., `/search?q=query`).
|
|
69
|
+
- **Matrix Params**: Scoped to a segment (e.g., `/products;category=books`).
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
# Outputs (Custom Events)
|
|
2
|
-
|
|
3
|
-
Outputs allow a child component to emit custom events that a parent component can listen to. Angular recommends using the new `output()` function for modern applications.
|
|
4
|
-
|
|
5
|
-
## Function-based outputs
|
|
6
|
-
|
|
7
|
-
Declare outputs using the `output()` function. This returns an `OutputEmitterRef`.
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import {Component, output} from '@angular/core';
|
|
11
|
-
|
|
12
|
-
@Component({
|
|
13
|
-
selector: 'custom-slider',
|
|
14
|
-
template: `<button (click)="changeValue(50)">Set to 50</button>`,
|
|
15
|
-
})
|
|
16
|
-
export class CustomSlider {
|
|
17
|
-
// Output without event data
|
|
18
|
-
panelClosed = output<void>();
|
|
19
|
-
|
|
20
|
-
// Output with event data (number)
|
|
21
|
-
valueChanged = output<number>();
|
|
22
|
-
|
|
23
|
-
changeValue(newValue: number) {
|
|
24
|
-
this.valueChanged.emit(newValue);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Usage in Template
|
|
30
|
-
|
|
31
|
-
Bind to the output event using parentheses `()`. If the event emits data, access it using the special `$event` variable.
|
|
32
|
-
|
|
33
|
-
```html
|
|
34
|
-
<custom-slider (panelClosed)="savePanelState()" (valueChanged)="logValue($event)" />
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Configuration Options
|
|
38
|
-
|
|
39
|
-
The `output` function accepts a config object to specify an alias.
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
@Component({...})
|
|
43
|
-
export class CustomSlider {
|
|
44
|
-
// The event is named 'valueChanged' in the template,
|
|
45
|
-
// but accessed as 'changed' in the component class.
|
|
46
|
-
changed = output<number>({ alias: 'valueChanged' });
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Programmatic Subscription
|
|
51
|
-
|
|
52
|
-
When creating components dynamically, you can subscribe to outputs programmatically:
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
const componentRef = viewContainerRef.createComponent(CustomSlider);
|
|
56
|
-
|
|
57
|
-
const subscription = componentRef.instance.valueChanged.subscribe((val) => {
|
|
58
|
-
console.log('Value changed:', val);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Clean up manually if needed (Angular cleans up destroyed components automatically)
|
|
62
|
-
subscription.unsubscribe();
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Decorator-based Outputs (@Output)
|
|
66
|
-
|
|
67
|
-
The legacy API uses the `@Output()` decorator with an `EventEmitter`. It remains supported but is not recommended for new code.
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
import { Component, Output, EventEmitter } from '@angular/core';
|
|
71
|
-
|
|
72
|
-
@Component({...})
|
|
73
|
-
export class LegacyExample {
|
|
74
|
-
@Output() valueChanged = new EventEmitter<number>();
|
|
75
|
-
|
|
76
|
-
// With alias
|
|
77
|
-
@Output('customEventName') changed = new EventEmitter<void>();
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Best Practices
|
|
82
|
-
|
|
83
|
-
- **Prefer `output()`**: Use the function-based `output()` instead of `@Output()` and `EventEmitter`.
|
|
84
|
-
- **Naming**: Use `camelCase` for output names. Avoid prefixing with `on` (e.g., use `valueChanged` instead of `onValueChanged`).
|
|
85
|
-
- **No DOM Bubbling**: Angular custom events do not bubble up the DOM tree like native events.
|
|
86
|
-
- **Avoid Collisions**: Do not choose names that collide with native DOM events (like `click` or `submit`).
|
|
1
|
+
# Outputs (Custom Events)
|
|
2
|
+
|
|
3
|
+
Outputs allow a child component to emit custom events that a parent component can listen to. Angular recommends using the new `output()` function for modern applications.
|
|
4
|
+
|
|
5
|
+
## Function-based outputs
|
|
6
|
+
|
|
7
|
+
Declare outputs using the `output()` function. This returns an `OutputEmitterRef`.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {Component, output} from '@angular/core';
|
|
11
|
+
|
|
12
|
+
@Component({
|
|
13
|
+
selector: 'custom-slider',
|
|
14
|
+
template: `<button (click)="changeValue(50)">Set to 50</button>`,
|
|
15
|
+
})
|
|
16
|
+
export class CustomSlider {
|
|
17
|
+
// Output without event data
|
|
18
|
+
panelClosed = output<void>();
|
|
19
|
+
|
|
20
|
+
// Output with event data (number)
|
|
21
|
+
valueChanged = output<number>();
|
|
22
|
+
|
|
23
|
+
changeValue(newValue: number) {
|
|
24
|
+
this.valueChanged.emit(newValue);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Usage in Template
|
|
30
|
+
|
|
31
|
+
Bind to the output event using parentheses `()`. If the event emits data, access it using the special `$event` variable.
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<custom-slider (panelClosed)="savePanelState()" (valueChanged)="logValue($event)" />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration Options
|
|
38
|
+
|
|
39
|
+
The `output` function accepts a config object to specify an alias.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
@Component({...})
|
|
43
|
+
export class CustomSlider {
|
|
44
|
+
// The event is named 'valueChanged' in the template,
|
|
45
|
+
// but accessed as 'changed' in the component class.
|
|
46
|
+
changed = output<number>({ alias: 'valueChanged' });
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Programmatic Subscription
|
|
51
|
+
|
|
52
|
+
When creating components dynamically, you can subscribe to outputs programmatically:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const componentRef = viewContainerRef.createComponent(CustomSlider);
|
|
56
|
+
|
|
57
|
+
const subscription = componentRef.instance.valueChanged.subscribe((val) => {
|
|
58
|
+
console.log('Value changed:', val);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Clean up manually if needed (Angular cleans up destroyed components automatically)
|
|
62
|
+
subscription.unsubscribe();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Decorator-based Outputs (@Output)
|
|
66
|
+
|
|
67
|
+
The legacy API uses the `@Output()` decorator with an `EventEmitter`. It remains supported but is not recommended for new code.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { Component, Output, EventEmitter } from '@angular/core';
|
|
71
|
+
|
|
72
|
+
@Component({...})
|
|
73
|
+
export class LegacyExample {
|
|
74
|
+
@Output() valueChanged = new EventEmitter<number>();
|
|
75
|
+
|
|
76
|
+
// With alias
|
|
77
|
+
@Output('customEventName') changed = new EventEmitter<void>();
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Best Practices
|
|
82
|
+
|
|
83
|
+
- **Prefer `output()`**: Use the function-based `output()` instead of `@Output()` and `EventEmitter`.
|
|
84
|
+
- **Naming**: Use `camelCase` for output names. Avoid prefixing with `on` (e.g., use `valueChanged` instead of `onValueChanged`).
|
|
85
|
+
- **No DOM Bubbling**: Angular custom events do not bubble up the DOM tree like native events.
|
|
86
|
+
- **Avoid Collisions**: Do not choose names that collide with native DOM events (like `click` or `submit`).
|
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
# Reactive Forms
|
|
2
|
-
|
|
3
|
-
Reactive forms provide a model-driven approach to handling form inputs. They are built around observable streams and provide synchronous access to the data model, making them more scalable and testable than template-driven forms.
|
|
4
|
-
|
|
5
|
-
## Core Classes
|
|
6
|
-
|
|
7
|
-
Reactive forms are built using these fundamental classes from `@angular/forms`:
|
|
8
|
-
|
|
9
|
-
- `FormControl`: Manages the value and validity of an individual input.
|
|
10
|
-
- `FormGroup`: Manages a group of controls (an object-like structure).
|
|
11
|
-
- `FormArray`: Manages a numerically indexed array of controls.
|
|
12
|
-
- `FormBuilder`: A service that provides factory methods for creating control instances.
|
|
13
|
-
|
|
14
|
-
## Setup
|
|
15
|
-
|
|
16
|
-
Import `ReactiveFormsModule` into your component.
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import {Component, inject} from '@angular/core';
|
|
20
|
-
import {ReactiveFormsModule, FormGroup, FormControl, Validators, FormBuilder} from '@angular/forms';
|
|
21
|
-
|
|
22
|
-
@Component({
|
|
23
|
-
selector: 'app-profile-editor',
|
|
24
|
-
imports: [ReactiveFormsModule],
|
|
25
|
-
templateUrl: './profile-editor.component.html',
|
|
26
|
-
})
|
|
27
|
-
export class ProfileEditor {
|
|
28
|
-
private fb = inject(FormBuilder);
|
|
29
|
-
|
|
30
|
-
// Using FormBuilder for concise definition
|
|
31
|
-
profileForm = this.fb.group({
|
|
32
|
-
firstName: ['', Validators.required],
|
|
33
|
-
lastName: [''],
|
|
34
|
-
address: this.fb.group({
|
|
35
|
-
street: [''],
|
|
36
|
-
city: [''],
|
|
37
|
-
}),
|
|
38
|
-
aliases: this.fb.array([this.fb.control('')]),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
onSubmit() {
|
|
42
|
-
console.warn(this.profileForm.value);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Template Binding
|
|
48
|
-
|
|
49
|
-
Use directives to bind the model to the view:
|
|
50
|
-
|
|
51
|
-
- `[formGroup]`: Binds a `FormGroup` to a `<form>` or `<div>`.
|
|
52
|
-
- `formControlName`: Binds a named control within a group to an input.
|
|
53
|
-
- `formGroupName`: Binds a nested `FormGroup`.
|
|
54
|
-
- `formArrayName`: Binds a nested `FormArray`.
|
|
55
|
-
- `[formControl]`: Binds a standalone `FormControl`.
|
|
56
|
-
|
|
57
|
-
```html
|
|
58
|
-
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
|
|
59
|
-
<input type="text" formControlName="firstName" />
|
|
60
|
-
|
|
61
|
-
<div formGroupName="address">
|
|
62
|
-
<input type="text" formControlName="street" />
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<div formArrayName="aliases">
|
|
66
|
-
@for (alias of aliases.controls; track $index) {
|
|
67
|
-
<input type="text" [formControlName]="$index" />
|
|
68
|
-
}
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
|
|
72
|
-
</form>
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Accessing Controls
|
|
76
|
-
|
|
77
|
-
Use getters for easy access to controls, especially for `FormArray`.
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
get aliases() {
|
|
81
|
-
return this.profileForm.get('aliases') as FormArray;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
addAlias() {
|
|
85
|
-
this.aliases.push(this.fb.control(''));
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Updating Values
|
|
90
|
-
|
|
91
|
-
- `patchValue()`: Updates only the specified properties. Fails silently on structural mismatches.
|
|
92
|
-
- `setValue()`: Replaces the entire model. Strictly enforces the form structure.
|
|
93
|
-
|
|
94
|
-
```ts
|
|
95
|
-
updateProfile() {
|
|
96
|
-
this.profileForm.patchValue({
|
|
97
|
-
firstName: 'Nancy',
|
|
98
|
-
address: { street: '123 Drew Street' }
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Unified Change Events
|
|
104
|
-
|
|
105
|
-
Modern Angular (v18+) provides a single `events` observable on all controls to track value, status, pristine, touched, reset, and submit events.
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
import {ValueChangeEvent, StatusChangeEvent} from '@angular/forms';
|
|
109
|
-
|
|
110
|
-
this.profileForm.events.subscribe((event) => {
|
|
111
|
-
if (event instanceof ValueChangeEvent) {
|
|
112
|
-
console.log('New value:', event.value);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Manual State Management
|
|
118
|
-
|
|
119
|
-
- `markAsTouched()` / `markAllAsTouched()`: Useful for showing validation errors on submit.
|
|
120
|
-
- `markAsDirty()` / `markAsPristine()`: Tracks if the value has been modified.
|
|
121
|
-
- `updateValueAndValidity()`: Manually triggers recalculation of value and status.
|
|
122
|
-
- Options `{ emitEvent: false }` or `{ onlySelf: true }` can be passed to most methods to control propagation.
|
|
1
|
+
# Reactive Forms
|
|
2
|
+
|
|
3
|
+
Reactive forms provide a model-driven approach to handling form inputs. They are built around observable streams and provide synchronous access to the data model, making them more scalable and testable than template-driven forms.
|
|
4
|
+
|
|
5
|
+
## Core Classes
|
|
6
|
+
|
|
7
|
+
Reactive forms are built using these fundamental classes from `@angular/forms`:
|
|
8
|
+
|
|
9
|
+
- `FormControl`: Manages the value and validity of an individual input.
|
|
10
|
+
- `FormGroup`: Manages a group of controls (an object-like structure).
|
|
11
|
+
- `FormArray`: Manages a numerically indexed array of controls.
|
|
12
|
+
- `FormBuilder`: A service that provides factory methods for creating control instances.
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
Import `ReactiveFormsModule` into your component.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {Component, inject} from '@angular/core';
|
|
20
|
+
import {ReactiveFormsModule, FormGroup, FormControl, Validators, FormBuilder} from '@angular/forms';
|
|
21
|
+
|
|
22
|
+
@Component({
|
|
23
|
+
selector: 'app-profile-editor',
|
|
24
|
+
imports: [ReactiveFormsModule],
|
|
25
|
+
templateUrl: './profile-editor.component.html',
|
|
26
|
+
})
|
|
27
|
+
export class ProfileEditor {
|
|
28
|
+
private fb = inject(FormBuilder);
|
|
29
|
+
|
|
30
|
+
// Using FormBuilder for concise definition
|
|
31
|
+
profileForm = this.fb.group({
|
|
32
|
+
firstName: ['', Validators.required],
|
|
33
|
+
lastName: [''],
|
|
34
|
+
address: this.fb.group({
|
|
35
|
+
street: [''],
|
|
36
|
+
city: [''],
|
|
37
|
+
}),
|
|
38
|
+
aliases: this.fb.array([this.fb.control('')]),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
onSubmit() {
|
|
42
|
+
console.warn(this.profileForm.value);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Template Binding
|
|
48
|
+
|
|
49
|
+
Use directives to bind the model to the view:
|
|
50
|
+
|
|
51
|
+
- `[formGroup]`: Binds a `FormGroup` to a `<form>` or `<div>`.
|
|
52
|
+
- `formControlName`: Binds a named control within a group to an input.
|
|
53
|
+
- `formGroupName`: Binds a nested `FormGroup`.
|
|
54
|
+
- `formArrayName`: Binds a nested `FormArray`.
|
|
55
|
+
- `[formControl]`: Binds a standalone `FormControl`.
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
|
|
59
|
+
<input type="text" formControlName="firstName" />
|
|
60
|
+
|
|
61
|
+
<div formGroupName="address">
|
|
62
|
+
<input type="text" formControlName="street" />
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div formArrayName="aliases">
|
|
66
|
+
@for (alias of aliases.controls; track $index) {
|
|
67
|
+
<input type="text" [formControlName]="$index" />
|
|
68
|
+
}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
|
|
72
|
+
</form>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Accessing Controls
|
|
76
|
+
|
|
77
|
+
Use getters for easy access to controls, especially for `FormArray`.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
get aliases() {
|
|
81
|
+
return this.profileForm.get('aliases') as FormArray;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
addAlias() {
|
|
85
|
+
this.aliases.push(this.fb.control(''));
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Updating Values
|
|
90
|
+
|
|
91
|
+
- `patchValue()`: Updates only the specified properties. Fails silently on structural mismatches.
|
|
92
|
+
- `setValue()`: Replaces the entire model. Strictly enforces the form structure.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
updateProfile() {
|
|
96
|
+
this.profileForm.patchValue({
|
|
97
|
+
firstName: 'Nancy',
|
|
98
|
+
address: { street: '123 Drew Street' }
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Unified Change Events
|
|
104
|
+
|
|
105
|
+
Modern Angular (v18+) provides a single `events` observable on all controls to track value, status, pristine, touched, reset, and submit events.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import {ValueChangeEvent, StatusChangeEvent} from '@angular/forms';
|
|
109
|
+
|
|
110
|
+
this.profileForm.events.subscribe((event) => {
|
|
111
|
+
if (event instanceof ValueChangeEvent) {
|
|
112
|
+
console.log('New value:', event.value);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Manual State Management
|
|
118
|
+
|
|
119
|
+
- `markAsTouched()` / `markAllAsTouched()`: Useful for showing validation errors on submit.
|
|
120
|
+
- `markAsDirty()` / `markAsPristine()`: Tracks if the value has been modified.
|
|
121
|
+
- `updateValueAndValidity()`: Manually triggers recalculation of value and status.
|
|
122
|
+
- Options `{ emitEvent: false }` or `{ onlySelf: true }` can be passed to most methods to control propagation.
|