jeudi 31 octobre 2013

Scope isolé dans les directives AngularJS


Second sujet que j'ai traité au Meetup chez Google, il s'agit des scopes isolés dans les directives.  Les slides se trouvent ici, et une vidéo a été mise en ligne là ; mon intervention commence par un sujet sur l'usage des services, et celui-ci est à la suite.

Le scope isolé est un outil bien pratique mis à notre disposition par AngularJS pour faciliter la création de widgets. Mais il ne faut pas l'utiliser n'importe quand, ni en faire n'importe quoi.


L'arbre des scopes


Les scopes d'AngularJS sont des objets qui servent de contexte d'évaluation des expressions contenues dans les templates.

Ils forment un arbre, dont la racine est le seul scope de l'application qui est aussi publié comme un service, sous le nom $rootScope. Ce $rootScope est associé à l'élément contenant toute l'application AngularJS, celui sur lequel on met la directive ngApp : ça peut être l'élément <html> lui-même, ou le <body>, ou un <div> à l'intérieur, peu importe.

samedi 26 octobre 2013

Services ou événements dans l'optique des tests

Quelques réflexions complémentaires à mon article sur l'usage des services, qui partent d'une question que l'on m'a posé à la fin de ma présentation au Meetup AngularJS Paris chez Google. Quelqu'un m'a demandé si les événements pouvaient être utilisés pour simplifier les tests unitaires d'un contrôleur. En limitant les injections de services en dépendances, on évite la nécessité de versions factices (mock objects) de ces services.

Cette question me turlupinait dans le trajet retour, et j'ai essayé de pousser plus loin la réflexion en explorant cette piste et diverses alternatives.

mercredi 23 octobre 2013

Usage des services AngularJS

Cet article est basé sur la présentation que j'ai faite hier au Meetup AngularJS Paris chez Google. Les slides se trouvent ici, et une vidéo a été mise en ligne là. Mais comme les slides perdent beaucoup de leur intérêt sans les explications qui vont avec, ça méritait bien un article - et même plusieurs, puisque j'ai mis deux exemples dans des articles séparés (les liens sont vers la fin). Je vais aussi en écrire un sur l'autre partie de ma présentation, sur les scopes isolés dans les directives.

S'il y a une fonctionnalité que les développeurs qui débutent sur AngularJS sous-estiment énormément, c'est bien les services. Je me rend compte régulièrement en formation ou lors d'audits que beaucoup de code pourrait être largement simplifié en utilisant plus efficacement les services. Ça n'a d'ailleurs rien d'étonnant, on commence à partir des exemples qu'on trouve sur internet, qui sont des exemples courts et n'ayant évidemment pas toute la structure d'une vraie application. Des exemples qui montrent comment ça marche, pas comment il faut faire.

Dans une application non triviale, au moins 90 % du code JavaScript devrait être dans les services. Il peut y avoir quelques directives et filtres bien sûr, dont une partie peut d'ailleurs être commune à plusieurs applications, mais ce sont les contrôleurs qui doivent être aussi réduits que possible. Un contrôleur AngularJS est juste une fonction d'initialisation du scope correspondant, et il doit essentiellement se limiter à cela : faire quelques affectations dans l'objet scope. Il ne doit pas faire de requêtes HTTP, ni des traitements sur les données, ni gérer le stockage des données.


Conserver les valeurs des critères de recherche

Comment conserver lorsque l'on change de vue à l'intérieur d'une application AngularJS des données correspondant à l'état de la vue, comme les valeurs des critères d'une recherche ?

Imaginons qu'on affiche dans une vue une liste d'objets, avec des critères permettant de faire un filtrage en local. Et sur chaque objet, un lien permet de naviguer vers une vue des détails de l'objet. Quand l'utilisateur revient sur la liste, il s'attend à la retrouver dans le même état. Ça suppose que les valeurs de filtrage saisies soient conservées.

Or si ces valeurs sont simplement dans le scope de la vue, elles seront perdues à chaque changement de vue, car le scope de l'ancienne vue est détruit par AngularJS. La solution simple pour les conserver est de les stocker dans un service.

Service AngularJS de notification

Un autre exemple de service qui peut être très utile : il s'agit d'afficher des notifications pendant quelques secondes, comme le font les applications de Google, avec un lien dans le message permettant d'annuler l'action.

C'est typiquement le genre de truc qu'on imagine compliqué, mais si on le prend bien, avec AngularJS ça s'écrit en quelques lignes - enfin sans compter le CSS qui finalement est le plus gros du boulot.

L'exemple se trouve ici sur GitHub, et il y a un lien vers la démo (c'est le même que pour l'article "Conserver les valeurs des critères de recherche"). Ajoutez des articles au panier, et quand vous en supprimez du panier, vous avez une notification avec un lien pour annuler l'action.

