Le Data Binding Angular

Le Data Binding est un élément essentiel dans les frameworks de Single Page Application. Il permet de synchroniser la vue au modèle JavaScript sous-jacent. Voici un schéma général du fonctionnement du Data Binding :

 

capture-decran-2016-10-23-a-10-07-07

 

databinding Angular a défini quatre sortes de Data Binding pour synchroniser le template et le Component. Il est ainsi possible de propager une donnée du Component vers le DOM, du DOM vers le Component et dans les deux sens. Ces formes de Data Binding sont communément nommées: 

 

 

 

  • Interpolation : Ce mécanisme permet de modifier le DOM à partir du modèle, si un changement est intervenu sur une valeur de ce dernier.
  • Property Binding : Ce mécanisme permet de valoriser une propriété d'un composant ou d'une directive à partir du modèle, si un changement est intervenu sur une valeur de ce dernier.
  • Event Binding : Ce mécanisme permet d'exécuter une fonction portée par un Component suite à un évènement émis par un élément du DOM.
  • Le "two-way" Data Binding : C'est une combinaison du Property Binding et du Event Binding sous une unique annotation. Dans ce cas là, le component se charge d'impacter le DOM en cas de changement du modèle ET le DOM avertit le Component d'un changement via l'émission d'un évènement. Le mécanisme se rapproche du fameux ngModel Angular 1, mais avec des algorithmes de Data Binding différents.  

​AngularJs a largement contribué à faire connaître ce mécanisme, c'était même l'un de ses principaux atouts mis en avant. Mais son mécanisme de Data Binding a également été critiqué pour ses "mauvaises" performances. Notamment le fameux "dirty checking" qui va vérifier l'ensemble des expressions pour voir s'il existe un changement pour être encore ensuite relancé pour gérer les watchers…

