Validation de saisie

Qui dit application métier, dit contrôle de saisie !

Dans cet article, je vais vous montrer comment créer une directive permettant de contrôler la saisie d’un champ texte par exemple. Vous avez certainement déjà dû utilisé des directives natives d’angular comme : required, ngMinLength…

Pour vous montrer comment faire, je vais prendre un exemple assez simple : vérifier que le champ contient bien « x » caractères (à noter que nous pourrions utiliser un ngMinLength combiné à un ngMaxLength mais cela serait un peu plus gourmand).

Et donc pour l’utiliser on fait :

Du coup tant que je n’aurais pas saisi 8 caractères mon champ ne sera pas valide et donc mon form non plus.

 

Je combine souvent ces règles avec la librairie angular-messages qui permet d’avoir des messages d’erreur en fonction de notre règle de validation (j’en parlerai dans un prochain article).

 

HttpInterceptor

Il peut arriver que sur un appel http, on n’obtient pas un resultat 200 (ok), dans ce cas là, on peut avoir à faire des traitements spécifiques.

Par exemple, sur 403 (accès réfusé) alors que l’utilisateur est déjà connecté (peut être que la session a expiré), on peut vouloir retenter de connecter l’utilisateur ou bien le rediriger vers la page de login. Ceci peut être fait à l’aide d’un http interceptor.

Je vais vous présenter son utilisation dans cet article :

  • Création du httpInterceptor :

     
  • Déclaration du httpInterceptor dans la configuration de l’application :

Grâce à ce service, on va donc pouvoir faire des traitements en cas d’échec de la requête pour le reconnecter ou bien le rediriger.

Organisation du code

J’étais très réfractaire à développer une solution full javascript puisque pour moi ce n’était pas vraiment un langage; Pas de notion de classe, interface, héritage …

Mais étant donné la tendance des applications je me suis tourné vers ce langage en utilisant le framework Angular qui pour moi est un framework assez complet. Très tourné injection de dépendance, je me suis dit je vais pouvoir faire une vraie application.

Je me suis rendu compte à l’utilisation qu’il était possible de faire le meilleur comme le pire. En maitrisant bien l’usage ce n’est plus un calvaire d’utiliser angular. Je vais donc essayer d’expliquer ma vision des choses dans cet article.

 

Factory/Service :

Tout d’abord l’encapsulation la de la classe par (function() { }(); permet d’éviter les problèmes de conflit à la minification.

Afin de diminuer les portées et que cela soit plus claire, on initialise la factory (ou service) par une fonction non anonyme :

De même pour les injections de dépendances, il est plus clair d’utiliser $inject :

Encore une fois préférer l’usage de fonction que l’on expose plutôt que de passer par des fonctions anonymes :

De cette manière, on évite diminue considérablement le nombre de portées et on visualise très facilement les méthodes et propriété publiques et privées. Couplé à une ngDoc on a un code bien lisible et compréhensible de tous :)

Controller/Directive

Les conseils évoqués précédemment restent valables pour les controllers et directives néanmoins il y a quelques subtilités que je vais essayer de décrire ici.

Par convention dans un controller on écrit  : var vm = this (vm = ViewModel). Ce qui correspond donc à ce qui va être exposé côté vue.

Du coup dans un soucis de performance et de lisibilité, il faut absolument exposer uniquement les propriétés et méthodes que l’on souhaite utiliser côté vue.

 

J’espère que ces conseils vont vous aider à mieux organiser vos classes angular.

Dans un prochain article, j’aborderais la structure d’une application angular.

 

PS : Ces conseils sont inspirés de John Papa, évangéliste Angular : https://github.com/johnpapa/angular-styleguide

Gestion des événements

Dans un précédent article je parlais des paramètres de directive. Le moyen le plus efficace pour communiquer avec un composant parent.

Dans cet article je vais vous parler des événements, l’autre moyen de communication avec d’autres composants.

Il est possible d’émettre des événements depuis le $scope ou bien depuis le $rootscope.

Si vous avez bien suivi mon article concernant le $scope vs $rootScope, vous comprendrez donc dans quel cas il faut choisir d’émettre l’événement depuis le $scope ou le $rootscope. Je vais néanmoins faire une légère piqûre de rappel.

Le $scope est capable de communiquer avec n’importe quel parent ou enfant. Par contre il ne pourra pas communiquer avec un « frère ». Voici un exemple pour comprendre :

