@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.
Files changed (187) hide show
  1. package/.claude/skills/angular-developer/SKILL.md +130 -130
  2. package/.claude/skills/angular-developer/references/angular-animations.md +160 -160
  3. package/.claude/skills/angular-developer/references/angular-aria.md +410 -410
  4. package/.claude/skills/angular-developer/references/cli.md +86 -86
  5. package/.claude/skills/angular-developer/references/component-harnesses.md +59 -59
  6. package/.claude/skills/angular-developer/references/component-styling.md +91 -91
  7. package/.claude/skills/angular-developer/references/components.md +117 -117
  8. package/.claude/skills/angular-developer/references/creating-services.md +97 -97
  9. package/.claude/skills/angular-developer/references/data-resolvers.md +69 -69
  10. package/.claude/skills/angular-developer/references/define-routes.md +67 -67
  11. package/.claude/skills/angular-developer/references/defining-providers.md +72 -72
  12. package/.claude/skills/angular-developer/references/di-fundamentals.md +120 -120
  13. package/.claude/skills/angular-developer/references/e2e-testing.md +66 -66
  14. package/.claude/skills/angular-developer/references/effects.md +83 -83
  15. package/.claude/skills/angular-developer/references/hierarchical-injectors.md +43 -43
  16. package/.claude/skills/angular-developer/references/host-elements.md +80 -80
  17. package/.claude/skills/angular-developer/references/injection-context.md +63 -63
  18. package/.claude/skills/angular-developer/references/inputs.md +101 -101
  19. package/.claude/skills/angular-developer/references/linked-signal.md +59 -59
  20. package/.claude/skills/angular-developer/references/loading-strategies.md +61 -61
  21. package/.claude/skills/angular-developer/references/mcp.md +106 -106
  22. package/.claude/skills/angular-developer/references/migrations.md +30 -30
  23. package/.claude/skills/angular-developer/references/navigate-to-routes.md +69 -69
  24. package/.claude/skills/angular-developer/references/outputs.md +86 -86
  25. package/.claude/skills/angular-developer/references/reactive-forms.md +122 -122
  26. package/.claude/skills/angular-developer/references/rendering-strategies.md +44 -44
  27. package/.claude/skills/angular-developer/references/resource.md +77 -77
  28. package/.claude/skills/angular-developer/references/route-animations.md +56 -56
  29. package/.claude/skills/angular-developer/references/route-guards.md +52 -52
  30. package/.claude/skills/angular-developer/references/router-lifecycle.md +45 -45
  31. package/.claude/skills/angular-developer/references/router-testing.md +87 -87
  32. package/.claude/skills/angular-developer/references/show-routes-with-outlets.md +68 -68
  33. package/.claude/skills/angular-developer/references/signal-forms.md +897 -897
  34. package/.claude/skills/angular-developer/references/signals-overview.md +94 -94
  35. package/.claude/skills/angular-developer/references/tailwind-css.md +69 -69
  36. package/.claude/skills/angular-developer/references/template-driven-forms.md +114 -114
  37. package/.claude/skills/angular-developer/references/testing-fundamentals.md +66 -66
  38. package/.github/instructions/typescript/code-conventions.md +7 -7
  39. package/.github/instructions/typescript/comments.md +40 -40
  40. package/.github/instructions/typescript/formatting.md +41 -41
  41. package/.github/instructions/typescript/naming-conventions.md +6 -6
  42. package/es2022/extensions/src/extensions/getSearch.js.map +1 -1
  43. package/es2022/extensions/src/extensions/getSelectedOption.js.map +1 -1
  44. package/es2022/extensions/src/extensions/getSelectedOptions.js.map +1 -1
  45. package/es2022/extensions/src/extensions/getValue.js.map +1 -1
  46. package/es2022/extensions/src/extensions/setReadonly.js.map +1 -1
  47. package/es2022/extensions/src/extensions/setValue.js.map +1 -1
  48. package/es2022/extensions/src/index.js.map +1 -1
  49. package/es2022/src/components/index.js.map +1 -1
  50. package/es2022/src/components/option/option.component.js.map +1 -1
  51. package/es2022/src/components/optionGroup/optgroup.component.js.map +1 -1
  52. package/es2022/src/components/select/select.component.js +2 -2
  53. package/es2022/src/components/select/select.component.js.map +1 -1
  54. package/es2022/src/decorators/index.js.map +1 -1
  55. package/es2022/src/decorators/mergeOptionsAsSignal/mergeOptionsAsSignal.decorator.js.map +1 -1
  56. package/es2022/src/directives/highlightInstance/highlightInstance.directive.js.map +1 -1
  57. package/es2022/src/directives/highlightSearch/highlightSearch.directive.js.map +1 -1
  58. package/es2022/src/directives/highlightText/highlightText.directive.js.map +1 -1
  59. package/es2022/src/directives/index.js.map +1 -1
  60. package/es2022/src/directives/normalStateTagTemplate/normalStateTagTemplate.directive.js.map +1 -1
  61. package/es2022/src/directives/normalStateTemplate/normalStateTemplate.directive.js.map +1 -1
  62. package/es2022/src/directives/optionGroupTemplate/optionGroupTemplate.directive.js.map +1 -1
  63. package/es2022/src/directives/optionTemplate/optionTemplate.directive.js.map +1 -1
  64. package/es2022/src/directives/selectAbsolute/selectAbsolute.directive.js.map +1 -1
  65. package/es2022/src/directives/selectControlValueAccessor/selectControlValueAccessor.directive.js.map +1 -1
  66. package/es2022/src/directives/selectEdit/selectEdit.directive.js.map +1 -1
  67. package/es2022/src/directives/selectFormControl/selectFormControl.directive.js.map +1 -1
  68. package/es2022/src/directives/selectMultipleKeepPopup/selectMultipleKeepPopup.directive.js.map +1 -1
  69. package/es2022/src/directives/selectNoCarret/selectNoCarret.directive.js.map +1 -1
  70. package/es2022/src/directives/selectPlaceholder/selectPlaceholder.directive.js.map +1 -1
  71. package/es2022/src/directives/withDirectAccess/withDirectAccess.directive.js.map +1 -1
  72. package/es2022/src/index.js.map +1 -1
  73. package/es2022/src/interfaces/index.js.map +1 -1
  74. package/es2022/src/interfaces/initState/initState.interface.js.map +1 -1
  75. package/es2022/src/interfaces/keyboardAction/keyboardAction.interface.js.map +1 -1
  76. package/es2022/src/interfaces/normalStateContext/normalStateContext.interface.js.map +1 -1
  77. package/es2022/src/interfaces/normalStateTagContext/normalStateTagContext.interface.js.map +1 -1
  78. package/es2022/src/interfaces/optionsGatherer/optionsGatherer.interface.js.map +1 -1
  79. package/es2022/src/interfaces/pluginDescription/pluginDescription.interface.js.map +1 -1
  80. package/es2022/src/interfaces/pluginOptions/pluginOptions.interface.js.map +1 -1
  81. package/es2022/src/interfaces/plugins/index.js.map +1 -1
  82. package/es2022/src/interfaces/plugins/interactions/interactions.interface.js.map +1 -1
  83. package/es2022/src/interfaces/plugins/keyboardHandler/keyboardHandler.interface.js.map +1 -1
  84. package/es2022/src/interfaces/plugins/keyboardHandler/simpleKeyboardHandler.interface.js.map +1 -1
  85. package/es2022/src/interfaces/plugins/liveSearch/editLiveSearch.interface.js.map +1 -1
  86. package/es2022/src/interfaces/plugins/liveSearch/filterLiveSearch.interface.js.map +1 -1
  87. package/es2022/src/interfaces/plugins/liveSearch/liveSearch.interface.js.map +1 -1
  88. package/es2022/src/interfaces/plugins/normalState/editNormalState.interface.js.map +1 -1
  89. package/es2022/src/interfaces/plugins/normalState/normalState.interface.js.map +1 -1
  90. package/es2022/src/interfaces/plugins/normalState/simpleNormalState.interface.js.map +1 -1
  91. package/es2022/src/interfaces/plugins/optionsHandler/optionsHandler.interface.js.map +1 -1
  92. package/es2022/src/interfaces/plugins/optionsHandler/simpleOptionsHandler.interface.js.map +1 -1
  93. package/es2022/src/interfaces/plugins/popup/popup.interface.js.map +1 -1
  94. package/es2022/src/interfaces/plugins/popup/simplePopup.interface.js.map +1 -1
  95. package/es2022/src/interfaces/plugins/positioner/commonPositioner.interface.js.map +1 -1
  96. package/es2022/src/interfaces/plugins/positioner/popoverPositioner.interface.js.map +1 -1
  97. package/es2022/src/interfaces/plugins/positioner/positioner.interface.js.map +1 -1
  98. package/es2022/src/interfaces/plugins/readonlyState/readonlyState.interface.js.map +1 -1
  99. package/es2022/src/interfaces/plugins/valueHandler/dynamicValueHandler.interface.js.map +1 -1
  100. package/es2022/src/interfaces/plugins/valueHandler/valueHandler.interface.js.map +1 -1
  101. package/es2022/src/interfaces/popupContext/popupContext.interface.js.map +1 -1
  102. package/es2022/src/interfaces/selectApi/selectApi.interface.js.map +1 -1
  103. package/es2022/src/interfaces/selectBusOptions/selectBusOptions.interface.js.map +1 -1
  104. package/es2022/src/interfaces/selectCssClasses/selectCssClasses.interface.js.map +1 -1
  105. package/es2022/src/interfaces/selectEvent/selectEvent.interface.js.map +1 -1
  106. package/es2022/src/interfaces/selectEvents/selectEvents.interface.js.map +1 -1
  107. package/es2022/src/interfaces/selectOption/selectOption.interface.js.map +1 -1
  108. package/es2022/src/interfaces/selectOptionGroup/selectOptionGroup.interface.js.map +1 -1
  109. package/es2022/src/interfaces/selectOptionState/selectOptionState.interface.js.map +1 -1
  110. package/es2022/src/interfaces/selectOptionStateSyntetic/selectOptionStateSyntetic.interface.js.map +1 -1
  111. package/es2022/src/interfaces/selectOptions/selectOptions.interface.js.map +1 -1
  112. package/es2022/src/interfaces/selectPlugin/selectPlugin.interface.js.map +1 -1
  113. package/es2022/src/interfaces/selectPluginTypes/selectPluginTypes.interface.js.map +1 -1
  114. package/es2022/src/interfaces/tempValue/tempValue.interface.js.map +1 -1
  115. package/es2022/src/interfaces/templateGatherer/templateGatherer.interface.js.map +1 -1
  116. package/es2022/src/interfaces/visualPluginOptions/visualPluginOptions.interface.js.map +1 -1
  117. package/es2022/src/misc/classes/codeOptionsGatherer/codeOptionsGatherer.interface.js.map +1 -1
  118. package/es2022/src/misc/classes/index.js.map +1 -1
  119. package/es2022/src/misc/classes/selectBus/selectBus.js.map +1 -1
  120. package/es2022/src/misc/classes/selectPluginInstances/selectPluginInstances.js.map +1 -1
  121. package/es2022/src/misc/enums.js.map +1 -1
  122. package/es2022/src/misc/providers.js.map +1 -1
  123. package/es2022/src/misc/tokens.js.map +1 -1
  124. package/es2022/src/misc/types.js.map +1 -1
  125. package/es2022/src/misc/utils.js.map +1 -1
  126. package/es2022/src/modules/index.js.map +1 -1
  127. package/es2022/src/modules/select.module.js.map +1 -1
  128. package/es2022/src/pipes/addNewOption/addNewOption.pipe.js.map +1 -1
  129. package/es2022/src/pipes/displayOptionValue/displayOptionValue.pipe.js.map +1 -1
  130. package/es2022/src/pipes/displayValue/displayValue.pipe.js.map +1 -1
  131. package/es2022/src/pipes/getPlugin/getPlugin.pipe.js.map +1 -1
  132. package/es2022/src/pipes/groupedListOptions/groupedListOptions.pipe.js.map +1 -1
  133. package/es2022/src/pipes/hasValue/hasValue.pipe.js.map +1 -1
  134. package/es2022/src/pipes/index.js.map +1 -1
  135. package/es2022/src/pipes/optionCssClasses/optionCssClasses.pipe.js.map +1 -1
  136. package/es2022/src/plugins/index.js.map +1 -1
  137. package/es2022/src/plugins/interactions/index.js.map +1 -1
  138. package/es2022/src/plugins/interactions/simpleInteractions/simpleInteractions.component.js.map +1 -1
  139. package/es2022/src/plugins/keyboardHandler/index.js.map +1 -1
  140. package/es2022/src/plugins/keyboardHandler/simpleKeyboardHandler/simpleKeyboardHandler.component.js.map +1 -1
  141. package/es2022/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.js +2 -2
  142. package/es2022/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.js.map +1 -1
  143. package/es2022/src/plugins/liveSearch/filterLiveSearch/filterLiveSearch.component.js.map +1 -1
  144. package/es2022/src/plugins/liveSearch/index.js.map +1 -1
  145. package/es2022/src/plugins/liveSearch/noLiveSearch/noLiveSearch.component.js.map +1 -1
  146. package/es2022/src/plugins/normalState/editNormalState/editNormalState.component.js +3 -2
  147. package/es2022/src/plugins/normalState/editNormalState/editNormalState.component.js.map +1 -1
  148. package/es2022/src/plugins/normalState/index.js.map +1 -1
  149. package/es2022/src/plugins/normalState/simpleNormalState/simpleNormalState.component.js +5 -6
  150. package/es2022/src/plugins/normalState/simpleNormalState/simpleNormalState.component.js.map +1 -1
  151. package/es2022/src/plugins/optionsHandler/index.js.map +1 -1
  152. package/es2022/src/plugins/optionsHandler/noOptionsHandler/noOptionsHandler.component.js.map +1 -1
  153. package/es2022/src/plugins/optionsHandler/optionsHandlerBase.js.map +1 -1
  154. package/es2022/src/plugins/optionsHandler/simpleOptionsHandler/simpleOptionsHandler.component.js.map +1 -1
  155. package/es2022/src/plugins/popup/index.js.map +1 -1
  156. package/es2022/src/plugins/popup/simplePopup/simplePopup.component.js +2 -2
  157. package/es2022/src/plugins/popup/simplePopup/simplePopup.component.js.map +1 -1
  158. package/es2022/src/plugins/positioner/commonPositioner/commonPositioner.component.js.map +1 -1
  159. package/es2022/src/plugins/positioner/index.js.map +1 -1
  160. package/es2022/src/plugins/positioner/noPositioner/noPositioner.component.js.map +1 -1
  161. package/es2022/src/plugins/positioner/popoverPositioner/popoverPositioner.component.js.map +1 -1
  162. package/es2022/src/plugins/valueHandler/dynamicValueHandler/dynamicValueHandler.component.js.map +1 -1
  163. package/es2022/src/plugins/valueHandler/index.js.map +1 -1
  164. package/es2022/src/plugins/valueHandler/staticValueHandler/staticValueHandler.component.js.map +1 -1
  165. package/package.json +125 -125
  166. package/src/components/select/select.component.css +5 -5
  167. package/src/interfaces/plugins/normalState/editNormalState.interface.d.ts +4 -0
  168. package/src/interfaces/plugins/normalState/editNormalState.interface.d.ts.map +1 -1
  169. package/src/interfaces/plugins/normalState/simpleNormalState.interface.d.ts +1 -5
  170. package/src/interfaces/plugins/normalState/simpleNormalState.interface.d.ts.map +1 -1
  171. package/src/plugins/liveSearch/editLiveSearch/editLiveSearch.component.html +19 -19
  172. package/src/plugins/normalState/editNormalState/editNormalState.component.d.ts.map +1 -1
  173. package/src/plugins/normalState/editNormalState/editNormalState.component.html +52 -50
  174. package/src/plugins/normalState/simpleNormalState/simpleNormalState.component.d.ts.map +1 -1
  175. package/src/plugins/normalState/simpleNormalState/simpleNormalState.component.html +36 -37
  176. package/src/plugins/popup/simplePopup/simplePopup.component.html +56 -56
  177. package/styles/components/_liveSearch.scss +32 -32
  178. package/styles/components/_normalState.scss +121 -116
  179. package/styles/components/_popup.scss +107 -107
  180. package/styles/components/_select.scss +14 -14
  181. package/styles/core/_defaultTheme.scss +105 -105
  182. package/styles/core/_misc.scss +34 -34
  183. package/styles/core/_mixins.scss +29 -29
  184. package/styles/index.scss +2 -2
  185. package/styles/themes/dark.scss +63 -63
  186. package/styles/themes/light.scss +64 -64
  187. package/version.bak +1 -1
