Suivez votre progression
Accueil Trailhead
Accueil Trailhead

Gestion des actions avec les contrôleurs

Objectifs de formation

Une fois cette unité terminée, vous pourrez :
  • Créer un contrôleur côté client afin de gérer les actions utilisateur.
  • Lire les valeurs d’attributs de composants.
  • Lire les valeurs de contrôles d’interface utilisateur depuis votre composant.
  • Écrire du code contrôleur en JavaScript qui modifie l’interface utilisateur.

Gestion des actions avec les contrôleurs

Jusqu’à présent, nous n’avions travaillé qu’avec du balisage style XML. Jusqu’à présent, le seul moyen de modifier la sortie de notre composant consistait à changer ce balisage. Jusqu’à présent, nos composants ne réagissaient pas aux entrées de l’utilisateur. Jusqu’à présent, nous n’avions pas développé en JavaScript.

Tout cela va changer dans cette unité.

Pour commencer, étudions un composant très simple, et imaginons ce qu’il devrait faire pour gérer son comportement simple.

Message du jour : Bouton « You look nice today », bouton « Today is going to be a great day ».

C’est helloMessageInteractive, et il est difficile d’imaginer un composant plus simple qui fasse « quelque chose ». Il comprend du texte statique, un message (actuellement vide) et deux boutons. Voici le code :

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Message of the day: {!v.message}</p>
    <div>
        <lightning:button label="You look nice today."
            onclick="{!c.handleClick}"/>
        <lightning:button label="Today is going to be a great day!"
            onclick="{!c.handleClick}"/>
    </div>
</aura:component>

Il devrait vous être familier. Tout ce que nous avons vraiment fait, c’est ajouter deux composants <lightning:button> à helloMessage. Lorsque vous cliquez sur un bouton, le message du jour se met à jour.

En fait, pas tout à fait. Si vous avez déjà entré et testé le code vous-même, vous aurez remarqué que lorsque vous cliquez sur l’un des boutons, vous obtenez un message d’erreur.

Il y a un problème.

Nous serons les premiers à admettre que tous les messages d’erreur que vous voyez dans les composants Lightning ne sont pas toujours aussi utiles qu’on l’aimerait. Mais celui-ci l’est ! Il indique qu’il n’y a aucune action de contrôleur nommée « handleClick ». D’où vient « handleClick » ? Il vient de l’expression que nous avons affectée à l’attribut onclick de chacune des deux balises <lightning:button> :

onclick="{!c.handleClick}"

Étant donné qu’il s’agit d’un bouton, vous pouvez probablement deviner que l’attribut onclick est ce qui vous permet d’affecter un comportement au bouton, qui doit être adopté lorsque vous cliquez dessus. Mais qu’avons-nous affecté ? Une expression, {!c.handleClick}, qui est peut-être un peu mystérieuse.

En fait, c’est vraiment simple. Tout comme l’expression v.message que nous avons vue précédemment, c.handleClick fournit une valeur, c, accompagnée d’une propriété, handleClick. c est le fournisseur de valeurs pour le contrôleur côté client du composant, et handleClick est une fonction définie dans ce contrôleur. Donc, {!c.handleClick} est une référence à un gestionnaire d’actions du contrôleur du composant.

c.handleClick : c est un fournisseur de valeurs pour le contrôleur du composant, avec la propriété handleClick, une fonction définie dans ce contrôleur

Mais au fait, qu’est-ce qu’un contrôleur ?

Oups ! En termes simples, un contrôleur est un ensemble de code définissant le comportement de votre application lorsque « des choses se passent », ces « choses » pouvant être une saisie d’éléments par l’utilisateur, l’utilisation d’un minuteur ou encore d’autres événements tels que des mises à jour de données. Si vous vous renseignez sur l’approche « Modèle-Vue-Contrôleur » sur divers sites de développement, vous obtenez différentes définitions. Dans le cas présent, pour les composants Lightning, un contrôleur est une ressource dans un paquet de composants, qui contient les gestionnaires d’actions de ce composant. Et les gestionnaires d’action sont quant à eux tout simplement des fonctions JavaScript dont la signature est particulière.

Au-delà des concepts de base

Nous parlons beaucoup de contrôleurs dans cette unité, et savons que le composant en lui-même est une vue. Nous avons même mentionné l’architecture MVC, ou Modèle-Vue-Contrôleur, un système de conception très courant dans les frameworks d’applications Web. Les composants Lightning reposent-ils sur une architecture MVC ?

En un mot, non. Il y a des similarités, sans aucun doute, mais il serait plus exact de dire que les composants Lightning reposent sur une architecture Vue-Contrôleur-Contrôleur-Modèle, ou peut-être Vue-Contrôleur-Contrôleur-Base de données.