lundi 14 octobre 2013

Validateur pour vérifier qu'une date est postérieure à une autre

Voici un exemple de validateur spécifique, qui répond au besoin classique de vérifier que la date saisie dans un champ est postérieure à celle saisie dans un autre champ du formulaire. Typiquement, on demande de saisir une date de début et une date de fin, et on veut s'assurer qu'un utilisateur étourdi n'a pas rentré une date de fin qui précède la date de début.

L'exemple est intéressant, car il permet de voir comment valider un champ par rapport à un autre, ce qui n'est pas expliqué dans la documentation d'AngularJS.


mardi 28 mai 2013

AngularJS et performances

La plupart des applications AngularJS ne posent pas de problèmes particuliers de performances. Mais dans certains cas, où une page peut comporter un grand nombre de bindings, il va falloir y prêter attention pour éviter les ralentissements.

Les développeurs d’AngularJS ont toujours indiqué que le framework est capable de supporter sans problème 2000 bindings dans une page web, sur une machine un peu ancienne. C’est un ordre de grandeur, un ordinateur récent avec un navigateur web rapide pourra en supporter beaucoup plus sans soucis. Par contre sur un smartphone un peu poussif, il faudra être prudent pour éviter de se retrouver avec une application pénible à utiliser.

Ça peut paraître beaucoup, 2000 bindings, et dans la majorité des pages d’une application on sera très loin de cette limite théorique, mais avec un gros tableau on peut l’atteindre facilement. Dans le cas d’un tableau comportant 10 colonnes, avec un binding par colonne, il suffit d’afficher 200 lignes pour arriver aux 2000 bindings. Dans tous les cas où l’on va afficher tout un ensemble de données pour chaque élément d’une collection potentiellement grande, que ce soit sous la forme d’un tableau, d’une liste ou de toute autre façon, il va falloir faire attention.

vendredi 22 mars 2013

Communauté AngularJS France, et rédacteurs pour FrAngular

Je me suis dit qu'il manquait un espace pour les échanges et les annonces concernant AngularJS en France. Les rencontres, soirées ou conférences sur notre framework préféré commencent à se multiplier, et il devient difficile de savoir ce qui a lieu en France, ou comment avertir le public intéressé.

Du coup je viens de créer une communauté sur Google+ intitulée - après une longue réflexion - “AngularJS France”. Ce n'est peut-être pas hyper original, mais on moins on comprend assez vite de quoi il s'agit. Elle est toute fraîche, les pixels ne sont pas secs, et j'en suis encore le seul membre mais j'imagine que ça ne va pas durer. Elle n'a pas pour but de concurrencer la communauté AngularJS officielle, mais simplement de permettre de trouver facilement les infos locales sur le sujet.

jeudi 14 mars 2013

Comment aborder AngularJS ?


Si vous avez lu les articles publiés sur FrAngular qui détaillent des aspects techniques du framework, c'est que vous avez peut-être déjà dépassé le stade de l’initiation. Néanmoins, pour ceux qui découvrent AngularJS, je vais expliquer comment on peut aborder ce framework dont l’apprentissage risque de s’avérer quelque peu déroutant.

Commencez par JavaScript


JavaScript est certainement le langage le plus mal connu de ses utilisateurs de toute l’histoire de l’informatique. Combien de développeurs qui font du JavaScript ont vraiment pris le temps de l’apprendre ? On y reconnaît une syntaxe familière parce qu’on a déjà fait du Java, du C++, du PHP, enfin quelque chose qui y ressemble de très loin, et du coup en tâtonnant on arrive à écrire du code JavaScript qui fonctionne à peu près. Mais du très mauvais code JavaScript. Je suis passé par là, comme presque tout le monde.

Les concepts de JavaScript - un langage objet sans classes et avec un forte composante fonctionnelle - sont complètement différents des autres langages objets les plus répandus. Il y a plus de ressemblance entre Java, C#, Python, Ruby, et même PHP en version objet, qu’entre n’importe lequel de ces langages et JavaScript.

mardi 5 mars 2013

Le langage d'expressions d'AngularJS

Voici un article qui tient du paradoxe, puisque je vais y décrire les possibilités du langage d'expressions d'AngularJS, tout en expliquant qu'il faut les utiliser au minimum.

Avec AngularJS, on utilise des expressions pour le binding, et avec de nombreuses directives. Elles ressemblent à des expressions JavaScript, mais n'en sont pas. Elles ne sont pas directement évaluées par l'interpréteur JavaScript, mais parsées et exécutées par AngularJS. Du coup on ne peut utiliser qu'un sous-ensemble des opérateurs et des mots-clefs de JavaScript, et elles divergent aussi de JavaScript sur quelques aspects.

