This content originally appeared on DEV Community and was authored by Romain Geffrault
C'est l'outil que j'aurai aimé avoir pour ne plus perdre de temps à gérer les actions sur une liste de données avec Angular.
Le but est de pouvoir appliqué facilement des actions CRUD sur une entité de la liste ou sur les entités sélectionnés et de tracker les états de chargement.
Bien que ce soit encore un prototype et qu'il faut maintenant que je teste sur le terrain, la solution est:
-✅ Entièrement fonctionnelle
-⚡ 100% déclarative & réactive
-🧠 Type-safe (indispensable pour l'auto-complétion), tous les types sont inférés
-🚀 Performante & optimisée (compatible zoneless)
-🛠️ Facile à prendre en main et super rapide à mettre en place
-🎛️ Personnalisable, qui s'adapte aux cas les plus simples et complexes
-🌀 Bénéficie de la puissance de RxJs
-📭 Pas de boilerplate
-🧼 Pas de memoryleak
Elle permet:
-📊 de connaître l'état de chargement de la liste de données (loading, loaded, error...)
-✍️ d'appliquer une/des actions CRUD et de tracker l'état de chargement de chacune de ces actions sur chaque entité
-🤹♂️ d'appliquer en parallèle les actions sur chaque entité
-🧩 de sélectionner et d'appliquer une action sur l'ensemble des entités sélectionnées, tout en trackant au niveau de chaque entité l'état de chargement
-🧮 d'ajouter des sélecteurs (états dérivés) au niveau de chaque entité et de la liste globale
-🔄 de choisir la stratégie de requête à appliquer pour chaque action (switchMap, exhaustMap, concatMap, mergeMap)
-🧘 préserve l'affichage en cours lors du changement de page
Quand je dis action, cela peut-être un appel API (ex: mettre à jour le nom d'une entité via un appel API UPDATE ou PUT).
Comme tu vas le voir par la suite, je trouve que la porte d'entré pour utilisé cet outil est assez accessible et ne nécessite que quelque connaissances basic en RxJs, au minimum connaître les Subjects.
Si tu n'as pas l'habitude des Subjects, prends 2min pour regarder ce qu'ils font. Ils suffisent pour faire tourner l'outil.
Bref, j'ai créé un outil de server state management. Je l'ai nommé DataListStore et j'en suis très fière.
Voici comment il s'utilise et je serai curieux d'avoir ton avis dessus.
Définir des sources (RxJs), pagination et actions
Ces sources vont servir pour trigger les actions/appels API que l'on va définir.
Grâce à RxJs, ces sources ne nécessitent que d'être des observables et peuvent donc provenir de "stream" existants (état dérivé).
Si tu n'as pas l'habitude avec ce concept, ne t'embête pas avec ça maintenant, les Subject suffiront.
Comment utiliser DataListStore pour afficher une liste de données
Il suffit d'injecter DataListStore comme un service habituel en Angular.
Le store renvoie une fonction, qui attend en paramètre la config du store.
Les paramètres étant entièrement typé, cela est très facile à utiliser grâce à l'auto-complétion.
Pour simplement afficher une liste de données et de connaître son état de chargement (loading, loaded, error), il suffit de lui donner l'appel api pour récupéré la liste de données, ainsi que la source (généralement, c'est la pagination).
Dès la que la source émet une nouvelle valeur, cela va appeler l'api.
A noter qu'il faut aussi ajouter une fonction entityIdSelector
qui permet de savoir comment identifier une entité. Je ne sais pas encore si je vais la garder.
Comment ajouter des actions CRUD et suivre leur état
Ici j'ai ajouté une action (update) qui va s'appliquer au niveau d'une entité.
Il m'a suffit de lier la source de l'action avec l'appel API à effectuer.
Ces actions peuvent être appliquées en parallèle sur différentes entités.
Côté template, il est très facile d'afficher l'état de chargement (loaded, loading, error) pour chaque action appliqué à l'entité.
Pas besoin de se prendre la tête non plus lorsque l'on a besoin d'ajouter plusieurs actions (update, edit, create, put, quoi d'autre update2? ).
Comment ajouter des actions de masse qui s'appliquent sur les entités sélectionnées
Comme pour les actions précédentes il suffit de lié une source qui émets une liste d'entités à un appel API et le tour est joué.
Ici j'ajoute une action qui me permet de supprimer toutes les entités sélectionnées.
On peut voir l'état de chargement au niveau de chaque entité sélectionné.
Simple et efficace non ?
Ajouter des sélecteurs (états dérivées)
J'ai l'impression de me répéter, mais grâce à l'auto-compéltion/typesafety, c'est très simple de les ajouter.
On peut ajouter des sélecteurs au niveau d'une entité mais aussi au niveau de store.
Ce sont des états dérivés qui sont calculés à chaque fois que le store émet une nouvelle valeur.
Je vais sans doute améliorer cette partie là encore, en permettant de récupérer les sélecteurs des niveau des entités, au sélecteurs du store.
Aller plus loin dans la personnalisation avec les reducer personnalisés
Déjà jusque là, je trouve l'outil déjà très cool. Mais je ne me suis pas arrêté là.
Ca peut-être utile de modifier une propriété de l'entité, que ce soit au chargement d'une action, à la fin de l'action suite à une succès ou une erreur.
Pour cela il est possible d'utiliser des reducers personnalisées pour chaque action.
Dans l'exemple qui suit, lors d'une création d'une entité, soit je l'ajoute à la liste si on est sur la première page soit, je la laisse dans la liste des outOfContextEntities
.
Sans rentrer trop dans les détails, cette liste permet de tracker les entités qui ont eu des actions appliquées. Je ne sais pas encore si je vais la garder ou l'exposer.
Aller toujours plus loin avec les delayedReducer
Inspiré par ce que propose l'opérateur groupBy de RxJs (duration
), j'ai ajouté des reducer qui s'appliqueront "en décalé", toujours trigger par une source.
Dans l'exemple qui suit, j'ai ajouté une action bulkdDelete
quand les entités sont supprimées, elle restent affichées avec l'état "Bulk deleted".
J'ai jouté un delayedReducer
pour les enlever de la liste après 15s.
J'ai aussi ajouté un reducer
pour ajouter une proprité ui.disappearIn$
à mon entité qui est un observable qui émet une string. Il va servir à afficher la phrase Remaining time before disappear: Xs
et se mettre à jour chaque seconde.
C'est poussé par les cheveux ? Oui sans doute, mais ça m'amusait de pouvoir faire ça simplement.
A noter que si l'utilisateur change de page, elles entités supprimées sont retirées.
Voilà, je pense avoir fait le tour de ce que j'ai pu mettre en place.
Comme je l'ai dit, il faut maintenant tester ce système sur le terrain pour l'ajuster au mieux.
Le code final del'exemple
Quelques points d'améliorations
Le nommage, je vais pour me rapprocher du nommage utilisé par TanStackQuery, pour plus d'harmonie.
J'ai rencontré beaucoup de limitations TS en terme de typage et de contraintes de typage. J'ai trouvé une solution proche de ce que je souhaitais, mais qui a quelques limitations agaçantes.
Bien que je n'ai pas eu besoin de déclarer de type à mon store, cela limite la façon dont je peux le moduler.
Je vais sans doute ajouter des fonctions intermédiaires avec des types parameters explicites pour améliorer la DX et certains cas de type-safety.
D'ailleurs, je vais essayer de faire un retour d'expérience avec les limitations de TS que j'ai rencontré lors du typage de ma fonction et les potentielles solutions.
La pagination (la source qui trigger l'appel api des entités) est très basique ici, je pense qu'elle n'est pas tout à fait fiable et mérite d'évoluer pour s'adapter au mieux.
Ajouter des events pour réagir plus facilement aux modifications de ce store.
Clean le code de l'outil, je pensais partir sur un petit fichier pour géré le store, mais avec les imports et les types, je suis autour des 1000 lignes de code. C'est pas fou niveau lisibilité. Mais le code en lui même reste assez simple à suivre.
Ajouter des fonctionnalités. Une fois sur le terrain, je verrai ce qui pourrait me simplifier encore la vie et ajouter de nouvelles fonctionnalités.
Son principale défaut, c'est que le code peut faire un peu grand si on ajoute plusieurs actions et reducer. L'ajout de fonction intermédiaire peut régler ce problème.
Conclusion
Si cet outil de server state management t'intéresse, fais le moi savoir en commentaire, ou en mettant un like sur ce poste.
Je partagerai très prochainement le code, une fois que je l'aurai organiser.
Je ne pense pas faire de lib public pour le moment, car il faut encore que l'outil murisse et fasse ses première preuves. Et j'aurais sans doute besoin d'aide pour le maintenir.
En tout cas, je suis déjà très fière du résultat et je sais qu'il me fera déjà gagner beaucoup de temps.
This content originally appeared on DEV Community and was authored by Romain Geffrault

Romain Geffrault | Sciencx (2025-04-02T17:59:29+00:00) Gérer le CRUD sur une liste de données avec Angular ? Voici l’outil que me manquait[FR]. Retrieved from https://www.scien.cx/2025/04/02/gerer-le-crud-sur-une-liste-de-donnees-avec-angular-voici-loutil-que-me-manquaitfr/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.