Les questions que vous vous posez dix fois par jour, avec une réponse courte et un lien vers la page qui l’explique en détail. Cherchez par mot ou filtrez par catégorie.
Les principes derrière chaque réponse
- Au plus près de l’usage
Les types, composants et états restent à côté du code qui les utilise ; vous ne les remontez que lorsqu’un nouveau consommateur apparaît.
- Une seule source de vérité
Ce qui peut être calculé est dérivé (
computed), pas stocké. - L’outil le plus simple qui résout le problème
@switchavant les composants dynamiques, un service à base de signals avant NgRx, la duplication avant la mauvaise abstraction. - Immutabilité
De nouvelles références pour de nouvelles données ; les signals et OnPush en dépendent.
Questions et réponses
41 questions sur 41
Composants
7Mon composant est-il smart ou dumb ?
S’il injecte des stores / des API / le Router → smart (page ou conteneur). S’il reçoit tout par des inputs et émet des outputs → dumb. Les pages routées sont smart ; gardez dumb le plus possible du reste.
Smart vs DumbQuand le rendre générique (<T>) ?
Quand vous avez déjà 2 ou 3 usages avec LE MÊME comportement sur des données différentes (tableau, select, liste) et que l’API ne contient aucun terme métier. Sinon, il reste spécifique.
Composants génériques <T>Quand le rendre dynamique ?
Seulement quand vous ne savez pas à la compilation quel composant apparaît (config, CMS, plugins, tableau de bord). Pour 2 à 5 variantes connues, utilisez @switch.
Composants dynamiquesinput + output ou model() ?
model() pour les valeurs de « contrôle » (toggle, slider, onglet actif). input + output quand le parent doit décider/valider, ou que l’événement a un sens (enregistrer, supprimer).
model() — binding bidirectionnelng-content ou ng-template ?
ng-content pour du contenu statique affiché une fois. ng-template quand le contenu doit être créé en lazy, répété, ou recevoir des données (contexte).
Projection de contenuComposant ou directive ?
Directive si vous ajoutez seulement un comportement à un élément existant (tooltip, autofocus). Composant si vous avez votre propre balisage ou vos propres styles.
Directives et composition d’hôteProjection ou inputs pour le contenu ?
Inputs quand le composant contrôle l’apparence (cohérence). Projection quand le parent a besoin d’un balisage libre (dialogues, cartes).
Projection de contenuArchitecture
7Déplacer le composant dans shared ?
Seulement s’il est utilisé MAINTENANT dans 2 fonctionnalités ou plus, n’a aucun terme métier, n’injecte pas de données et se comporte partout pareil. Sinon, il vit dans features/x/ui.
Shared vs featureInterface en ligne ou fichier séparé ?
Utilisée par un seul fichier → en ligne. Type d’input/output → exporté depuis le fichier du composant. Utilisée par plusieurs fichiers d’une fonctionnalité → features/x/models. Entre fonctionnalités → l’API publique du propriétaire.
Interfaces et modèlesFaut-il un DTO distinct du modèle ?
Oui, si l’API suit d’autres conventions, si vous ne la maîtrisez pas, ou si l’interface a des champs dérivés. Non, pour un CRUD simple aux types déjà propres.
Interfaces et modèlesQue met-on dans core ?
Ce qui est utilisé une seule fois au niveau de l’application ou comme infrastructure : auth, layout (shell), ErrorHandler, interceptors, services transversaux.
Structure des dossiersPeut-on importer une fonctionnalité depuis une autre ?
Idéalement non. Communiquez via l’URL, un store dans core, ou shared. Si c’est inévitable : uniquement via l’API publique de l’autre fonctionnalité (index.ts).
Barrels, alias et frontièresDes barrels (index.ts) partout ?
Non. Seulement à la frontière d’une fonctionnalité/bibliothèque, comme API publique. À l’intérieur, importez directement les fichiers.
Barrels, alias et frontièresEnum ou union de strings ?
Union + objet as const. Plus simple, compatible Tree-shaking, facile à parcourir dans les templates.
Interfaces et modèlesÉtat & données
7signal, computed ou linkedSignal ?
signal = état indépendant. computed = dérivé, en lecture seule. linkedSignal = dérivé, mais modifiable (une sélection qui se réinitialise, un brouillon d’un input).
linkedSignal() — état dérivé modifiableQuand utiliser effect() ?
Uniquement pour des effets vers l’extérieur : localStorage, logs, bibliothèques impératives, le DOM. Jamais pour définir un autre signal (→ computed / linkedSignal).
effect() — quand OUI, quand NONSignal ou Observable ?
Signal pour l’état affiché. Observable pour les flux d’événements dans le temps (websocket, drag, opérateurs complexes). Le pont : toSignal / toObservable.
Signals ↔ RxJSComment charger des données depuis le serveur ?
Lectures réactives → httpResource (ou resource / rxResource). Écritures (POST/PUT/DELETE) → HttpClient, puis mise à jour/rechargement de la resource.
resource, rxResource, httpResourceOù conserver l’état ?
Le plus bas possible : composant → store de fonctionnalité (providers sur la route/page) → global (@Service en root). Filtres partageables → l’URL.
State Management avec les SignalsAi-je besoin de NgRx ?
En général non : un service avec des signals suffit. NgRx SignalStore si vous voulez des conventions/plugins ; NgRx Store si vous avez besoin d’un journal d’actions et du time-travel.
State Management avec les SignalsDebounce sur un signal ?
debounced(sig, 300) (v22, expérimental). Dans Signal Forms : la règle debounce() ou l’option debounce de validateHttp.
debounced() — signals différésTemplate
5Méthode, pipe ou computed dans le template ?
computed pour les calculs propres au composant ; une pipe pure pour le formatage réutilisable ; une méthode seulement pour les choses triviales (elle s’exécute à chaque rendu).
Pipes : quand et commentQue tracker dans @for ?
Un id stable (track item.id). $index seulement pour les listes statiques. L’identité (track item) seulement si les objets ne sont pas recréés.
Control Flow : @if, @for, @switchngClass ou [class] ?
[class.x] / [class] : natif, sans import, plus rapide. Migration : ng g @angular/core:ngclass-to-class.
Bindings de classe et de styleQuand utiliser @defer ?
Contenu lourd ou contenu sous la ligne de flottaison (graphiques, commentaires, éditeurs). Pas pour le contenu principal (LCP).
@defer — Lazy Loading dans les templatesCombien de logique dans le template ?
Des expressions simples et @let pour les sous-expressions. Règles métier et calculs sur de grandes listes → computed.
@let et les nouvelles expressions de templateDI
5@Service() ou @Injectable() ?
Nouveau code en v22 : @Service() (singleton auto-provided, inject() uniquement). @Injectable si vous utilisez la DI par constructeur ou devez prendre en charge d’anciennes versions.
inject() et @Service()Où fournir le service ?
Root si l’état doit survivre à la navigation. Route/page pour l’état d’une fonctionnalité. Composant pour une instance par composant (assistant, éditeur).
Providers et hiérarchie des injecteursClasse ou InjectionToken ?
Classe quand vous avez de la logique/des méthodes. InjectionToken pour les valeurs : config, URLs, fonctions, plugins (multi).
InjectionToken et provideX()Une interface pour le service (IUserService) ?
Non. Si vous avez besoin de plusieurs implémentations ou de mocks : une classe abstraite comme token, avec @Service({ factory }) pour l’implémentation par défaut.
inject() et @Service()Service lourd, rarement utilisé ?
injectAsync(() => import(...)) avec prefetch: onIdle (v22).
injectAsync() — services en Lazy LoadingFormulaires & routing
6Signal Forms ou Reactive Forms ?
Nouveaux formulaires en v22 → Signal Forms. Les Reactive existants restent ; vous migrez progressivement avec SignalFormControl / compatForm.
Signal Forms — les basesContrôle personnalisé : FormValueControl ou CVA ?
FormValueControl pour Signal Forms (un model() + des inputs facultatifs). ControlValueAccessor pour Reactive / Template-driven.
Contrôles de formulaire personnalisésResolver ou httpResource ?
Resolver pour des données petites et indispensables. httpResource + skeleton pour les listes et tableaux de bord (navigation instantanée).
Guards et resolverscanMatch ou canActivate ?
canMatch pour les zones restreintes (il ne télécharge pas le chunk). canActivate pour les vérifications à l’entrée d’une route qui existe pour tout le monde.
Guards et resolversRoute séparée ou état dans la page ?
Une route si l’écran a besoin de son propre lien (partageable, bouton retour). État local pour les dialogues, dropdowns, étapes éphémères.
Routing moderne et Lazy LoadingComment lire les paramètres de route ?
withComponentInputBinding() + input() dans le composant routé. Pas d’ActivatedRoute ni de subscribe.
Routing moderne et Lazy LoadingQualité
4Pourquoi l’interface ne se met-elle pas à jour ?
Presque certainement : un champ simple a changé de façon asynchrone (setTimeout, subscribe) dans une application zoneless/OnPush, ou un objet a été muté. Passez aux signals et aux mises à jour immuables.
Change DetectionOù gérer les erreurs ?
Prévisibles → localement (resource.error()). Transversales (401/500) → interceptor. Échec de rendu d’une zone → @boundary. Le reste → ErrorHandler global.
Erreurs : @boundary et ErrorHandlerQue tester, et comment ?
Stores et mappers : tests unitaires, sans DOM. Composants dumb : createComponent + bindings. Pages : faux store + HttpTestingController. Parcours : e2e.
Tests avec VitestMes propres composants sont-ils accessibles ?
Construisez-les sur Angular Aria (headless) : clavier, focus et ARIA corrects ; le style est à vous.
Angular Aria