Ici je souhaite communiquer depuis mon composant « dashboard » vers mes autres composants . 3 cas de figures :

  • Le composant est un enfant (le cas de ma directive « component »)
    • Je vais pouvoir faire utiliser simplement le scope
    • Et le mode $broadcast, ce qui nous donne :
    • $scope.$broadcast(‘monEvent’,args);
  • Le composant est un « frère » (sidebar)
    • Etant donné que chaque directive a un scope isolé (même s’il existe une exception), il est donc logique les scope de « c1 » et « c2 » ne puissent pas communiquer
    • Du coup, pour les faire communiquer on va devoir utiliser le $rootscope.
    • Et le mode $broadcast
    • $rootScope.$broadcast(‘monEvent’, args);
  • Le composant est un parent (header-content)
    • Comme on l’a vu précédemment le scope reste le même, du coup on peut utiliser le Scope
    • On veut faire remonter l’événement, donc on va utiliser $emit :
    • $scope.$emit(‘monEvent’,args);

Une petite astuce pour pas de tromper sur l’utilisation de $broadcast et $emit :

  • Si l’on souhaite faire descendre l’événement, on utilise $broadcast
  • Si l’on souhaite faire monter l’événement on utilise $emit

A noter qu’en fait le $emit peut être capter à la fois par les parents mais aussi par les enfants

Pour finir, les arguments d’événement peuvent être ce que l’on veut, aussi bien un simple string, qu’un objet complexe ou bien encore une méthode (pour passer un callback par exemple) 😉

Les paramètres de directive

Créer des directives est la base d’angular. Cela permet de découper les vues en plusieurs composants bien distinct qui ont leur propre comportement.

En revanche il faut bien comprendre comment passer des paramètres d’un controller (ou directive) à une (autre) directive.

Etant donné que par défaut (et c’est pas plus mal), les directives ont un scope isolée, il n’est pas possible d’accéder aux variables directement définies dans le scope du composant parent.

Pour cela, Il y 3 types de paramètres différents :

  • @ : pourra contenir qu’un type simple et devra être passé entre {{}}
  • = : Peut contenir n’importe quel objet et pourra éventuellement être modifié dans la directive. Très utilisé pour effectuer du data-binding
  • & : Permettra de passer un callback (function)

Voici un exemple d’utilisation de ces 3 paramètres :

Tout d’abord la partie « behind » appelante:

La déclaration de la directive :

Et l’appel HTML

J’espère que cet exemple vous aura aider à comprendre toutes les possibilités qu’offre la communication avec les directives.

A savoir qu’il est également possible de transmettre des informations d’un composant à un autre à l’aide des événements. J’en parlerai dans un prochain billet. Il est néanmoins conseillé d’utiliser au maximum les paramètres dans un soucis de performance et de maintenabilité.

$scope vs $rootScope

Pour réaliser une application angularjs, il est très important de comprendre les différences entre $scope et $rootScope. Cela permettra par la suite de mieux comprendre la gestion d´événement.

$rootScope

le $rootScope comme son nom l’indique fait référence à la racine. En effet, il y en un seul par application. Il va nous permettre de pouvoir transmettre des variables et événements entre nos différents controllers.

$scope

Le $scope quand à lui est instancié pour chaque controller. Il va permettre de communiquer avec les vues et directives filles.

Pour mieux comprendre, il suffit d’observer ce schéma

angularjsscopes

Du coup si je dois communiquer d’un controller à un autre, je vais devoir utiliser le $rootScope. En revanche si je souhaite dialoguer avec les enfants d’un controller je vais plutôt utiliser le $scope.

Attention à ne pas trop utiliser le $rootScope pour stocker des éléments au risque d’alourdir votre application.

Je vais finir cette article par la gestion des événements, cela permettra de comprendre l’utilisation que l’on peut avoir du $rootScope.

A noter qu’ici j’ai injecté le $scope dans mes controllers. C’est une pratique à éviter. On préférera exposer les méthode du controller via this.

 

Création de modèle objet

Tout d’abord, pourquoi vouloir créer des modèles d’objet ?
Pour moi il y a 3 objectifs :
– Structurer le code
– ne pas avoir besoin d’attendre l’éxécution du code pour connaître le contenu de l’objet.
– Ajouter des comportements à un objet.

Pour se faire, je crée une factory comme suit :

On comprend assez vite comment enrichir nos objets en utilisant cette méthode.
Pour aller plus loin, je rajoute un paramètre « data » à mon constructeur dans le but de pouvoir initialiser mes valeurs d’objet. Voici l’exemple :

Cette usage permet de mapper les objets provenant d’un dataservice :

A la sortie du « getPeople », on a donc un tableau de « Person » qui pourra être utilisé dans les vues.