{{L'interpolation}}

 

Nous allons enfin commencer à dynamiser nos applications grâce au Data Binding ! Commençons par créer un nouveau projet prj-data-binding à l'aide d'Angular-Cli :

 

capture-decran-2016-10-19-a-07-58-28

Si vous désirez plus d'informations à ce sujet,  je vous conseille le tutoriel Démarrer avec Angular-Cli.

 

et je vous propose de modifier notre AppComponent comme ceci :

 

 

Dans cet exemple, nous avons un template basique pour décrire l'identité d'une personne. J'ai utilisé les {{ }} pour binder les propriétés du Component avec leur pendant dans le template. Avec ce mécanisme, il est donc possible d'afficher une propriété de votre modèle dans votre template en la nommant de la même façon. Comme nous avons le plaisir d'utiliser TypeScript, j'en ai profité pour typer les propriétés du Component. Ainsi, person est une string ; age est un number ; et address est un any. J'ai fait de l'interpolation !

Mais l'interpolation, c'est quoi exactement ? 

C'est un mécanisme qui va, dans un premier temps, analyser vos templates pour retrouver vos {{interpolations}}, afin de placer, dans un second temps, des écouteurs de changement sur les propriétés de votre component qui sont liées par leurs noms. Une fois cette résolution de liaisons faite, Angular va valoriser vos interpolations avec ces propriétés lors d'un changement de ces dernières.

 

Il est maintenant le temps de voir le résultat en lançant le serveur web (à l'aide de ng serve ) si cela n'est pas encore fait, pour constater le résultat suivant :

 

Personne : John Doe | Age : 30 | Adresse : [object Object]

 

Les interpolations  {{person}} et {{age}} ont bien fonctionné. person étant une string, aucune transformation n'est à opérer pour remplacer {{person}} par "John Doe". age était un number et a été transformé en string à l'aide du mécanisme de cast, et il s'affiche donc plutôt bien. Par contre, notre adresse, étant un objet, a été castée en [object Object]. Pour afficher un object, notre template doit explicitement inscrire {{address.street}}, par exemple, pour afficher la rue.

 

L'interpolation est donc une fonctionnalité bien utile pour afficher une donnée et la synchroniser en permanence avec le modèle.

 

[Le Property Binding]

Le property Binding est également un mécanisme de Data Binding "one way". Tout comme l'interpolation, il permet de répercuter dans le DOM les valeurs des propriétés du Component. L'annotation associée est […] mais pour les réfractaires, il est possible de préfixer par bind- les propriétés. Le Property Binding est utilisable :

  • Sur un élément du DOM. Par exemple <img [src] ="…" /> ou <img bind-src ="…" /> .
  • Sur un attribute directive. Par exemple <div [ngClass] ="…"> ou <div bind-ngClass ="…"> .
  • Sur la propriété d'un component. Par exemple <page [color] ="…"> ou <page bind-color ="…"> .

 

Le Property Binding sur un élément du DOM

Si vous désirez valoriser de manière dynamique une propriété d'un élément HTML du DOM, le Property Binding est l'homme de la situation. Imaginons que nous voulions aligner notre fiche identité à droite de l'écran : il suffit, dans notre cas, d'ajouter l'attribut align à l'élément de notre template <div> et le valoriser à right. Maintenant, pour une raison X, nous préférons variabiliser l'alignement avec une propriété alignement de notre Component. Pour réaliser cela,  nous avons deux possibilités : 

  • Utiliser l'interpolation, à savoir,  modifier notre div comme ceci :

 

 

  • Utiliser le Property Binding, à savoir, modifier notre div comme cela :

 

 

Alors pourquoi préférer le Property Binding à l'interpolation ? Il n'y a pas, techniquement, de raison de choisir une manière plutôt qu'une autre. Dans le cas du Property Binding sur un élément du DOM, la propriété alignement sera toujours une string, il ne peut pas y avoir de problème de cast dû à l'interpolation. C'est donc plus une histoire de visibilité du code. Je vous conseille toutefois d'établir des règles de codage afin d'harmoniser vos templates.

 

Le Property Binding sur un attribut directive

Le Property Binding sur un attribute directive fonctionne de la même manière. Pour rappel, un attribute directive est une directive modifiant le comportement ou l'apparence d'un élément. Angular propose déjà une série d'attribute directives tels que ngClass ou ngStyle. Imaginons que l'on veuille changer la couleur du texte de notre div à l'aide des styles CSS. Angular propose d'utiliser la directive ngStyle afin d'appliquer dynamiquement un attribut de style CSS sur l'élément courant. Pour réaliser cette prouesse, la directive ngStyle utilise le Property Binding. Nous pouvons donc nous créer une propriété couleur dans notre component et appliquer cette couleur en tant que style CSS :

 

 

Le Data Binding va remplacer la variable couleur dans le template par sa valeur 'red' définie dans le Component. Si vous désirez d'autres exemples de Property Binding sur un attribut directive, je vous conseille ce tutoriel sur les Directives. Vous y apprendrez comment les propriétés sont passées aux Directives grâce au @Input.

 

Le Property Binding sur une propriété d'un component

Comme je n'ai pas de Component tout fait pour illustrer ce cas, nous allons nous faire plaisir et créer quelques Components pour comprendre le Data Binding sur une propriété d'un Component : 

 

capture-decran-2016-10-19-a-08-02-25

 

Vous allez maintenant comprendre comment fonctionne le property binding Angular grâce au décorateur @Input. Commençons par modifier le template de notre Component AppComponent pour y placer notre component Comp1Component. Pour illustrer notre property binding, je vous propose de passer la propriété address de notre AppComponent à notre nouveau Component Comp1Component. Il s'agit d'un property binding classique. 

 

 

Dans ce Property Binding, nous retrouvons bien la propriété address à droite de l'égalité et entre [ ] (à gauche donc) un nom de propriété ( comme finalement ngStyle, ngClass, …) qui sera valorisé par le mécanisme de Property Binding. Notre Component Comp1Component récupérera donc address au niveau de sa portée. C'est ici que le decorator @Input entre en jeu. En le positionnant devant une variable, le mécanisme de Data Binding dans le sens "extérieur vers intérieur" se met en place. 

 

 

Grâce au décorateur @Input, le template de Comp1Component  affiche la propriété monAdresse.street sans problème.

 

(L'Event Binding)

Avec le Property Binding, vous avez pu, à partir d'un component, binder une propriété pour interagir avec un élément du DOM. Maintenant, vous allez voir comment, à partir d'un évènement du DOM, interagir avec un Component. Pour réaliser ce Data Binding, Angular utilise les évènements ; D'où le nom de Event Binding. Avec ce mécanisme, vous pouvez être averti des évènements utilisateurs tels que le click, la frappe sur le clavier, le touch, … La syntaxe est proche du property binding : à gauche de l'égalité on retrouve l'évènement que l'on veut émettre entre parenthèses ou précédé de on- et à droite, on trouve la fonction que l'on appellera lorsque le Component interceptera l'évènement. Par exemple, si vous désirez réagir à un click sur un bouton de notre template AppComponent  pour modifier le nom de la personne, il suffit de rajouter une méthode modifierPersonne()  qui modifiera la propriété person  lorsque l'on clique sur le bouton ( on aura donc une interaction dans le DOM qui modifiera le modèle) :

 

Si vous cliquez sur le bouton, l'adresse sera automatiquement modifiée dans notre template en haut à droite de l'écran. 

 

Vous pouvez aussi créer vos propres Event Binding très simplement afin d'envoyer un évènement d'un Component vers un Component parent. Pour illustrer cela, nous allons utiliser notre Component Comp2Component créé précédemment. Ce Component sera chargé d'incrémenter ou de décrémenter une variable à l'aide de deux boutons et envoyer le résultat via un évènement. Le Component parent AppComponent s'occupera, lui, de récupérer cet évènement afin d'afficher la valeur. Voici pour commencer le source de Comp2Component :

 

 

Si vous avez l'oeil, vous avez sans doute observé un nouveau decorator : @Output. Ce décorateur se veut être le pendant du decorator @Input. Quand @Input se charge de recevoir une valeur, @Output se charge, lui, d'envoyer une donnée. Ainsi, counterChange est une instance de classe EventEmitter en charge d'envoyer un évènement lors une pression sur un des boutons.

EventEmitter est une classe utilisée dans une directive ou un component pour émettre un évènement. Sa méthode principale est emit(value? : T) qui permet d'envoyer un évènement contenant potentiellement un objet ou une valeur.

Il ne reste plus qu'à utiliser Comp2Component  dans notre Component principal AppComponent en déclarant notre Event Binding afin de récupérer la valeur émise par le Component :

 

 

Comme par magie, la méthode myValueChange est appelée à chaque fois qu'un évènement counterChange est reçu. A noter la possibilité de passer $event en paramètre pour récupérer le contenu de l'évènement.

 

[(Le two-way Data Binding)]

 

Pour terminer cet article, je vais vous parler du two-way Data Binding. Ce mécanisme permet, à partir d'une même notation, de modifier le modèle à partir du DOM et de modifier le DOM à partir du modèle. Voici la syntaxe utilisée dans Angular pour déclarer un tel Data Binding : 

 

 

Il faut se souvenir  que les parenthèses sont entre les crochets. Pour se souvenir de cela, cette notation se nomme "banana in a box"… Cette banane dans une boite rappelle ce que nous avons pu voir avec le Property Binding et l'event binding. Effectivement, ce que nous venons de voir aurait pu également s'écrire :

 

 

Nous pouvons dès lors en déduire que le code de notre component aura en @Input nommé taille et un @output nommé tailleChange. Cela constitue donc la règle du Data Binding 2-way : Si l'on considère la notation [(x)], x est la propriété à setter et xChange est l'évènement lancé lors d'une modification de sa valeur. Cet évènement sera donc intercepté par son component parent afin de récupérer cette valeur.

Voici le code  du component <ma-taille> :

 

 

Pour l'utiliser, il est nécessaire de déclarer, dans le component parent, une propriété maTaille qui sera bindée, puis de l'utiliser comme ceci :

 

 

[(Le two-way Data Binding avec NgModel)]

 

NgModel est une directive qui permet de réaliser du data-binding sur les éléments de formulaire de type Input et textarea. Cette directive fonctionne, dans la pratique, de la même manière que la directive ngModel d'AngularJS. Voici la syntaxe de cette directive :

 

 

Important : Pour utiliser cette directive, il est nécessaire de rajouter le module FormModule à votre projet, mais rassurez-vous, Angular-Cli l'a déjà fait pour vous.

 

Comme vu précédemment, cela aurait pu également s'écrire :

 

 

Nous pouvons l'utiliser dans le templparate de AppComponent. Il va permettre de modifier la propriété person et vous pourrez ainsi constater que l'affichage de la personne (en haut à droite) sera également modifié.

 

 

Simple et efficace !

 

William Koza

William Koza

Consultant Indépendant  
Passionné par la conception et le développement logiciel, j’ai rapidement pris le rôle de Technical Leader lors de mes premiers projets. Ces expériences ont ainsi pu me faire accéder à des rôles d’architecte dans des projets d’envergure. Aujourd'hui, j'exerce mon métier en tant qu'indépendant, et toujours avec la même passion.
William Koza

Les derniers articles par William Koza (tout voir)