jeudi 28 février 2013

AngularJS, ce n'est pas pour jouer


De nombreux messages ont circulé hier sur Twitter annonçant un jeu en ligne, Bombermine, réalisé avec AngularJS. Étonnant... mais erroné. J’ai moi-même rediffusé un de ces messages, avant de regarder de plus près et de voir qu’AngularJS n’est utilisé que pour l’interface utilisateur, mais que le jeu lui-même est écrit avec GWT.

AngularJS est particulièrement efficace pour la réalisation d’application web, mais pas du tout adapté à la création de jeux.

CRUD... au sens large


Les développeurs d’AngularJS le présentent comme un framework destiné à la réalisation d’applications de type “CRUD” (Create - Read - Update - Delete), c’est-à-dire des applications web affichant des données, et permettant de les saisir ou de les modifier.

C’est effectivement le cas, si l’on ne prend pas le terme CRUD dans un sens trop restrictif, voire péjoratif. Il ne faut pas imaginer des applications réduites à l’affichage de trois pauvres formulaires, bien au contraire.

mardi 19 février 2013

Les fonctionnalités de Twig avec AngularJS: angular-twig-pack

Depuis que je travaille avec AngularJS, j'ai entendu beaucoup de gens comparer le Framework avec divers moteurs de template... Et il en existe! La liste (non-exhaustive) de wikipedia: Template_engine_(web) en est la preuve. Malheureusement, Wikipedia ne nous numérote pas ce tableau, heureusement que la console est là:

> document.querySelectorAll('.wikitable tbody tr').length
89

Bon ... Trêve de plaisanterie, passons aux choses sérieuses. Je me suis dit pourquoi ne pas prendre un moteur de template existant et créer un pack de directives, filters et services pour ne pas trop dépayser les puristes.

Kezako

Pour cet exercice, j'ai choisi le Framework Twig (uniquement car je l'ai déjà utilisé et surtout car j'adore les couleurs du site: http://twig.sensiolabs.org/).

mercredi 13 février 2013

Un outil de présentation en AngularJS

Pour une fois je ne vais pas vous détailler un aspect technique du framework, mais présenter une petite application qui peut être utile. Mais si je la présente ici, c'est bien sûr parce qu'elle est écrite avec AngularJS, et qu'il y a quelques exemples dans le code qui peuvent vous intéresser.

J'avais besoin d'un outil pour présenter des slides sur AngularJS en début de semaine prochaine : lundi 18 février à LyonJS, et mardi 19 février au Marseille JUG. Bien sûr il existe maintenant des outils pour faire des présentations en HTML avec plein d'effets spéciaux impressionnants. Mais je dois être de la vieille école, parce que j'ai toujours l'impression que ces effets qui en mettent plein la vue détournent l'attention du contenu. En fait je ne mets jamais d'animations dans mes présentations ; sans pousser aussi loin le minimalisme, je penche plus vers la “méthode Lessig”. Donc tout ce dont j'avais besoin c'était d'un outil comme ShowOff, permettant d'écrire rapidement les styles dans une syntaxe markdown.

Mais ShowOff c'est une application serveur, en Ruby, avec une liste de dépendances presque aussi longue que le bras. Du coup j'ai écrit ce week-end une version simplifiée avec AngularJS, une simple application cliente sans côté serveur. Je l'ai mise sur GitHub : angular-showoff. Il y a un lien vers la démo dans le descriptif.

vendredi 8 février 2013

Solution simple pour des formulaires avec données différées

Je ne suis pas sûr d'avoir trouvé un titre très vendeur pour cet article, mais vous y trouverez un exemple qui peut être très utile. C'est une solution hybride entre les $resource et les promises du service $q d'AngularJS. Elle est très simple à mettre en oeuvre, pour utiliser avec des formulaires travaillant sur des données chargées en asynchrone, un besoin somme toute très fréquent.

AngularJS fournit en standard le service $resource, qui permet de gérer facilement des entités chargées en asynchrone, mais il est prévu pour fonctionner avec une API serveur de type REST. Il n'est pas nécessaire que ce soit une API strictement RESTful, mais il ne faut pas qu'elle s'en éloigne trop pour que l'utilisation du service $resource soit pertinente.

lundi 4 février 2013

Drag & Drop avec AngularJS

Le drag & drop est revenu à la mode avec l'arrivée des tablettes et des smartphones. Un temps boudé par les développeurs web, il est de bon ton d'offrir de tels mécanismes dans nos applications web. A l'image de Trello et de ses fameuses colonnes, nous allons voir comment rendre des éléments html draggable et droppable.

