À la suite de mon article de la semaine dernière Angular: Comment détecter un clic hors d'un composant ? j'ai eu quelques retours de collègues (merci à vous Gérôme et Nicolas !) et j'ai retravaillé un peu la directive que je proposais de copier-coller.
Pourquoi la retravailler ?
Le premier point c'est qu'on pouvait écrire la même chose en écoutant un seul et unique évènement (le clic sur le document) et donc n'avoir qu'un seul listener sur le DOM.
Si on utilise la directive 2-3 fois dans l'application ça ne fait aucune différence d'avoir un ou deux listeners, mais si on se retrouve par exemple à suivre individuellement les clics hors des cellules d'un tableau généré dynamiquement à partir d'un gros volume de donnée ça devient gênant (pensez à 500 cellules, on aurait donc 1000 listeners au lieu de 500…).
Le second point vient aussi au niveau de l'idée d'éviter des soucis de performance quand on utilise beaucoup la directive. Imaginons encore une fois qu'on ait 500 instances de la directive et qu'on affiche le nombre de fois qu'on appuie hors des éléments sur chaque élément (c'est un exemple inutile, mais on peut vite se retrouver à faire des choses similaires). Dans ce cas on aura un lag de 1 à 2 secondes le temps que toutes les instances de directive soient résoluent.
La solution que Nicolas m'a proposé et que j'ai implémenté après avoir créé un exemple pour expérimenter le problème c'est de permettre de n'écouter l'évènement ngxOutsideClick que à la demande en cas de gros volume. L'idée c'est que généralement on ne cherchera pas à écouter tout le temps qu'on clic hors d'un élément, mais uniquement à certains moments. Pensez à une page contenant 500 menus déroulants, on ne s'intéresse au clic hors de celui-ci que s'il est ouvert, on veut donc bien utiliser la directive sur chaque menu déroulant, mais on a pas besoin de l'évènement s'il n'est pas ouvert.
Le résultat : un package npm à importer
La directive devenant plus complexe j'ai donc décidé d'en faire un package npm. J'ai créé une démo pour expérimenter le fait qu'on écoute ou non l'évènement, le lag si on écoute tout le temps, etc.
Cette librairie propose donc un module unique NgxOutsideClickModule qui expose uniquement une directive NgxOutsideClickDirective qui s'utilise très simplement :
<div (ngxOutsideClick)="doSomething($event)">
...
</div>
ou si on veut activer/désactiver l'écoute
<div (ngxOutsideClick)="doSomething($event)" [ngxOutsideClickEnabled]="false">
...
</div>
J'ai évidemment mis une couche de test unitaire, qui sont exécutés à chaque commit sur le dépôt github. Le tout avec du déploiement continu vers npm de sorte à pouvoir corriger d'éventuel bug ou apporter des améliorations très rapidement !
Le code souce, le guide d'installation et la démo se trouve ici : https://github.com/kuroidoruido/ngx-outside-click