@dsivd/prestations-ng 18.8.0-beta.13 → 19.0.0-beta.1

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 (298) hide show
  1. package/.browserslistrc +12 -21
  2. package/ANGULAR_SIGNALS.md +856 -0
  3. package/CHANGELOG.md +333 -312
  4. package/COMPONENTS.md +350 -0
  5. package/CONTRIBUTING.md +2 -4
  6. package/ESLINT_MIGRATION_GUIDE.md +64 -67
  7. package/IAM_ACV_MIGRATION_OIDC.md +138 -0
  8. package/MULTI_ETAPES.md +1 -1
  9. package/README.md +4 -2
  10. package/UPGRADING_V12.md +0 -10
  11. package/UPGRADING_V16.md +0 -1
  12. package/UPGRADING_V18.md +398 -233
  13. package/UPGRADING_V19.md +174 -0
  14. package/dsivd-prestations-ng-19.0.0-beta.1.tgz +0 -0
  15. package/fesm2022/dsivd-prestations-ng.mjs +9333 -10485
  16. package/fesm2022/dsivd-prestations-ng.mjs.map +1 -1
  17. package/index.html +1 -1
  18. package/package.json +18 -17
  19. package/schematics/utility/add-allow-synthetic-default-imports.js +2 -2
  20. package/schematics/utility/add-allowed-common-js-dependencies.js +3 -3
  21. package/schematics/utility/foehn2-bootstrap5-migration.js +21 -21
  22. package/schematics/utility/migrate-to-karma-coverage.js +2 -2
  23. package/schematics/utility/remove-emit-decorator-metadata.js +2 -2
  24. package/types/dsivd-prestations-ng.d.ts +3699 -0
  25. package/MODULES.md +0 -371
  26. package/abstract-page-component.d.ts +0 -57
  27. package/directives/currency-formatter.directive.d.ts +0 -20
  28. package/directives/formatter.module.d.ts +0 -11
  29. package/directives/iban-formatter.directive.d.ts +0 -10
  30. package/directives/ide-formatter.directive.d.ts +0 -17
  31. package/directives/ndc-formatter.directive.d.ts +0 -24
  32. package/dsivd-prestations-ng-18.8.0-beta.13.tgz +0 -0
  33. package/foehn-address/address.type.d.ts +0 -27
  34. package/foehn-address/foehn-address.module.d.ts +0 -15
  35. package/foehn-address/foehn-display-address.component.d.ts +0 -16
  36. package/foehn-address/foehn-input-address.component.d.ts +0 -107
  37. package/foehn-address/foehn-input-foreign-locality.component.d.ts +0 -16
  38. package/foehn-address/foehn-input-foreign-street.component.d.ts +0 -12
  39. package/foehn-agenda/calendar.type.d.ts +0 -9
  40. package/foehn-agenda/current-week.type.d.ts +0 -5
  41. package/foehn-agenda/day-slots.type.d.ts +0 -5
  42. package/foehn-agenda/foehn-agenda-navigation/foehn-agenda-navigation.component.d.ts +0 -21
  43. package/foehn-agenda/foehn-agenda-timeslot-panel/foehn-agenda-timeslot-panel.component.d.ts +0 -51
  44. package/foehn-agenda/foehn-agenda.component.d.ts +0 -29
  45. package/foehn-agenda/foehn-agenda.module.d.ts +0 -17
  46. package/foehn-agenda/pagination-week.type.d.ts +0 -5
  47. package/foehn-agenda/selected-slot.type.d.ts +0 -7
  48. package/foehn-autocomplete/foehn-autocomplete.component.d.ts +0 -126
  49. package/foehn-autocomplete/foehn-autocomplete.module.d.ts +0 -13
  50. package/foehn-boolean/foehn-boolean-checkbox.component.d.ts +0 -6
  51. package/foehn-boolean/foehn-boolean-radio.component.d.ts +0 -9
  52. package/foehn-boolean/foehn-boolean.module.d.ts +0 -12
  53. package/foehn-breadcrumb/breadcrumb-event.service.d.ts +0 -48
  54. package/foehn-breadcrumb/breadcrumb.d.ts +0 -19
  55. package/foehn-breadcrumb/foehn-breadcrumb.component.d.ts +0 -30
  56. package/foehn-breadcrumb/foehn-breadcrumb.module.d.ts +0 -10
  57. package/foehn-checkables/foehn-checkable-group.component.d.ts +0 -64
  58. package/foehn-checkables/foehn-checkables.module.d.ts +0 -17
  59. package/foehn-checkables/foehn-checkbox.component.d.ts +0 -9
  60. package/foehn-checkables/foehn-radio.component.d.ts +0 -12
  61. package/foehn-checkables/foehn-select.component.d.ts +0 -22
  62. package/foehn-checkables/form-select-option-group.d.ts +0 -4
  63. package/foehn-checkables/form-select-option.d.ts +0 -5
  64. package/foehn-confirm-modal/foehn-confirm-modal-content.d.ts +0 -9
  65. package/foehn-confirm-modal/foehn-confirm-modal.component.d.ts +0 -17
  66. package/foehn-confirm-modal/foehn-confirm-modal.module.d.ts +0 -9
  67. package/foehn-confirm-modal/foehn-confirm-modal.service.d.ts +0 -18
  68. package/foehn-date-picker/date-picker-navigation.helper.d.ts +0 -26
  69. package/foehn-date-picker/date-picker.helper.d.ts +0 -30
  70. package/foehn-date-picker/day-month.type.d.ts +0 -8
  71. package/foehn-date-picker/focused-day.type.d.ts +0 -6
  72. package/foehn-date-picker/foehn-date-picker.component.d.ts +0 -78
  73. package/foehn-date-picker/foehn-date-picker.module.d.ts +0 -13
  74. package/foehn-date-picker/month-year.type.d.ts +0 -4
  75. package/foehn-date-picker-button/foehn-date-picker-button.component.d.ts +0 -31
  76. package/foehn-date-picker-button/foehn-date-picker-button.module.d.ts +0 -12
  77. package/foehn-debug-summary/foehn-debug-summary.component.d.ts +0 -21
  78. package/foehn-debug-summary/foehn-debug-summary.component.module.d.ts +0 -9
  79. package/foehn-decision-electronique/foehn-decision-electronique.component.d.ts +0 -11
  80. package/foehn-decision-electronique/foehn-decision-electronique.module.d.ts +0 -11
  81. package/foehn-dropdown-menu/dropdown-menu-group.type.d.ts +0 -5
  82. package/foehn-dropdown-menu/dropdown-menu-item.type.d.ts +0 -9
  83. package/foehn-dropdown-menu/foehn-dropdown-menu.component.d.ts +0 -42
  84. package/foehn-dropdown-menu/foehn-dropdown-menu.module.d.ts +0 -11
  85. package/foehn-feedback-notification/foehn-feedback-notification.component.d.ts +0 -32
  86. package/foehn-feedback-notification/foehn-feedback-notification.module.d.ts +0 -11
  87. package/foehn-feedback-notification/foehn-feedback-notification.type.d.ts +0 -8
  88. package/foehn-footer/foehn-footer.component.d.ts +0 -44
  89. package/foehn-footer/foehn-footer.module.d.ts +0 -9
  90. package/foehn-footer/footer-link.type.d.ts +0 -4
  91. package/foehn-form/foehn-form.component.d.ts +0 -27
  92. package/foehn-form/foehn-form.module.d.ts +0 -10
  93. package/foehn-form/register-ng-model.service.d.ts +0 -9
  94. package/foehn-growl/foehn-growl.component.d.ts +0 -17
  95. package/foehn-growl/foehn-growl.module.d.ts +0 -8
  96. package/foehn-growl/growl-broker.service.d.ts +0 -12
  97. package/foehn-growl/growl-message.d.ts +0 -7
  98. package/foehn-growl/growl-types.d.ts +0 -6
  99. package/foehn-header/foehn-header.component.d.ts +0 -47
  100. package/foehn-header/foehn-header.module.d.ts +0 -14
  101. package/foehn-header/foehn-skip-link.component.d.ts +0 -23
  102. package/foehn-help-modal/foehn-help-modal.component.d.ts +0 -17
  103. package/foehn-help-modal/foehn-help-modal.module.d.ts +0 -10
  104. package/foehn-help-modal/foehn-help-modal.type.d.ts +0 -13
  105. package/foehn-icons/abstract-icon-component.d.ts +0 -9
  106. package/foehn-icons/foehn-icon-calendar.component.d.ts +0 -8
  107. package/foehn-icons/foehn-icon-check-square-o.component.d.ts +0 -8
  108. package/foehn-icons/foehn-icon-check.component.d.ts +0 -8
  109. package/foehn-icons/foehn-icon-chevron-down.component.d.ts +0 -8
  110. package/foehn-icons/foehn-icon-chevron-left.component.d.ts +0 -8
  111. package/foehn-icons/foehn-icon-chevron-right.component.d.ts +0 -8
  112. package/foehn-icons/foehn-icon-chevron-up.component.d.ts +0 -8
  113. package/foehn-icons/foehn-icon-clock.component.d.ts +0 -8
  114. package/foehn-icons/foehn-icon-comment-dots.component.d.ts +0 -8
  115. package/foehn-icons/foehn-icon-edit.component.d.ts +0 -8
  116. package/foehn-icons/foehn-icon-external-link-alt.component.d.ts +0 -8
  117. package/foehn-icons/foehn-icon-file-pdf.component.d.ts +0 -8
  118. package/foehn-icons/foehn-icon-info-circle.component.d.ts +0 -8
  119. package/foehn-icons/foehn-icon-lock.component.d.ts +0 -8
  120. package/foehn-icons/foehn-icon-map-marker.component.d.ts +0 -8
  121. package/foehn-icons/foehn-icon-minus-circle.component.d.ts +0 -8
  122. package/foehn-icons/foehn-icon-pencil.component.d.ts +0 -8
  123. package/foehn-icons/foehn-icon-plus-circle.component.d.ts +0 -8
  124. package/foehn-icons/foehn-icon-plus-square.component.d.ts +0 -8
  125. package/foehn-icons/foehn-icon-search.component.d.ts +0 -8
  126. package/foehn-icons/foehn-icon-times.component.d.ts +0 -8
  127. package/foehn-icons/foehn-icon-trash-alt.component.d.ts +0 -8
  128. package/foehn-icons/foehn-icon-unlock-alt.component.d.ts +0 -8
  129. package/foehn-icons/foehn-icon-user.component.d.ts +0 -8
  130. package/foehn-icons/foehn-icons.module.d.ts +0 -31
  131. package/foehn-input/foehn-input-email.component.d.ts +0 -15
  132. package/foehn-input/foehn-input-hidden.component.d.ts +0 -14
  133. package/foehn-input/foehn-input-number.component.d.ts +0 -42
  134. package/foehn-input/foehn-input-password.component.d.ts +0 -12
  135. package/foehn-input/foehn-input-phone.component.d.ts +0 -25
  136. package/foehn-input/foehn-input-prefixed-text.component.d.ts +0 -26
  137. package/foehn-input/foehn-input-string.component.d.ts +0 -9
  138. package/foehn-input/foehn-input-text.component.d.ts +0 -11
  139. package/foehn-input/foehn-input-textarea.component.d.ts +0 -22
  140. package/foehn-input/foehn-input.component.d.ts +0 -127
  141. package/foehn-input/foehn-input.module.d.ts +0 -24
  142. package/foehn-input/pattern.const.d.ts +0 -11
  143. package/foehn-input-date/foehn-input-date.component.d.ts +0 -33
  144. package/foehn-input-date-time/foehn-input-date-time.component.d.ts +0 -40
  145. package/foehn-input-time/foehn-input-time.component.d.ts +0 -19
  146. package/foehn-list/foehn-list.component.d.ts +0 -27
  147. package/foehn-list/foehn-list.module.d.ts +0 -9
  148. package/foehn-list/page-change-event.d.ts +0 -5
  149. package/foehn-menu-prestation/abstract-list-item-detail-page.component.d.ts +0 -35
  150. package/foehn-menu-prestation/abstract-menu-page.component.d.ts +0 -13
  151. package/foehn-menu-prestation/abstract-page-from-menu.component.d.ts +0 -20
  152. package/foehn-menu-prestation/foehn-error-pill/foehn-error-pill.component.d.ts +0 -12
  153. package/foehn-menu-prestation/foehn-list-summary/foehn-list-item-description.d.ts +0 -6
  154. package/foehn-menu-prestation/foehn-list-summary/foehn-list-item.d.ts +0 -5
  155. package/foehn-menu-prestation/foehn-list-summary/foehn-list-summary.component.d.ts +0 -40
  156. package/foehn-menu-prestation/foehn-menu-items/foehn-menu-item/foehn-menu-item.component.d.ts +0 -16
  157. package/foehn-menu-prestation/foehn-menu-items/foehn-menu-item-transmit/foehn-menu-item-transmit.component.d.ts +0 -23
  158. package/foehn-menu-prestation/foehn-menu-prestation.module.d.ts +0 -18
  159. package/foehn-misc/foehn-abbr.component.d.ts +0 -7
  160. package/foehn-misc/foehn-misc.module.d.ts +0 -7
  161. package/foehn-modal/foehn-modal.component.d.ts +0 -24
  162. package/foehn-modal/foehn-modal.module.d.ts +0 -11
  163. package/foehn-multiselect-autocomplete/foehn-multiselect-autocomplete.component.d.ts +0 -54
  164. package/foehn-multiselect-autocomplete/foehn-multiselect-autocomplete.module.d.ts +0 -13
  165. package/foehn-nav13/foehn-input-nav13.component.d.ts +0 -20
  166. package/foehn-nav13/foehn-input-nav13.module.d.ts +0 -11
  167. package/foehn-navigation/abstract-foehn-navigation.component.d.ts +0 -19
  168. package/foehn-navigation/foehn-navigation/foehn-navigation.component.d.ts +0 -22
  169. package/foehn-navigation/foehn-navigation.module.d.ts +0 -13
  170. package/foehn-navigation/foehn-navigation.service.d.ts +0 -69
  171. package/foehn-navigation/foehn-simple-navigation/foehn-simple-navigation.component.d.ts +0 -8
  172. package/foehn-notfound/foehn-notfound.component.d.ts +0 -19
  173. package/foehn-notfound/foehn-notfound.module.d.ts +0 -10
  174. package/foehn-page/foehn-page-counter.component.d.ts +0 -15
  175. package/foehn-page/foehn-page-expiration-timer/current-session-expiration.d.ts +0 -5
  176. package/foehn-page/foehn-page-expiration-timer/demande-expiration-interceptor.d.ts +0 -15
  177. package/foehn-page/foehn-page-expiration-timer/demande-expiration.service.d.ts +0 -16
  178. package/foehn-page/foehn-page-expiration-timer/foehn-page-expiration-timer.component.d.ts +0 -36
  179. package/foehn-page/foehn-page-expiration-timer/interval.helper.d.ts +0 -3
  180. package/foehn-page/foehn-page-modal.component.d.ts +0 -23
  181. package/foehn-page/foehn-page-modal.service.d.ts +0 -12
  182. package/foehn-page/foehn-page.component.d.ts +0 -80
  183. package/foehn-page/foehn-page.module.d.ts +0 -24
  184. package/foehn-page/foehn-page.service.d.ts +0 -19
  185. package/foehn-page/foehn-transmit-waiting-modal/demande-transmit-interceptor.d.ts +0 -16
  186. package/foehn-page/foehn-transmit-waiting-modal/foehn-transmit-waiting-modal.component.d.ts +0 -11
  187. package/foehn-page/foehn-transmit-waiting-modal/foehn-transmit-waiting-modal.service.d.ts +0 -11
  188. package/foehn-recap-section/foehn-recap-section.component.d.ts +0 -21
  189. package/foehn-recap-section/foehn-recap-section.module.d.ts +0 -10
  190. package/foehn-recap-section/foehn-recap-section.type.d.ts +0 -17
  191. package/foehn-remaining-alerts-summary/foehn-remaining-alerts-summary.component.d.ts +0 -20
  192. package/foehn-remaining-alerts-summary/foehn-remaining-alerts-summary.module.d.ts +0 -8
  193. package/foehn-status-progress-bar/foehn-status-progress-bar.component.d.ts +0 -23
  194. package/foehn-status-progress-bar/foehn-status-progress-bar.module.d.ts +0 -10
  195. package/foehn-table/foehn-table-column-configuration.d.ts +0 -14
  196. package/foehn-table/foehn-table-page-change-event.d.ts +0 -5
  197. package/foehn-table/foehn-table.component.d.ts +0 -40
  198. package/foehn-table/foehn-table.module.d.ts +0 -13
  199. package/foehn-table/row-element.type.d.ts +0 -4
  200. package/foehn-table/tableSort.d.ts +0 -4
  201. package/foehn-upload/abstract-foehn-uploader.component.d.ts +0 -68
  202. package/foehn-upload/document-reference.d.ts +0 -12
  203. package/foehn-upload/foehn-bo-multi-upload/bo-multi-upload.service.d.ts +0 -27
  204. package/foehn-upload/foehn-bo-multi-upload/bo-multi-upload.type.d.ts +0 -11
  205. package/foehn-upload/foehn-bo-multi-upload/foehn-bo-multi-upload.component.d.ts +0 -38
  206. package/foehn-upload/foehn-bo-multi-upload/foehn-bo-multi-upload.module.d.ts +0 -13
  207. package/foehn-upload/foehn-multi-upload/foehn-multi-upload.component.d.ts +0 -42
  208. package/foehn-upload/foehn-multi-upload/foehn-multi-upload.module.d.ts +0 -13
  209. package/foehn-upload/foehn-multi-upload/multi-upload.service.d.ts +0 -29
  210. package/foehn-upload/foehn-multi-upload/multi-upload.type.d.ts +0 -11
  211. package/foehn-upload/foehn-multi-upload/pending-upload.service.d.ts +0 -26
  212. package/foehn-upload/foehn-picture-upload/foehn-picture-upload.component.d.ts +0 -38
  213. package/foehn-upload/foehn-picture-upload/foehn-picture-upload.module.d.ts +0 -14
  214. package/foehn-upload/foehn-upload-progress-bar/foehn-upload-progress-bar.component.d.ts +0 -22
  215. package/foehn-upload/foehn-upload-progress-bar/foehn-upload-progress-bar.module.d.ts +0 -11
  216. package/foehn-upload/foehn-upload-progress-bar/upload-progress.service.d.ts +0 -19
  217. package/foehn-upload/foehn-upload-progress-bar/upload-progress.type.d.ts +0 -6
  218. package/foehn-upload/page-upload-limit.service.d.ts +0 -22
  219. package/foehn-upload/pending-upload.type.d.ts +0 -9
  220. package/foehn-upload/uploader.helper.d.ts +0 -66
  221. package/foehn-user-connected-as/foehn-user-connected-as.component.d.ts +0 -12
  222. package/foehn-user-connected-as/foehn-user-connected-as.module.d.ts +0 -9
  223. package/foehn-validation-alert-summary/foehn-validation-alert-summary.component.d.ts +0 -20
  224. package/foehn-validation-alert-summary/foehn-validation-alert-summary.module.d.ts +0 -9
  225. package/foehn-validation-alerts/foehn-validation-alerts.component.d.ts +0 -14
  226. package/foehn-validation-alerts/foehn-validation-alerts.module.d.ts +0 -8
  227. package/form-error.d.ts +0 -5
  228. package/form-post-response.d.ts +0 -19
  229. package/gesdem/gesdem-error-handler.service.d.ts +0 -22
  230. package/gesdem/gesdem-event.service.d.ts +0 -16
  231. package/gesdem/gesdem-handler.service.d.ts +0 -52
  232. package/gesdem/gesdem-loader.guard.d.ts +0 -2
  233. package/gesdem/gesdem-statut-utils.d.ts +0 -12
  234. package/gesdem-action-recovery/gesdem-action-recovery-login/gesdem-action-recovery-login.component.d.ts +0 -39
  235. package/gesdem-action-recovery/gesdem-action-recovery-registration/gesdem-action-recovery-registration.component.d.ts +0 -59
  236. package/gesdem-action-recovery/gesdem-action-recovery.module.d.ts +0 -17
  237. package/gesdem-action-recovery/gesdem-action-recovery.service.d.ts +0 -24
  238. package/gesdem-action-recovery/reprise-info.d.ts +0 -6
  239. package/gesdem-confirmation/gesdem-confirmation.component.d.ts +0 -65
  240. package/gesdem-confirmation/gesdem-confirmation.module.d.ts +0 -12
  241. package/gesdem-error/gesdem-error.component.d.ts +0 -34
  242. package/gesdem-error/gesdem-error.module.d.ts +0 -12
  243. package/global.const.d.ts +0 -1
  244. package/helpers/demande.helper.d.ts +0 -3
  245. package/helpers/object.helper.d.ts +0 -30
  246. package/i18n-form.d.ts +0 -5
  247. package/index.d.ts +0 -5
  248. package/pipes/currency.pipe.d.ts +0 -10
  249. package/pipes/date.pipe.d.ts +0 -12
  250. package/pipes/formatIde.pipe.d.ts +0 -7
  251. package/pipes/pipes.module.d.ts +0 -9
  252. package/prestations-ng-core.module.d.ts +0 -12
  253. package/public-api.d.ts +0 -238
  254. package/refinf/model/address-type-light.d.ts +0 -5
  255. package/refinf/model/canton.d.ts +0 -4
  256. package/refinf/model/district.d.ts +0 -7
  257. package/refinf/model/municipality.d.ts +0 -9
  258. package/refinf/model/place-of-origin.d.ts +0 -9
  259. package/refinf/model/postal-locality.d.ts +0 -11
  260. package/sdk-appinfo/application-info.d.ts +0 -61
  261. package/sdk-appinfo/application-info.service.d.ts +0 -32
  262. package/sdk-currency/currency.helper.d.ts +0 -9
  263. package/sdk-date/date.helper.d.ts +0 -20
  264. package/sdk-dictionary/default-dictionary.d.ts +0 -2
  265. package/sdk-dictionary/sdk-dictionary.module.d.ts +0 -7
  266. package/sdk-dictionary/sdk-dictionary.pipe.d.ts +0 -12
  267. package/sdk-dictionary/sdk-dictionary.service.d.ts +0 -44
  268. package/sdk-drafts/draft.model.d.ts +0 -5
  269. package/sdk-drafts/drafts-container.component.d.ts +0 -33
  270. package/sdk-drafts/drafts.module.d.ts +0 -14
  271. package/sdk-drafts/drafts.service.d.ts +0 -20
  272. package/sdk-epayment/model/EPaymentParameters.d.ts +0 -21
  273. package/sdk-epayment/pending-payment/pending-payment.component.d.ts +0 -9
  274. package/sdk-epayment/sdk-epayment.component.d.ts +0 -33
  275. package/sdk-epayment/sdk-epayment.module.d.ts +0 -11
  276. package/sdk-epayment/sdk-epayment.service.d.ts +0 -21
  277. package/sdk-events-logger/sdk-event-type.d.ts +0 -12
  278. package/sdk-events-logger/sdk-event.d.ts +0 -8
  279. package/sdk-events-logger/sdk-events-logger.service.d.ts +0 -18
  280. package/sdk-recaptcha/grecaptcha/grecaptcha.component.d.ts +0 -39
  281. package/sdk-recaptcha/recaptcha.service.d.ts +0 -44
  282. package/sdk-recaptcha/sdk-recaptcha.component.d.ts +0 -27
  283. package/sdk-recaptcha/sdk-recaptcha.module.d.ts +0 -9
  284. package/sdk-redirect/iam-expired-interceptor.service.d.ts +0 -12
  285. package/sdk-redirect/redirect.component.d.ts +0 -22
  286. package/sdk-redirect/sdk-redirect.module.d.ts +0 -9
  287. package/sdk-session-info/session-info-data.d.ts +0 -29
  288. package/sdk-session-info/session-info-with-application.service.d.ts +0 -20
  289. package/sdk-session-info/session-info.service.d.ts +0 -17
  290. package/sdk-statistics/sdk-statistics.service.d.ts +0 -24
  291. package/sdk-support-alert/support-alert-container.component.d.ts +0 -20
  292. package/sdk-support-alert/support-alert.component.d.ts +0 -12
  293. package/sdk-support-alert/support-alert.model.d.ts +0 -12
  294. package/sdk-support-alert/support-alert.module.d.ts +0 -10
  295. package/sdk-support-alert/support-alert.service.d.ts +0 -34
  296. package/service-locator.d.ts +0 -4
  297. package/supported-browser.d.ts +0 -1
  298. package/validation/validation-handler.service.d.ts +0 -15