Pourquoi « contrôleur » est-il en double dans ce nom de système ? C’est parce que lorsqu’ils interagiront avec Salesforce, vos composants auront un contrôleur côté serveur en plus du contrôleur côté client avec lequel nous avons travaillé dans cette unité. Cette conception à double contrôleur est la différence clé entre les composants Lightning et l’architecture MVC.

Quelle est la distinction entre « modèle » et « base de données » ? Dans l’architecture MVC traditionnelle, le modèle est une entité programmatique (généralement une classe) entre le stockage de données sous-jacent (généralement une base de données relationnelle) et le reste de l’application. Dans les composants Lightning, il n’existe pas de classe Apex se trouvant directement entre les méthodes du contrôleur @AuraEnabled et les opérations DML. Cependant, les sObjects sont une entité intervenant entre votre code Apex et la couche de stockage de données sous-jacente. Vous pouvez ajouter des champs de calcul, une logique de validation et même un comportement entièrement programmatique sous la forme de déclencheurs. Donc, est-ce une base de données ou un modèle ? En fait, c’est bonnet blanc et blanc bonnet.

Alors, un peu désorienté ? Intéressé(e) ? Nous couvrirons les détails des contrôleurs côté serveur dans une prochaine unité.

Examinons le contrôleur helloMessageInteractive plus en détails pour rendre cette explication un peu plus concrète.

({
    handleClick: function(component, event, helper) {
        let btnClicked = event.getSource();         // the button
        let btnMessage = btnClicked.get("v.label"); // the button's label
        component.set("v.message", btnMessage);     // update our message
    }
})

Le format des ressources Contrôleur est intéressant. Ce sont des objets JavaScript contenant un mappage des paires nom-valeur, dans lequel le nom est celui du gestionnaire d’actions et la valeur est une définition de fonction.

Gestionnaires d’actions

L’ensemble formé par la paire nom-valeur et la signature de la fonction spécifique constitue un gestionnaire d’actions. Vous verrez ou entendrez les termes Gestionnaire d’actions, Action de contrôleur et Fonction de contrôleur être utilisés de manière interchangeable, et la plupart du temps, cela ne posera aucun problème. Ils font pratiquement toujours référence à la même chose (nous ne nous préoccuperons pas des exceptions dans ce module).

Ne vous souciez pas trop du format spécial de la ressource Contrôleur. Lorsque vous cliquez sur le bouton CONTROLLER de la Developer Console, vous obtenez une ressource Contrôleur avec un exemple de gestionnaire d’actions déjà ajouté. Le piège (qui entraînera des erreurs de syntaxe si vous n’y prenez pas garde), c’est que vous devez insérer des virgules entre les gestionnaires d’actions. C’est simplement dû à la syntaxe JavaScript de base. Nous entrerons bientôt dans le détail.

La véritable fonction handleClick ne comprend que quatre lignes de code, mais elles peuvent sembler difficiles à comprendre au premier regard. À haut niveau, c’est simple : lorsque vous cliquez sur le bouton, son gestionnaire d’actions est appelé (1). Dans le gestionnaire d’actions, le contrôleur obtient le bouton sur lequel vous avez cliqué, extrait son libellé texte, puis règle l’attribut message du composant sur ce texte (2). Et voilà, le message du jour est mis à jour (3). You look nice today!

Dans le gestionnaire d’actions, le contrôleur obtient le texte du bouton sur lequel vous avez cliqué puis règle l’attribut message du composant.

Simple, n’est-ce pas ? Bon…

Étant donné que c’est super important, étudions cela ligne par ligne.