vendredi 25 janvier 2013

Google Chart Tools avec AngularJS

Pouvoir inclure un graphique dans une application AngularJS par la simple utilisation d'une directive, l'idée est séduisante. Et bien sûr, pour respecter la philosophie du framework, le graphique doit se mettre à jour quand les données changent.



Voici un exemple de directive qui permet exactement ça, pour un graphique de type camembert, en l'occurrence le “Pie Chart” de Google Chart Tools. L'utilisation est toute simple :

<pie-chart data="chartData" title="My Daily Activities" 
           width="500" height="350"
           select="selectRow(selectedRowIndex)"></pie-chart>

Dans les attributs, on fournit simplement les données (ici "chartData", c'est le nom d'une propriété du scope, comme avec ng-bind), le titre du graphique, ses dimensions, et éventuellement une expression qui est exécutée lorsque l'utilisateur sélectionne une portion du camembert.

mardi 22 janvier 2013

De JSF à AngularJS


Ce matin j’ai partagé sur Twitter cet article en anglais qui fait une comparaison entre AngularJS et JSF. D’autres que moi l’ont partagé aussi, mais il y a eu quelques réactions étonnées, du genre : “c’est une blague ?”.

Pour moi la comparaison n’a rien d’absurde, et mérite de plus amples explications que ce qu’on peut écrire dans un tweet de 140 caractères.

Tout comme l’auteur de l’article, je viens du monde Java et j’ai travaillé avec JSF pendant 5 ans, certes surtout comme architecte et en support à mes collègues qui l’utilisaient au quotidien, mais j’ai aussi fait ma part de développements. Et moi aussi en découvrant AngularJS, j’ai forcément constaté des ressemblances entre les deux frameworks.

mardi 15 janvier 2013

AngularJS: Service de gestion de raccourcis clavier

A l'image des applications Google, Twitter et autres grosses applications Web du moment, il est très "user-friendly" (convivial pour les franglophobes !) de mettre en place une série de raccourcis clavier pour utiliser de manière optimisée l'application.

Les raccourcis clavier sont une touche ou une combinaison de deux ou plusieurs touches à presser simultanément afin d'éviter une action de pointage par la souris. Le fait de ne pas déplacer en permanence la main entre le clavier et la souris fait déjà gagner un temps précieux pour les gens qui travaillent toute la journée sur une application. De plus, à chaque action de la souris, il faut un temps de pointage pour déplacer le curseur sur l'endroit voulu.

Comment centraliser la gestion de ces raccourcis dans une application AngularJS ?

Nous allons voir comment utiliser un service AngularJS pour rendre cette gestion de raccourcis clavier générale.

vendredi 11 janvier 2013

Tableaux complexes avec AngularJS : ng-repeat et tbody

[Ajout du 12/01/2013] J'ai modifié la solution proposée à la fin de l'article pour utiliser une directive ng-switch plutôt que ng-show, ce qui est beaucoup plus pertinent.

On m'a demandé plusieurs fois ce qui peut être compliqué à faire avec AngularJS. Il y a une chose qui parfois s'avère contraignante, surtout pour présenter des tableaux complexes, c'est le fait que les templates d'AngularJS doivent être du HTML, sinon forcément valide, du moins compris par le navigateur.

AngularJS compile le template à partir du DOM chargé par le navigateur. Il ne travaille pas sur le fichier source HTML, mais sur le DOM construit par le navigateur à partir du source, et ça fait une grosse différence. Ce fonctionnement est un des principaux atouts d'AngularJS, mais dans quelques rares cas, il peut s'avérer contraignant.


lundi 7 janvier 2013

AngularJS : Scopes et évènements

Le scope d'AngularJS n'est pas très différent de la notion de scope du langage JavaScript, ce contexte qui pose parfois problème, lorsque le mot clé this ne pointe plus vers le bon contexte dans un callback. On utilise $scope ou $rootScope, en les injectant dans un contrôleur, pour faire référence respectivement au contexte local du contrôleur ou au contexte global de l'application.

Si les scopes d'AngularJS peuvent être créés manuellement, ils vont surtout être créés automatiquement par le framework lors de l'utilisation de certaines directives ou la déclaration d'un nouveau contrôleur. Ils sont reliés sous la forme d'un arbre hiérarchique avec héritage par prototype. Cette organisation en arbre peut être gênante lorsque l'on veut effectuer une communication directe entre des scopes qui ne sont pas reliés par une relation père/fils.

Comment faire passer des informations d'un scope à un autre quand il n'existe pas de relation directe entre eux?

Nous allons voir comment utiliser l'API des scopes fournie par AngularJS pour envoyer et intercepter des évènements personnalisés.