@@ -1,83 +1,83 @@
1
- # Side Effects with `effect` and `afterRenderEffect`
2
-
3
- In Angular, an **effect** is an operation that runs whenever one or more signal values it tracks change.
4
-
5
- ## When to use `effect`
6
-
7
- Effects are intended for syncing signal state to imperative, non-signal APIs.
8
-
9
- **Valid Use Cases:**
10
-
11
- - Logging analytics.
12
- - Syncing state to `localStorage` or `sessionStorage`.
13
- - Performing custom rendering to a `<canvas>` or 3rd-party charting library.
14
-
15
- **CRITICAL RULE: DO NOT use effects to propagate state.**
16
- If you find yourself using `.set()` or `.update()` on a signal _inside_ an effect to keep two signals in sync, you are making a mistake. This causes `ExpressionChangedAfterItHasBeenChecked` errors and infinite loops. **Always use `computed()` or `linkedSignal()` for state derivation.**
17
-
18
- ## Basic Usage
19
-
20
- Effects execute asynchronously during the change detection process. They always run at least once.
21
-
22
- ```ts
23
- import { Component, signal, effect } from '@angular/core';
24
-
25
- @Component({...})
26
- export class Example {
27
- count = signal(0);
28
-
29
- constructor() {
30
- // Effect must be created in an injection context (e.g., a constructor)
31
- effect((onCleanup) => {
32
- console.log(`Count changed to ${this.count()}`);
33
-
34
- const timer = setTimeout(() => console.log('Timer finished'), 1000);
35
-
36
- // Cleanup function runs before the next execution, or when destroyed
37
- onCleanup(() => clearTimeout(timer));
38
- });
39
- }
40
- }
41
- ```
42
-
43
- ## DOM Manipulation with `afterRenderEffect`
44
-
45
- Standard `effect` runs _before_ Angular updates the DOM. If you need to manually inspect or modify the DOM based on a signal change (e.g., integrating a 3rd party UI library), use `afterRenderEffect`.
46
-
47
- `afterRenderEffect` runs after Angular has finished rendering the DOM.
48
-
49
- ### Render Phases
50
-
51
- To prevent reflows (forced layout thrashing), `afterRenderEffect` forces you to divide your DOM reads and writes into specific phases.
52
-
53
- ```ts
54
- import { Component, afterRenderEffect, viewChild, ElementRef } from '@angular/core';
55
-
56
- @Component({...})
57
- export class Chart {
58
- canvas = viewChild.required<ElementRef>('canvas');
59
-
60
- constructor() {
61
- afterRenderEffect({
62
- // 1. Read from the DOM
63
- earlyRead: () => {
64
- return this.canvas().nativeElement.getBoundingClientRect().width;
65
- },
66
- // 2. Write to the DOM (receives the result of the previous phase)
67
- write: (width) => {
68
- // NEVER read from the DOM in the write phase.
69
- setupChart(this.canvas().nativeElement, width);
70
- }
71
- });
72
- }
73
- }
74
- ```
75
-
76
- **Available Phases (executed in this order):**
77
-
78
- 1. `earlyRead`
79
- 2. `write` (Never read here)
80
- 3. `mixedReadWrite` (Avoid if possible)
81
- 4. `read` (Never write here)
82
-
83
- _Note: `afterRenderEffect` only runs on the client, never during Server-Side Rendering (SSR)._
1
+ # Side Effects with `effect` and `afterRenderEffect`
2
+
3
+ In Angular, an **effect** is an operation that runs whenever one or more signal values it tracks change.
4
+
5
+ ## When to use `effect`
6
+
7
+ Effects are intended for syncing signal state to imperative, non-signal APIs.
8
+
9
+ **Valid Use Cases:**
10
+
11
+ - Logging analytics.
12
+ - Syncing state to `localStorage` or `sessionStorage`.
13
+ - Performing custom rendering to a `<canvas>` or 3rd-party charting library.
14
+
15
+ **CRITICAL RULE: DO NOT use effects to propagate state.**
16
+ If you find yourself using `.set()` or `.update()` on a signal _inside_ an effect to keep two signals in sync, you are making a mistake. This causes `ExpressionChangedAfterItHasBeenChecked` errors and infinite loops. **Always use `computed()` or `linkedSignal()` for state derivation.**
17
+
18
+ ## Basic Usage
19
+
20
+ Effects execute asynchronously during the change detection process. They always run at least once.
21
+
22
+ ```ts
23
+ import { Component, signal, effect } from '@angular/core';
24
+
25
+ @Component({...})
26
+ export class Example {
27
+ count = signal(0);
28
+
29
+ constructor() {
30
+ // Effect must be created in an injection context (e.g., a constructor)
31
+ effect((onCleanup) => {
32
+ console.log(`Count changed to ${this.count()}`);
33
+
34
+ const timer = setTimeout(() => console.log('Timer finished'), 1000);
35
+
36
+ // Cleanup function runs before the next execution, or when destroyed
37
+ onCleanup(() => clearTimeout(timer));
38
+ });
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## DOM Manipulation with `afterRenderEffect`
44
+
45
+ Standard `effect` runs _before_ Angular updates the DOM. If you need to manually inspect or modify the DOM based on a signal change (e.g., integrating a 3rd party UI library), use `afterRenderEffect`.
46
+
47
+ `afterRenderEffect` runs after Angular has finished rendering the DOM.
48
+
49
+ ### Render Phases
50
+
51
+ To prevent reflows (forced layout thrashing), `afterRenderEffect` forces you to divide your DOM reads and writes into specific phases.
52
+
53
+ ```ts
54
+ import { Component, afterRenderEffect, viewChild, ElementRef } from '@angular/core';
55
+
56
+ @Component({...})
57
+ export class Chart {
58
+ canvas = viewChild.required<ElementRef>('canvas');
59
+
60
+ constructor() {
61
+ afterRenderEffect({
62
+ // 1. Read from the DOM
63
+ earlyRead: () => {
64
+ return this.canvas().nativeElement.getBoundingClientRect().width;
65
+ },
66
+ // 2. Write to the DOM (receives the result of the previous phase)
67
+ write: (width) => {
68
+ // NEVER read from the DOM in the write phase.
69
+ setupChart(this.canvas().nativeElement, width);
70
+ }
71
+ });
72
+ }
73
+ }
74
+ ```
75
+
76
+ **Available Phases (executed in this order):**
77
+
78
+ 1. `earlyRead`
79
+ 2. `write` (Never read here)
80
+ 3. `mixedReadWrite` (Avoid if possible)
81
+ 4. `read` (Never write here)
82
+
83
+ _Note: `afterRenderEffect` only runs on the client, never during Server-Side Rendering (SSR)._
@@ -1,43 +1,43 @@
1
- # Hierarchical Injectors
2
-
3
- Angular's dependency injection system is hierarchical, meaning services can be scoped to different levels of the application.
4
-
5
- ## Types of Injector Hierarchies
6
-
7
- 1. **`EnvironmentInjector` Hierarchy**: Configured via `@Injectable({ providedIn: 'root' })` or `ApplicationConfig.providers` during bootstrap. These are global singletons.
8
- 2. **`ElementInjector` Hierarchy**: Created implicitly at each DOM element. Configured via the `providers` or `viewProviders` array in `@Component()` or `@Directive()`.
9
-
10
- ## Resolution Rules
11
-
12
- When a dependency is requested, Angular resolves it in two phases:
13
-
14
- 1. It searches up the **`ElementInjector`** tree, starting from the requesting component/directive up to the root element.
15
- 2. If not found, it searches the **`EnvironmentInjector`** tree, starting from the closest environment injector up to the root.
16
- 3. If still not found, it throws an error (unless marked optional).
17
-
18
- ## Resolution Modifiers
19
-
20
- You can alter how Angular searches for a dependency using the options object in `inject()`:
21
-
22
- - **`optional`**: If the dependency isn't found, return `null` instead of throwing an error.
23
- - **`self`**: Only check the current `ElementInjector`. Do not look up the parent tree.
24
- - **`skipSelf`**: Start searching in the parent `ElementInjector`, skipping the current element.
25
- - **`host`**: Stop searching when reaching the host component's view boundary.
26
-
27
- ```ts
28
- @Component({...})
29
- export class Example {
30
- // Returns null if not found instead of crashing
31
- optionalService = inject(MyService, { optional: true });
32
-
33
- // Skips this component's providers, looks at parent
34
- parentService = inject(ParentService, { skipSelf: true });
35
- }
36
- ```
37
-
38
- ## `providers` vs `viewProviders`
39
-
40
- When providing a service at the component level:
41
-
42
- - **`providers`**: The service is available to the component, its view (template), and any **projected content** (`<ng-content>`).
43
- - **`viewProviders`**: The service is available to the component and its view, but **NOT** to projected content. Use this to isolate services from content passed in by consumers.
1
+ # Hierarchical Injectors
2
+
3
+ Angular's dependency injection system is hierarchical, meaning services can be scoped to different levels of the application.
4
+
5
+ ## Types of Injector Hierarchies
6
+
7
+ 1. **`EnvironmentInjector` Hierarchy**: Configured via `@Injectable({ providedIn: 'root' })` or `ApplicationConfig.providers` during bootstrap. These are global singletons.
8
+ 2. **`ElementInjector` Hierarchy**: Created implicitly at each DOM element. Configured via the `providers` or `viewProviders` array in `@Component()` or `@Directive()`.
9
+
10
+ ## Resolution Rules
11
+
12
+ When a dependency is requested, Angular resolves it in two phases:
13
+
14
+ 1. It searches up the **`ElementInjector`** tree, starting from the requesting component/directive up to the root element.
15
+ 2. If not found, it searches the **`EnvironmentInjector`** tree, starting from the closest environment injector up to the root.
16
+ 3. If still not found, it throws an error (unless marked optional).
17
+
18
+ ## Resolution Modifiers
19
+
20
+ You can alter how Angular searches for a dependency using the options object in `inject()`:
21
+
22
+ - **`optional`**: If the dependency isn't found, return `null` instead of throwing an error.
23
+ - **`self`**: Only check the current `ElementInjector`. Do not look up the parent tree.
24
+ - **`skipSelf`**: Start searching in the parent `ElementInjector`, skipping the current element.
25
+ - **`host`**: Stop searching when reaching the host component's view boundary.
26
+
27
+ ```ts
28
+ @Component({...})
29
+ export class Example {
30
+ // Returns null if not found instead of crashing
31
+ optionalService = inject(MyService, { optional: true });
32
+
33
+ // Skips this component's providers, looks at parent
34
+ parentService = inject(ParentService, { skipSelf: true });
35
+ }
36
+ ```
37
+
38
+ ## `providers` vs `viewProviders`
39
+
40
+ When providing a service at the component level:
41
+
42
+ - **`providers`**: The service is available to the component, its view (template), and any **projected content** (`<ng-content>`).
43
+ - **`viewProviders`**: The service is available to the component and its view, but **NOT** to projected content. Use this to isolate services from content passed in by consumers.
@@ -1,80 +1,80 @@
1
- # Component Host Elements
2
-
3
- The **host element** is the DOM element that matches a component's selector. The component's template renders inside this element.
4
-
5
- ## Binding to the Host Element
6
-
7
- Use the `host` property in the `@Component` decorator to bind properties, attributes, styles, and events to the host element. This is the **preferred approach** over legacy decorators.
8
-
9
- ```ts
10
- @Component({
11
- selector: 'custom-slider',
12
- host: {
13
- 'role': 'slider', // Static attribute
14
- '[attr.aria-valuenow]': 'value', // Attribute binding
15
- '[class.active]': 'isActive()', // Class binding
16
- '[style.color]': 'color()', // Style binding
17
- '[tabIndex]': 'disabled ? -1 : 0', // Property binding
18
- '(keydown)': 'onKeyDown($event)', // Event binding
19
- },
20
- })
21
- export class CustomSlider {
22
- value = 0;
23
- disabled = false;
24
- isActive = signal(false);
25
- color = signal('blue');
26
-
27
- onKeyDown(event: KeyboardEvent) {
28
- /* ... */
29
- }
30
- }
31
- ```
32
-
33
- ## Legacy Decorators
34
-
35
- `@HostBinding` and `@HostListener` are supported for backwards compatibility but should be avoided in new code.
36
-
37
- ```ts
38
- export class CustomSlider {
39
- @HostBinding('tabIndex')
40
- get tabIndex() {
41
- return this.disabled ? -1 : 0;
42
- }
43
-
44
- @HostListener('keydown', ['$event'])
45
- onKeyDown(event: KeyboardEvent) {
46
- /* ... */
47
- }
48
- }
49
- ```
50
-
51
- ## Binding Collisions
52
-
53
- If both the component (host binding) and the consumer (template binding) bind to the same property:
54
-
55
- 1. **Static vs Static**: The instance (consumer) binding wins.
56
- 2. **Static vs Dynamic**: The dynamic binding wins.
57
- 3. **Dynamic vs Dynamic**: The component's host binding wins.
58
-
59
- ## Injecting Host Attributes
60
-
61
- Use `HostAttributeToken` with the `inject` function to read static attributes from the host element at construction time.
62
-
63
- ```ts
64
- import {Component, HostAttributeToken, inject} from '@angular/core';
65
-
66
- @Component({
67
- selector: 'app-btn',
68
- template: `<ng-content />`,
69
- })
70
- export class AppButton {
71
- // Throws error if 'type' is missing unless injected with { optional: true }
72
- type = inject(new HostAttributeToken('type'));
73
- }
74
- ```
75
-
76
- Usage:
77
-
78
- ```html
79
- <app-btn type="primary">Click Me</app-btn>
80
- ```
1
+ # Component Host Elements
2
+
3
+ The **host element** is the DOM element that matches a component's selector. The component's template renders inside this element.
4
+
5
+ ## Binding to the Host Element
6
+
7
+ Use the `host` property in the `@Component` decorator to bind properties, attributes, styles, and events to the host element. This is the **preferred approach** over legacy decorators.
8
+
9
+ ```ts
10
+ @Component({
11
+ selector: 'custom-slider',
12
+ host: {
13
+ 'role': 'slider', // Static attribute
14
+ '[attr.aria-valuenow]': 'value', // Attribute binding
15
+ '[class.active]': 'isActive()', // Class binding
16
+ '[style.color]': 'color()', // Style binding
17
+ '[tabIndex]': 'disabled ? -1 : 0', // Property binding
18
+ '(keydown)': 'onKeyDown($event)', // Event binding
19
+ },
20
+ })
21
+ export class CustomSlider {
22
+ value = 0;
23
+ disabled = false;
24
+ isActive = signal(false);
25
+ color = signal('blue');
26
+
27
+ onKeyDown(event: KeyboardEvent) {
28
+ /* ... */
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Legacy Decorators
34
+
35
+ `@HostBinding` and `@HostListener` are supported for backwards compatibility but should be avoided in new code.
36
+
37
+ ```ts
38
+ export class CustomSlider {
39
+ @HostBinding('tabIndex')
40
+ get tabIndex() {
41
+ return this.disabled ? -1 : 0;
42
+ }
43
+
44
+ @HostListener('keydown', ['$event'])
45
+ onKeyDown(event: KeyboardEvent) {
46
+ /* ... */
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Binding Collisions
52
+
53
+ If both the component (host binding) and the consumer (template binding) bind to the same property:
54
+
55
+ 1. **Static vs Static**: The instance (consumer) binding wins.
56
+ 2. **Static vs Dynamic**: The dynamic binding wins.
57
+ 3. **Dynamic vs Dynamic**: The component's host binding wins.
58
+
59
+ ## Injecting Host Attributes
60
+
61
+ Use `HostAttributeToken` with the `inject` function to read static attributes from the host element at construction time.
62
+
63
+ ```ts
64
+ import {Component, HostAttributeToken, inject} from '@angular/core';
65
+
66
+ @Component({
67
+ selector: 'app-btn',
68
+ template: `<ng-content />`,
69
+ })
70
+ export class AppButton {
71
+ // Throws error if 'type' is missing unless injected with { optional: true }
72
+ type = inject(new HostAttributeToken('type'));
73
+ }
74
+ ```
75
+
76
+ Usage:
77
+
78
+ ```html
79
+ <app-btn type="primary">Click Me</app-btn>
80
+ ```
@@ -1,63 +1,63 @@
1
- # Injection Context
2
-
3
- The `inject()` function can only be used when code is executing within an **injection context**.
4
-
5
- ## Where is an Injection Context Available?
6
-
7
- An injection context is automatically available in:
8
-
9
- 1. **Field initializers** of classes instantiated by DI (`@Injectable`, `@Component`, `@Directive`, `@Pipe`).
10
- 2. **Constructors** of classes instantiated by DI.
11
- 3. **Factory functions** specified in `useFactory` or `InjectionToken` configurations.
12
- 4. **Functional APIs** executed by Angular (e.g., functional route guards, resolvers, interceptors).
13
-
14
- ```ts
15
- @Component({...})
16
- export class Example {
17
- // ✅ Valid: Field initializer
18
- private router = inject(Router);
19
-
20
- constructor() {
21
- // ✅ Valid: Constructor
22
- const http = inject(HttpClient);
23
- }
24
-
25
- onClick() {
26
- // ❌ Invalid: Not an injection context
27
- // const auth = inject(AuthService);
28
- }
29
- }
30
- ```
31
-
32
- ## `runInInjectionContext`
33
-
34
- If you need to run a function within an injection context (often needed for dynamic component creation or testing), use `runInInjectionContext`. This requires access to an existing injector (like `EnvironmentInjector` or `Injector`).
35
-
36
- ```ts
37
- import {Injectable, inject, EnvironmentInjector, runInInjectionContext} from '@angular/core';
38
-
39
- @Injectable({providedIn: 'root'})
40
- export class MyService {
41
- private injector = inject(EnvironmentInjector);
42
-
43
- doSomethingDynamic() {
44
- runInInjectionContext(this.injector, () => {
45
- // ✅ Now valid to use inject() here
46
- const router = inject(Router);
47
- });
48
- }
49
- }
50
- ```
51
-
52
- ## `assertInInjectionContext`
53
-
54
- Use `assertInInjectionContext` in utility functions to guarantee they are called from a valid context. It throws a clear error if not.
55
-
56
- ```ts
57
- import {assertInInjectionContext, inject, ElementRef} from '@angular/core';
58
-
59
- export function injectNativeElement<T extends Element>(): T {
60
- assertInInjectionContext(injectNativeElement);
61
- return inject(ElementRef).nativeElement;
62
- }
63
- ```
1
+ # Injection Context
2
+
3
+ The `inject()` function can only be used when code is executing within an **injection context**.
4
+
5
+ ## Where is an Injection Context Available?
6
+
7
+ An injection context is automatically available in:
8
+
9
+ 1. **Field initializers** of classes instantiated by DI (`@Injectable`, `@Component`, `@Directive`, `@Pipe`).
10
+ 2. **Constructors** of classes instantiated by DI.
11
+ 3. **Factory functions** specified in `useFactory` or `InjectionToken` configurations.
12
+ 4. **Functional APIs** executed by Angular (e.g., functional route guards, resolvers, interceptors).
13
+
14
+ ```ts
15
+ @Component({...})
16
+ export class Example {
17
+ // ✅ Valid: Field initializer
18
+ private router = inject(Router);
19
+
20
+ constructor() {
21
+ // ✅ Valid: Constructor
22
+ const http = inject(HttpClient);
23
+ }
24
+
25
+ onClick() {
26
+ // ❌ Invalid: Not an injection context
27
+ // const auth = inject(AuthService);
28
+ }
29
+ }
30
+ ```
31
+
32
+ ## `runInInjectionContext`
33
+
34
+ If you need to run a function within an injection context (often needed for dynamic component creation or testing), use `runInInjectionContext`. This requires access to an existing injector (like `EnvironmentInjector` or `Injector`).
35
+
36
+ ```ts
37
+ import {Injectable, inject, EnvironmentInjector, runInInjectionContext} from '@angular/core';
38
+
39
+ @Injectable({providedIn: 'root'})
40
+ export class MyService {
41
+ private injector = inject(EnvironmentInjector);
42
+
43
+ doSomethingDynamic() {
44
+ runInInjectionContext(this.injector, () => {
45
+ // ✅ Now valid to use inject() here
46
+ const router = inject(Router);
47
+ });
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## `assertInInjectionContext`
53
+
54
+ Use `assertInInjectionContext` in utility functions to guarantee they are called from a valid context. It throws a clear error if not.
55
+
56
+ ```ts
57
+ import {assertInInjectionContext, inject, ElementRef} from '@angular/core';
58
+
59
+ export function injectNativeElement<T extends Element>(): T {
60
+ assertInInjectionContext(injectNativeElement);
61
+ return inject(ElementRef).nativeElement;
62
+ }
63
+ ```