handleClick: function(component, event, helper) {

Le nom du gestionnaire d’actions, suivi d’une déclaration de fonction anonyme. Ce qui est important ici, c’est la signature de fonction. Bien que ce ne soit pas techniquement obligatoire, vous devez toujours déclarer vos fonctions de contrôleur de manière à ce qu’elles prennent en compte ces trois paramètres. Nous les étudierons davantage au fil de notre progression, mais pour le moment, ces paramètres représentent ce qui suit :

  • component : le composant. Dans le cas présent, il s’agit de helloMessageInteractive.
  • event : l’événement qui a entraîné l’appel du gestionnaire d’actions.
  • helper : l’assistance du composant, c’est-à-dire une autre ressource JavaScript constituée de fonctions réutilisables.
    let btnClicked = event.getSource();         // the button

N’oubliez pas que handleClick est connecté à notre balise <lightning:button> et à son attribut onclick. Ici, l’événement désigné par le paramètre event est le clic d’une personne. Cet événement fait référence à la notion de source (ce qui a généré l’événement), c’est-à-dire le bouton lui-même. Par conséquent, l’appel de event.getSource() nous permet d’obtenir une référence au bouton <lightning:button> spécifique sur lequel un clic a été réalisé.

    let btnMessage = btnClicked.get("v.label"); // the button's label

Que faire maintenant que nous avons une référence au bouton ? Nous l’examinons et obtenons son étiquette, qui est paramétrée au niveau de <lightning:button> au sein du balisage du composant. Par exemple, <lightning:button label="You look nice today." ... >.

Réfléchissons-y un peu plus. Nous n’avons pas la définition de <lightning:button> sous les yeux, mais label n’est qu’un autre attribut, très semblable à l’attribut message que nous avons ajouté à helloMessageInteractive. Vous pouvez appeler get() pour n’importe quel composant en fournissant le nom de l’attribut que vous souhaitez récupérer, au format v.attributeName. Vous obtiendrez ici la valeur de l’attribut.

Notez que tout comme pour le balisage des composants, v représente la vue, le composant en lui-même, mais dans ce cas précis, il s’agit du composant enfant <lightning:button>, et non de helloMessageInteractive ! Vous pouvez vous représenter ce qui se passe comme ceci : btnClicked.get("v.label") tape sur l’épaule du composant btnClicked, quel qu’il soit, et lui dit « Eh, donne-moi v.label ». Ce composant pense « v, c’est moi », s’auto-analyse et retourne la valeur de son attribut label.

Donc maintenant que nous avons récupéré une chaîne de texte à partir du bouton, il ne nous reste plus qu’une étape : remplacer notre attribut message par le nouveau texte du message. Sans surprise, tout comme get() lit une valeur d’un composant, set() écrit une valeur.

    component.set("v.message", btnMessage);     // update our message

Cependant, remarquez une différence importante. Nous avons appelé get() pour btnClicked, le bouton <lightning:button> se trouvant dans helloMessageInteractive. Nous appelons set() pour component, c’est-à-dire le composant helloMessageInteractive. C’est un schéma qui se répétera pour pratiquement tous les composants que vous créerez : obtenir les valeurs des composants enfants, éventuellement leur appliquer un certain traitement, puis régler les valeurs dans le composant en lui-même.

Modèle de programmation à contrôleur d’affichage des composants Aura

Tout d’abord, une petite vérification. Vous avez tout compris ? Sûr ? Si vous êtes seulement à peu près sûr, assurez-vous d’avoir bien créé le composant helloMessageInteractive à l’aide du code précédent. Ce n’est qu’un seul composant, et le copier/coller du code prend deux minutes, mais il est essentiel de pouvoir jouer avec pour comprendre la gestion des actions.

Ce que vous avez fait jusqu’ici a pu vous sembler très simple, car il n’y avait pas beaucoup de lignes de code. Toutefois, ces lignes de code illustrent certains concepts fondamentaux de la conception d’applications reposant sur des composants Aura.

Vous pouvez considérer que vous attachez les composants aux gestionnaires d’actions, comme si vous les « câbliez ». Considérez helloMessageInteractive comme s’il s’agissait d’un simple circuit électrique. Il y a des interrupteurs et des ampoules (le framework des composants Lightning fournit le courant). En lui-même, un interrupteur peut émettre un joli clic, mais tant que vous ne l’avez pas câblé, il n’est pas très utile. Vous pouvez disposer de l’ampoule à filament la plus furieusement tendance qui soit, mais tant que vous ne l’aurez pas câblée, elle n’éclairera rien du tout.

Il en va de même pour les composants Aura. Nous avons dit précédemment que les différentes ressources d’un lot de composants étaient « autoconnectées » ensemble. Et c’est vrai : le câblage prend la forme des fournisseurs de valeurs v et c. Ces éléments sont automatiquement créés et accessibles dans vos composants, votre contrôleur peut donc faire référence au composant et inversement. Toutefois, cette connexion automatique n’a lieu qu’à haut niveau, dans helloMessageInteractive, entre la ressource .cmp du composant et la ressource .js du contrôleur. La flèche verte de l’illustration suivante symbolise cette relation.

helloMessageInteractive et son contrôleur sont autoconnectés

Par contre, pour créer un lien entre un composant <lightning:button> précis et un gestionnaire d’actions spécifique, c’est-à-dire relier des éléments générant des événements (comme des boutons) à des éléments gérant les événements (comme une fonction de contrôleur spécifique), vous devrez établir manuellement la connexion. Mais en fait, vous l’avez fait vous-même ! Ce sont les flèches rouges nécessaires pour établir un circuit fonctionnel.

Le fait d’ajouter {!c.handleClick} à l’attribut onclick d’un composant <lightning:button> (1) le relie au gestionnaire d’actions spécifique. En outre, le fait d’appeler component.set("v.message", newMessage) (2) relie le résultat de ce gestionnaire d’actions à l’attribut message du composant. Il est lui-même raccordé à l'expression {!v.message}.

Vous pouvez ensuite considérer l’événement onclick comme étant un électron parcourant le circuit que vous avez créé. Si vous ne créez pas de circuit complet, l’événement ne va nulle part et rien ne se passe. Pensez-y lorsque vous commencerez à développer vos propres composants. Votre circuit est-il complet ? Vous êtes sûr ? En cas de doute, vous pouvez vous aider en schématisant le tout sur un tableau ou une feuille, afin de vérifier toutes les connexions.

Vous câblerez si souvent des composants, événements et gestionnaires ensemble à haut et bas niveaux, que vous aurez l’impression d’être un électricien (ou, vu le nom du framework, peut-être Benjamin Franklin). Le câblage est fondamental pour le modèle de programmation de composant Aura.

Alors, allons un peu plus loin. Après tout, la victoire se forge à l’entraînement.

Enchaînement, recâblage et débogage simple de fonctions

Notre première version de handleClick comportait trois lignes de code car nous avions réparti chaque étape du schéma obtenir-traiter-régler sur des lignes distinctes. Vous pouvez utiliser un enchaînement de fonctions pour réduire ce nombre de lignes. Étant donné que vous aurez probablement déjà constaté cela dans d’autres codes de composants Lightning, essayons de le faire nous-mêmes. Ajoutez le code supplémentaire suivant à votre contrôleur helloMessageInteractive, après handleClick.

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        component.set("v.message", newMessage);
    },
    handleClick3: function(component, event, helper) {
        component.set("v.message", event.getSource().get("v.label"));
    }