@@ -0,0 +1,856 @@
1
+ # Angular Signals — Migration Guide
2
+
3
+ ## Table of contents
4
+
5
+ - [Overview](angular-signals#overview)
6
+ - [Core primitives](angular-signals#core_primitives)
7
+ - [computed()](angular-signals#_code_computed____code_)
8
+ - [effect()](angular-signals#_code_effect____code_)
9
+ - [untracked()](angular-signals#_code_untracked____code_)
10
+ - [linkedSignal()](angular-signals#_code_linkedsignal____code_)
11
+ - [input() and model()](angular-signals#_code_input____code__and__code_model____code_)
12
+ - [viewChildren() and viewChild()](angular-signals#_code_viewchildren____code__and__code_viewchild____code_)
13
+ - [Mental model — computed() vs effect()](angular-signals#mental_model____code_computed____code__vs__code_effect____code_)
14
+ - [Migration patterns](angular-signals#migration_patterns)
15
+ - [Inheritance caveat](angular-signals#inheritance_caveat)
16
+ - [Testing signals](angular-signals#testing_signals)
17
+ - [Common pitfalls](angular-signals#common_pitfalls)
18
+
19
+ ---
20
+
21
+ ## Overview
22
+
23
+ Angular Signals are a reactive primitive introduced to replace zone-based
24
+ change detection with a fine-grained, declarative reactivity model.
25
+ The goal is to make data flow explicit, predictable, and performant.
26
+
27
+ ```ts
28
+ import { signal, computed, effect, untracked } from '@angular/core';
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Core primitives
34
+
35
+ ### `signal()`
36
+
37
+ A writable reactive value. Reading it inside a reactive context (template,
38
+ `computed`, `effect`) creates a dependency automatically.
39
+
40
+ ```ts
41
+ readonly count = signal(0);
42
+
43
+ increment(): void {
44
+ this.count.update(v => v + 1);
45
+ // or
46
+ this.count.set(5);
47
+ }
48
+ ```
49
+
50
+ | Method | Description |
51
+ | ------------- | --------------------------------- |
52
+ | `.set(value)` | Replace the value |
53
+ | `.update(fn)` | Derive next value from current |
54
+ | `.mutate(fn)` | Mutate in place (arrays, objects) |
55
+
56
+ ---
57
+
58
+ ## `computed()`
59
+
60
+ A **read-only derived signal**. Re-evaluates only when one of its dependencies
61
+ changes. Lazy and memoized.
62
+
63
+ ```ts
64
+ readonly minYear = computed(() => this.minDate()?.[0] ?? dayjs().year() - 100);
65
+ readonly fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
66
+ readonly isValid = computed(() => this.value() >= this.min() && this.value() <= this.max());
67
+ ```
68
+
69
+ ### Rules
70
+
71
+ - Pure and synchronous — no side effects
72
+ - Never call `.set()` inside a `computed()`
73
+ - Dependencies are tracked automatically — no need to declare them
74
+
75
+ ### When `computed()` replaces imperative code
76
+
77
+ Before — manual update in a setter:
78
+
79
+ ```ts
80
+ @Input()
81
+ set minDate(value: number[]) {
82
+ this._minDate = value;
83
+ if (value?.length) {
84
+ this.minYear = value[0]; // manual sync
85
+ }
86
+ }
87
+ ```
88
+
89
+ After — declarative derivation:
90
+
91
+ ```ts
92
+ readonly minDate = input<number[]>();
93
+ readonly minYear = computed(() => this.minDate()?.[0] ?? dayjs().year() - 100);
94
+ ```
95
+
96
+ ---
97
+
98
+ ## `effect()`
99
+
100
+ Runs a **side effect** whenever its signal dependencies change.
101
+ Use it to synchronize signals with the outside world.
102
+
103
+ ```ts
104
+ effect(() => {
105
+ localStorage.setItem('theme', this.theme());
106
+ });
107
+
108
+ effect(() => {
109
+ this.externalHelper.value = this.mySignal();
110
+ });
111
+ ```
112
+
113
+ ### Rules
114
+
115
+ - Runs at least once on initialization
116
+ - Avoid calling `.set()` on signals inside an effect — use `computed()` instead
117
+ - Registered in the constructor injection context by default
118
+ - Cleaned up automatically when the component is destroyed
119
+ - Only signals read **without** `untracked()` become dependencies — see
120
+ [`untracked()`](angular-signals#_code_untracked____code_) below for reading
121
+ a signal inside an effect without subscribing to it
122
+
123
+ ### Tracking the previous value
124
+
125
+ `effect()` does not provide a previous value out of the box.
126
+ Use a plain class field to capture it:
127
+
128
+ ```ts
129
+ private previousIsVisible = false;
130
+
131
+ private readonly visibilityEffect = effect(() => {
132
+ const current = this.isVisible();
133
+ const previous = this.previousIsVisible;
134
+
135
+ if (!previous && current) {
136
+ this.onOpen();
137
+ }
138
+
139
+ this.previousIsVisible = current;
140
+ });
141
+ ```
142
+
143
+ ---
144
+
145
+ ## `untracked()`
146
+
147
+ `untracked()` lets you read a signal's value **inside a reactive context**
148
+ (`effect()`, `computed()`) **without** registering it as a dependency.
149
+ This is the main tool for controlling exactly which signals an `effect()`
150
+ reacts to, when the effect's body needs to read more state than it should
151
+ actually react to.
152
+
153
+ ```ts
154
+ import { untracked } from '@angular/core';
155
+
156
+ effect(() => {
157
+ const id = this.userId(); // tracked — effect re-runs when this changes
158
+ const config = untracked(() => this.appConfig()); // read, but not tracked
159
+
160
+ this.analytics.logUserView(id, config);
161
+ });
162
+ ```
163
+
164
+ ### Why this matters
165
+
166
+ An `effect()` automatically tracks **every** signal it reads during its
167
+ synchronous execution. Sometimes that's too broad: you only want the effect
168
+ to re-run for a subset of the signals it touches, and reading the rest is
169
+ just "give me the current value, don't subscribe me to it."
170
+
171
+ This is especially common when an effect needs to read the **same signal it
172
+ is about to write to** (directly or via a method that writes to it).
173
+ Reading it without `untracked()` can cause the effect to register itself as
174
+ its own dependency, leading to redundant re-runs or, in more complex chains,
175
+ an infinite loop.
176
+
177
+ ```ts
178
+ // 🔴 Risky — `this.value()` is read in the same effect that may end up
179
+ // triggering a write back to `value`, depending on what updateNgModel does
180
+ effect(() => {
181
+ this.showLine1();
182
+ this.showLine2();
183
+
184
+ const current = this.value(); // tracked unintentionally
185
+ const sanitized = this.sanitize(current);
186
+
187
+ if (sanitized !== current) {
188
+ this.updateNgModel(sanitized); // writes back to `value`
189
+ }
190
+ });
191
+
192
+ // 🟢 Safe — only the visibility signals are tracked;
193
+ // `value` is read but not subscribed to
194
+ effect(() => {
195
+ this.showLine1();
196
+ this.showLine2();
197
+
198
+ const current = untracked(() => this.value());
199
+ const sanitized = this.sanitize(current);
200
+
201
+ if (sanitized !== current) {
202
+ this.updateNgModel(sanitized);
203
+ }
204
+ });
205
+ ```
206
+
207
+ In the safe version, the effect's dependency list is exactly
208
+ `[showLine1, showLine2]`. Writing to `value` inside the effect body no longer
209
+ risks the effect re-triggering itself purely because it also happened to read
210
+ `value()` reactively.
211
+
212
+ ### Other common uses
213
+
214
+ Reading a signal for one-off, non-reactive logic inside a `computed()`:
215
+
216
+ ```ts
217
+ readonly summary = computed(() => {
218
+ const items = this.items();
219
+ // logging shouldn't be a reason for `summary` to be considered "stale"
220
+ untracked(() => console.debug('recomputing summary', items.length));
221
+ return items.length;
222
+ });
223
+ ```
224
+
225
+ Calling an imperative API (router, third-party widget, focus management)
226
+ that internally reads signals, without wanting those internal reads to
227
+ become dependencies of your effect:
228
+
229
+ ```ts
230
+ effect(() => {
231
+ const open = this.isVisible();
232
+ if (open) {
233
+ untracked(() => this.focusManager.focusDefaultElement());
234
+ }
235
+ });
236
+ ```
237
+
238
+ ### Rules
239
+
240
+ - `untracked()` does not prevent the read — it only prevents the
241
+ **dependency tracking** of that read
242
+ - Use it when an effect or computed needs a signal's current value for
243
+ logic, but should not re-run merely because that signal changed
244
+ - A frequent signal that you need `untracked()`: an `effect()` that reads
245
+ and then conditionally writes back to the **same** signal — read the
246
+ current value with `untracked()`, keep the write outside of it
247
+ - Do not reach for `untracked()` as a substitute for an equality check;
248
+ it controls _what triggers_ the effect, not _whether the write is a no-op_.
249
+ Combine both when guarding against redundant or looping writes
250
+
251
+ ---
252
+
253
+ ## `linkedSignal()`
254
+
255
+ A **writable signal** whose value resets automatically when a source signal
256
+ changes. It fills the gap between `computed()` (read-only) and `signal()`
257
+ (no automatic sync with a source).
258
+
259
+ ```ts
260
+ import { linkedSignal } from '@angular/core';
261
+
262
+ readonly options = input<string[]>([]);
263
+
264
+ readonly selectedOption = linkedSignal(() => this.options()[0]);
265
+ ```
266
+
267
+ Whenever `options` changes, `selectedOption` resets to the first item.
268
+ But the user (or the component) can still write to it in the meantime:
269
+
270
+ ```ts
271
+ this.selectedOption.set('other value'); // works, until options changes again
272
+ ```
273
+
274
+ ---
275
+
276
+ ### When to use `linkedSignal()`
277
+
278
+ | Scenario | Tool |
279
+ | --------------------------------------------- | ---------------- |
280
+ | Read-only derivation, never written locally | `computed()` |
281
+ | Local state that resets when a source changes | `linkedSignal()` |
282
+ | Two-way binding with parent | `model()` |
283
+ | Independent local state | `signal()` |
284
+
285
+ ---
286
+
287
+ ### Full form — source + computation
288
+
289
+ The short form `linkedSignal(() => source())` is sugar for the full form,
290
+ which gives you access to the **previous value** of the linked signal:
291
+
292
+ ```ts
293
+ readonly selectedOption = linkedSignal<string[], string>({
294
+ source: this.options,
295
+ computation: (newOptions, previous) => {
296
+ // If the previously selected option still exists in the new list, keep it
297
+ if (previous && newOptions.includes(previous.value)) {
298
+ return previous.value;
299
+ }
300
+ return newOptions[0];
301
+ },
302
+ });
303
+ ```
304
+
305
+ `previous` contains `{ value: T }` — the last value of the linked signal
306
+ before the source changed, or `undefined` on first run.
307
+
308
+ ---
309
+
310
+ ### Migration pattern — setter with local state reset
311
+
312
+ A common pattern before signals was a setter that reset local state
313
+ when an input changed:
314
+
315
+ ```ts
316
+ // Before
317
+ private _options: string[] = [];
318
+ selectedOption: string;
319
+
320
+ @Input()
321
+ set options(value: string[]) {
322
+ this._options = value;
323
+ this.selectedOption = value[0]; // reset local selection
324
+ }
325
+ ```
326
+
327
+ After — `linkedSignal()` expresses this declaratively:
328
+
329
+ ```ts
330
+ // After
331
+ readonly options = input<string[]>([]);
332
+ readonly selectedOption = linkedSignal(() => this.options()[0]);
333
+ ```
334
+
335
+ ---
336
+
337
+ ### Red flag — `effect()` resetting a `signal()`
338
+
339
+ If you find yourself writing an `effect()` that resets a plain `signal()`
340
+ when another signal changes, that is a `linkedSignal()` in disguise:
341
+
342
+ ```ts
343
+ // 🔴 Bad
344
+ readonly selectedOption = signal('');
345
+
346
+ private readonly resetEffect = effect(() => {
347
+ this.selectedOption.set(this.options()[0]);
348
+ });
349
+
350
+ // 🟢 What it really is
351
+ readonly selectedOption = linkedSignal(() => this.options()[0]);
352
+ ```
353
+
354
+ ---
355
+
356
+ ## `input()` and `model()`
357
+
358
+ ### `input()`
359
+
360
+ Replaces `@Input()` for one-way parent → child binding.
361
+
362
+ ```ts
363
+ // Before
364
+ @Input() closeable = true;
365
+
366
+ // After
367
+ readonly closeable = input(true);
368
+ ```
369
+
370
+ With a default value and a type:
371
+
372
+ ```ts
373
+ readonly minYear = input<number>(dayjs().year() - 100);
374
+ ```
375
+
376
+ ### `model()`
377
+
378
+ Replaces `@Input()` + `@Output()` pairs for **two-way binding**.
379
+ Automatically creates the corresponding `Change` output.
380
+
381
+ ```ts
382
+ // Before
383
+ @Input() isVisible = false;
384
+ @Output() isVisibleChange = new EventEmitter<boolean>();
385
+
386
+ // After
387
+ readonly isVisible = model(false);
388
+ ```
389
+
390
+ Usage in a parent template:
391
+
392
+ ```html
393
+ <!-- two-way -->
394
+ <my-component [(isVisible)]="open" />
395
+
396
+ <!-- one-way — will cause a compiler error with model() -->
397
+ <my-component [isVisible]="open" />
398
+ ```
399
+
400
+ > ⚠️ `model()` does not accept one-way `[binding]` alone.
401
+ > Use `input()` if the child never needs to write back to the parent.
402
+
403
+ > ⚠️ `model()` holds object values by reference. Mutating a nested property
404
+ > of a `model()`'s value (e.g. `this.address().locality.name = 'x'`) does
405
+ > **not** notify the signal or the parent binding. Always `.set()` or
406
+ > `.update()` with a new top-level reference:
407
+ > `this.address.update(current => ({ ...current, locality: newLocality }))`.
408
+
409
+ ### Choosing between `input()` and `model()`
410
+
411
+ | Scenario | Tool |
412
+ | -------------------------------- | ------------ |
413
+ | Parent writes, child only reads | `input()` |
414
+ | Parent writes, child writes back | `model()` |
415
+ | Derived from other inputs | `computed()` |
416
+
417
+ ### `input()` with alias — ESLint caveat
418
+
419
+ If you need an internal name different from the public binding name,
420
+ use the `alias` option. Note that `@angular-eslint/no-input-rename` will
421
+ flag this — disable it locally only when strictly necessary:
422
+
423
+ ```ts
424
+ // eslint-disable-next-line @angular-eslint/no-input-rename
425
+ readonly minYearInput = input<number>(dayjs().year() - 100, { alias: 'minYear' });
426
+ ```
427
+
428
+ Prefer renaming the property to match the alias whenever possible.
429
+
430
+ ---
431
+
432
+ ## `viewChildren()` and `viewChild()`
433
+
434
+ Replaces `@ViewChildren` and `@ViewChild` with signal-based queries.
435
+
436
+ ```ts
437
+ // Before
438
+ @ViewChildren('dayButtonElemRef') daysButtons: QueryList<ElementRef>;
439
+
440
+ // After
441
+ readonly daysButtons = viewChildren<ElementRef>('dayButtonElemRef');
442
+ ```
443
+
444
+ The signal returns a `readonly T[]` — always guard against empty arrays:
445
+
446
+ ```ts
447
+ const enabled = [...(this.daysButtons() ?? [])].filter(
448
+ (el) => el.nativeElement.getAttribute('disabled') === null,
449
+ );
450
+ ```
451
+
452
+ Reacting to changes — use `effect()`:
453
+
454
+ ```ts
455
+ private readonly daysEffect = effect(() => {
456
+ const buttons = this.daysButtons();
457
+ if (buttons.length > 0) {
458
+ this.changeDetector.detectChanges();
459
+ }
460
+ this.helper.buttons = buttons;
461
+ });
462
+ ```
463
+
464
+ ---
465
+
466
+ ## Mental model — `computed()` vs `effect()`
467
+
468
+ > **"Am I calculating something, or am I doing something?"**
469
+
470
+ | Intent | Tool |
471
+ | ------------------------- | ------------ |
472
+ | Transform data | `computed()` |
473
+ | Derive state | `computed()` |
474
+ | Synchronize with the DOM | `effect()` |
475
+ | Drive an external service | `effect()` |
476
+ | Log, track | `effect()` |
477
+
478
+ ### The red flag
479
+
480
+ If you find yourself writing an `effect()` that calls `.set()` on another signal,
481
+ it is almost always a `computed()` in disguise:
482
+
483
+ ```ts
484
+ // 🔴 Bad — effect producing a value
485
+ effect(() => {
486
+ this.minYear.set(this.minDate()?.[0] ?? dayjs().year() - 100);
487
+ });
488
+
489
+ // 🟢 What it really is
490
+ readonly minYear = computed(() => this.minDate()?.[0] ?? dayjs().year() - 100);
491
+ ```
492
+
493
+ > 💡 If the effect genuinely needs to remain an `effect()` (e.g. it also
494
+ > performs a non-signal side effect like calling a service), but reads a
495
+ > signal purely for context rather than as a trigger, reach for
496
+ > [`untracked()`](angular-signals#_code_untracked____code_) instead of
497
+ > restructuring into a `computed()`.
498
+
499
+ ---
500
+
501
+ ## Migration patterns
502
+
503
+ ### Pattern 1 — Simple `@Input()` → `input()`
504
+
505
+ ```ts
506
+ // Before
507
+ @Input() id: string;
508
+
509
+ // After
510
+ readonly id = input<string>();
511
+ ```
512
+
513
+ ### Pattern 2 — `@Input()` with setter → `input()` + `computed()`
514
+
515
+ When the setter only derived a value:
516
+
517
+ ```ts
518
+ // Before
519
+ @Input()
520
+ set minDate(value: number[]) {
521
+ this._minDate = value;
522
+ if (value?.length) this.minYear = value[0];
523
+ }
524
+
525
+ // After
526
+ readonly minDate = input<number[]>();
527
+ readonly minYear = computed(() => this.minDate()?.[0] ?? dayjs().year() - 100);
528
+ ```
529
+
530
+ When the setter triggered side effects:
531
+
532
+ ```ts
533
+ // Before
534
+ @Input()
535
+ set isVisible(val: boolean) {
536
+ this._isVisible = val;
537
+ this.isVisibleChange.emit(val);
538
+ this.focusDefaultDay();
539
+ }
540
+
541
+ // After
542
+ readonly isVisible = model(false);
543
+
544
+ private readonly isVisibleEffect = effect(() => {
545
+ const val = this.isVisible();
546
+ this.focusDefaultDay();
547
+ });
548
+ ```
549
+
550
+ ### Pattern 3 — `@Input()` + `@Output()` pair → `model()`
551
+
552
+ ```ts
553
+ // Before
554
+ @Input() value: boolean;
555
+ @Output() valueChange = new EventEmitter<boolean>();
556
+
557
+ // After
558
+ readonly value = model(false);
559
+
560
+ // Writing back from inside the component
561
+ this.value.set(false); // automatically emits valueChange
562
+ ```
563
+
564
+ ### Pattern 4 — `@ViewChildren` → `viewChildren()`
565
+
566
+ ```ts
567
+ // Before
568
+ @ViewChildren('ref') items: QueryList<ElementRef>;
569
+
570
+ ngAfterViewInit(): void {
571
+ this.items.changes.subscribe(list => this.helper.items = list);
572
+ }
573
+
574
+ // After
575
+ readonly items = viewChildren<ElementRef>('ref');
576
+
577
+ private readonly itemsEffect = effect(() => {
578
+ this.helper.items = this.items();
579
+ });
580
+ ```
581
+
582
+ ### Pattern 5 — Multiple trigger signals with a guarded re-sanitization
583
+
584
+ A common case in components with several "visibility" or "feature flag"
585
+ signals: you need to re-run some sanitization logic whenever **any** of
586
+ several signals change, but the logic also reads and conditionally rewrites
587
+ a `model()` value. Track only the trigger signals, read the model value with
588
+ `untracked()`, and guard the write with an equality check to avoid loops:
589
+
590
+ ```ts
591
+ readonly showLine1 = input(true);
592
+ readonly showLine2 = input(true);
593
+ readonly value = model<Address>();
594
+
595
+ private readonly sanitizeEffect = effect(() => {
596
+ // tracked dependencies
597
+ const showLine1 = this.showLine1();
598
+ const showLine2 = this.showLine2();
599
+
600
+ // read without subscribing to `value` itself
601
+ const current = untracked(() => this.value());
602
+ if (!current) return;
603
+
604
+ const sanitized: Address = { ...current };
605
+ if (!showLine1) sanitized.addressLine1 = null;
606
+ if (!showLine2) sanitized.addressLine2 = null;
607
+
608
+ if (!this.addressesEqual(sanitized, current)) {
609
+ this.value.set(sanitized);
610
+ }
611
+ });
612
+ ```
613
+
614
+ ---
615
+
616
+ ## Inheritance caveat
617
+
618
+ Signal inputs are **not inherited**. Angular registers them at compile time
619
+ via the `@Component` decorator — TypeScript inheritance alone is not enough.
620
+
621
+ ```ts
622
+ export class BaseComponent {
623
+ readonly isVisible = input<boolean>(false); // ❌ not seen by child's Angular metadata
624
+ }
625
+
626
+ export class ChildComponent extends BaseComponent {
627
+ // isVisible is not recognized as an Angular input here
628
+ }
629
+ ```
630
+
631
+ ### Solutions
632
+
633
+ **Override in the child** — verbose but explicit:
634
+
635
+ ```ts
636
+ export class ChildComponent extends BaseComponent {
637
+ override readonly isVisible = input<boolean>(false);
638
+ }
639
+ ```
640
+
641
+ **Prefer composition over inheritance:**
642
+
643
+ ```ts
644
+ export class ChildComponent {
645
+ readonly isVisible = input<boolean>(false);
646
+ // shared behavior via inject() or a shared service
647
+ }
648
+ ```
649
+
650
+ > ⚠️ This is why the Angular automatic migration tool is conservative around
651
+ > classes that are extended. Always audit your inheritance chain before migrating.
652
+
653
+ ---
654
+
655
+ ## Testing signals
656
+
657
+ ### Setting inputs in tests
658
+
659
+ Use `fixture.componentRef.setInput()` for both `input()` and `model()`:
660
+
661
+ ```ts
662
+ fixture.componentRef.setInput('minDate', [2020, 7, 15]);
663
+ fixture.componentRef.setInput('isVisible', true);
664
+ ```
665
+
666
+ ### Writing to a `model()` from a test
667
+
668
+ ```ts
669
+ component.isVisible.set(true);
670
+ fixture.detectChanges();
671
+ ```
672
+
673
+ ### Reading a signal value in an expectation
674
+
675
+ ```ts
676
+ // 🔴 Wrong — reads the signal object, not the value
677
+ expect(component.isVisible).toBeTrue();
678
+
679
+ // 🟢 Correct — call the signal to read its value
680
+ expect(component.isVisible()).toBeTrue();
681
+ ```
682
+
683
+ ### Effects and timing
684
+
685
+ Effects are asynchronous relative to `detectChanges()`.
686
+ Always use `await fixture.whenStable()` after triggering a signal change
687
+ that runs an effect:
688
+
689
+ ```ts
690
+ component.isVisible.set(true);
691
+ await fixture.whenStable();
692
+ fixture.detectChanges();
693
+ ```
694
+
695
+ When testing behavior triggered by `model()` changes (e.g. focus management),
696
+ reproduce the real toggle rather than calling internal methods directly:
697
+
698
+ ```ts
699
+ // 🔴 Fragile — bypasses the effect
700
+ component.focusDefaultDay();
701
+
702
+ // 🟢 Robust — triggers the full reactive chain
703
+ component.isVisible.set(false);
704
+ await fixture.whenStable();
705
+ component.isVisible.set(true);
706
+ await fixture.whenStable();
707
+ fixture.detectChanges();
708
+ ```
709
+
710
+ ### Testing `untracked()` reads
711
+
712
+ `untracked()` is invisible to the test from the outside — there's nothing
713
+ to assert about it directly. What you _can_ and should assert is the
714
+ **dependency boundary** it creates: changing the untracked signal alone
715
+ should not cause the effect to re-run.
716
+
717
+ ```ts
718
+ // component reads `this.config` via untracked() inside an effect
719
+ // that is otherwise only triggered by `this.userId`
720
+
721
+ component.config.set({ theme: 'dark' }); // untracked — should NOT trigger the effect
722
+ await fixture.whenStable();
723
+ expect(loggerSpy).not.toHaveBeenCalled();
724
+
725
+ component.userId.set('123'); // tracked — SHOULD trigger the effect
726
+ await fixture.whenStable();
727
+ expect(loggerSpy).toHaveBeenCalledWith('123', { theme: 'dark' });
728
+ ```
729
+
730
+ ---
731
+
732
+ ## Common pitfalls
733
+
734
+ ### 1. Using `model()` where `input()` is enough
735
+
736
+ `model()` implies two-way binding. If the child never writes back,
737
+ use `input()` — it is simpler and communicates intent clearly.
738
+
739
+ ### 2. Using `computed()` where `model()` is needed
740
+
741
+ If the parent and child both need to write a value, `computed()` is read-only
742
+ and will not work. Use `model()`.
743
+
744
+ ### 3. Calling `.set()` inside `computed()`
745
+
746
+ ```ts
747
+ // 🔴 Runtime error
748
+ readonly x = computed(() => {
749
+ this.y.set(this.z() + 1); // forbidden
750
+ return this.z();
751
+ });
752
+ ```
753
+
754
+ ### 4. Forgetting to call signals in templates
755
+
756
+ ```html
757
+ <!-- 🔴 Renders the signal object -->
758
+ {{ mySignal }}
759
+
760
+ <!-- 🟢 Renders the value -->
761
+ {{ mySignal() }}
762
+ ```
763
+
764
+ ### 5. Spreading a `viewChildren()` signal without guarding
765
+
766
+ ```ts
767
+ // 🔴 TypeError if the signal returns undefined during init
768
+ const items = [...this.daysButtons()];
769
+
770
+ // 🟢 Safe
771
+ const items = [...(this.daysButtons() ?? [])];
772
+ ```
773
+
774
+ ### 6. Expecting `[binding]` to work with `model()`
775
+
776
+ `model()` only accepts `[(two-way)]` or the split form
777
+ `[value]="x" (valueChange)="x = $event"`.
778
+ A plain `[binding]` will produce a compiler error.
779
+
780
+ ### 7. Over-tracking inside `effect()` — forgetting `untracked()`
781
+
782
+ An `effect()` tracks **every** signal it reads, not just the ones you
783
+ intended as triggers. Reading a signal "just to get its current value"
784
+ inside an effect still subscribes the effect to it, which can cause:
785
+
786
+ - redundant re-runs when an unrelated signal changes, or
787
+ - infinite loops when the effect reads and then (directly or indirectly)
788
+ writes to the same signal
789
+
790
+ ```ts
791
+ // 🔴 `this.value()` is tracked, even though the intent was just to read
792
+ // the current value before writing a sanitized version of it
793
+ effect(() => {
794
+ const sanitized = this.sanitize(this.value());
795
+ this.value.set(sanitized); // may re-trigger this same effect
796
+ });
797
+
798
+ // 🟢 Read without tracking; only intentional triggers remain tracked
799
+ effect(() => {
800
+ const current = untracked(() => this.value());
801
+ const sanitized = this.sanitize(current);
802
+ if (sanitized !== current) {
803
+ this.value.set(sanitized);
804
+ }
805
+ });
806
+ ```
807
+
808
+ ### 8. Using `untracked()` instead of an equality check
809
+
810
+ `untracked()` controls what _triggers_ an effect — it does not make a write
811
+ inside the effect "safe" by itself. If the effect's only tracked dependencies
812
+ are, say, two visibility flags, and the write always replaces `value` with a
813
+ new object (even when nothing actually changed), the effect can still cause
814
+ unnecessary downstream updates (re-renders, parent `valueChange` emissions,
815
+ form dirty-state changes). Pair `untracked()` with an explicit equality
816
+ check before writing:
817
+
818
+ ```ts
819
+ // 🔴 Always writes a new object, even when sanitization changed nothing
820
+ effect(() => {
821
+ this.showLine1();
822
+ const current = untracked(() => this.value());
823
+ this.value.set({ ...current }); // new reference every time, even if no-op
824
+ });
825
+
826
+ // 🟢 Only writes when the sanitized result actually differs
827
+ effect(() => {
828
+ this.showLine1();
829
+ const current = untracked(() => this.value());
830
+ const sanitized = this.sanitize(current);
831
+ if (!this.isEqual(sanitized, current)) {
832
+ this.value.set(sanitized);
833
+ }
834
+ });
835
+ ```
836
+
837
+ ### 9. Mutating a `model()`'s nested object instead of reassigning
838
+
839
+ This is the signals-era version of "mutating `@Input()` used to work."
840
+ Pre-signals, Zone.js-driven change detection re-read template expressions
841
+ on virtually every async event, so mutating a nested property and letting
842
+ CD "catch it eventually" appeared to work. Signals only propagate on
843
+ `.set()`/`.update()` — mutating `this.address().locality.name = 'x'` is
844
+ invisible to the signal, the template, and any `effect()`/`computed()`
845
+ depending on it.
846
+
847
+ ```ts
848
+ // 🔴 Silent no-op from the signal's perspective
849
+ this.address().locality.name = 'newName';
850
+
851
+ // 🟢 New top-level reference — the signal and bound parent both update
852
+ this.address.update((current) => ({
853
+ ...current,
854
+ locality: { ...current.locality, name: 'newName' },
855
+ }));
856
+ ```