Houp-là ! Avez-vous obtenu une erreur de syntaxe en essayant d’enregistrer ? Vous souvenez-vous de ce que nous avons dit précédemment, notamment qu’il fallait ajouter des virgules entre vos gestionnaires d’actions ? C’est le problème ici. Ajoutez une virgule après la dernière accolade (« } ») de handleClick, comme vous pouvez le voir à la fin de handleClick2 dans l’extrait précédent.

Ces gestionnaires d’actions font exactement la même chose que handleClick, avec moins de lignes de code. Ils le font en ignorant les variables intermédiaires, souvent en « s’enchaînant » directement à l’appel de fonction suivant, en ajoutant cet appel à la fin du précédent, et en les séparant par une virgule (ce concept sera plus clair si vous examinez les différences entre handleClick et handleClick2).

Le style à utiliser relève de vos préférences personnelles ou du style de codage de votre entreprise. L’humble auteur de ces lignes préfère handleClick2, qui sépare get et set, sans s’ennuyer avec une variable pour le bouton, car nous n’avons besoin que de son libellé.

Bien sûr, vous ne pourrez pas vérifier si les nouveaux gestionnaires d’actions fonctionnent tant que vous n’aurez pas relié un bouton <lightning:button> pour utiliser l’un d’entre eux, en définissant l’attribut onclick sur {!c.handleClick2} ou {!c.handleClick3}. Considérez que c’est comme si vous déconnectiez les fils d’une ampoule pour les connecter à une autre ampoule. C’est aussi simple !

À ce stade, vous rechargez l’application, vous cliquez sur l’un des boutons reconnectés, et… C’est la même chose en termes de conception n’est-ce pas ? Comment pourrions-nous également déterminer le gestionnaire d’actions qui est appelé ?

Les choses les plus simples sont parfois les meilleures. Ajoutons un peu de journalisation à l’une des fonctions du gestionnaire d’actions :

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        console.log("handleClick2: Message: " + newMessage);
        component.set("v.message", newMessage);
    },

Maintenant, si vous reliez un bouton <lightning:button> à handleClick2, vous verrez apparaître un message de journal dans la console JavaScript de votre navigateur dès que vous cliquerez dessus.

Oui, il y a des outils de débogage plus sophistiqués, mais afficher sur la console est une technique permettant de déboguer rapidement. Si vous souhaitez obtenir une sortie à partir d’un objet, quel qu’en soit le type, placez-le dans JSON.stringify(votreObjet) pour obtenir de nombreuses informations utiles. Lorsque vous souhaitez jeter un rapide coup d’œil, console.log() est votre ami.

Nous n’aborderons pas ces techniques et outils de débogage plus sophistiqués ici, mais reportez-vous aux Ressources pour obtenir de superbes outils et instructions.

Bon, helloMessageInteractive était d’une simplicité enfantine et codé en dur (pour un optimisme à toute épreuve). Dans la prochaine unité, nous travaillerons avec quelque chose de plus complexe et apprendrons à capturer les entrées de vrais utilisateurs. Et comme les gens du monde réel ne sont pas toujours aussi positifs, nous apprendrons à valider leur entrée.