Suivez votre progression
Accueil Trailhead
Accueil Trailhead

Découverte des actions Lightning

Objectifs de formation

Une fois cette unité terminée, vous pourrez :
  • Créer une action et un composant Aura pour remplir les champs selon les entrées de l’utilisateur et fournir des messages de commentaire aux utilisateurs
  • Créer une action et un composant Aura s’intégrant à un système tiers
  • Commencer la migration de vos fonctionnalités de bouton JavaScript personnalisées vers des alternatives compatibles Lightning.

Actions Lightning : intelligentes, rapides et mobiles

Nous vous avons présenté plusieurs solutions qui fonctionnent à la fois dans Lightning Experience et Salesforce Classic et remplacent à merveille les boutons JavaScript. Mais nous reconnaissons que ces solutions déclaratives et de programmation ne traitent pas tous les scénarios d’utilisation. La bonne nouvelle, c’est qu’il y a une chose qui en traite de nombreux autres. Introduction d’actions Lightning : actions rapides invoquant des composants Lightning.
Remarque

Remarque

À compter de la version Spring ’19 (version d’API 45.0), vous pouvez créer des composants Lightning à l’aide de deux modèles de programmation : le modèle Composants Web Lightning et le modèle Composants Aura d’origine. Les composants Web Lightning et les composants Aura peuvent coexister et interagir sur une page. Ce contenu aborde les composants Aura.

Les actions Lightning reposent sur l’infrastructure de composants Lightning existante. Vous pouvez aisément convertir vos composants Aura existants en actions et les utiliser dans l’application mobile Salesforce et Lightning Experience.

Pour rendre un composant Aura invocable en tant qu’action, vous devez ajouter une des deux interfaces au composant : force:lightningQuickAction ou force:lightningQuickActionWithoutHeader. La première interface ajoute l’en-tête standard, ainsi que les boutons Enregistrer et Annuler, à la superposition de l’action Lightning, alors que ce n’est pas le cas avec la deuxième interface.

Une autre interface utile pour les actions Lightning est force:hasRecordId, qui fournit le contexte d’enregistrement au composant lorsqu’il est invoqué à partir d’une page d’enregistrement. Si vous configurez votre action Lightning en tant qu’action rapide globale, vous n’avez pas besoin du contexte d’enregistrement. Cependant, si vous souhaitez accéder aux données ou métadonnées d’un enregistrement, vous devez implémenter force:hasRecordId.

Remarque

Remarque

Si vous n’avez jamais conçu de composants Aura auparavant, rendez-vous dans le Centre de développement Lightning, menez à bien le projet Prise en main rapide des composants Aura, puis suivez le module Bases des composants Aura.

Plongeons-nous dans les actions Lightning. Nous aborderons ensuite quelques fonctionnalités de bouton JavaScript qui peuvent être remplacées par des actions Lightning.
  • Remplir les champs en fonction des entrées utilisateur et fournir des messages de commentaire
  • Intégrer des API de fournisseurs tiers

Remplir les champs en fonction des entrées utilisateur et afficher des messages de commentaire à l’attention de ces utilisateurs

Supposons que vous utilisez des boutons JavaScript pour valider ou manipuler des données et afficher des commentaires ou instructions à l’attention de vos utilisateurs lorsqu’ils travaillent avec les enregistrements. Voici un exemple montrant comment vous pouvez facilement valider ou manipuler des données dans un composant Lightning avant que vos utilisateurs ne créent ou mettent à jour un enregistrement.

Dans notre exemple d’organisation, nous avons créé un objet nommé Étude de cas, que nous utilisons pour suivre différents projets de recherche. Lorsque nous ajoutons de nouveaux utilisateurs test, nous capturons leurs noms et adresses e-mail. L’adresse e-mail étant notre principale méthode de contact, nous voulons nous assurer qu’elle est correctement saisie. Nous voulons aussi créer un pseudonyme spécifique à chacun de ces utilisateurs test afin qu’ils puissent rester anonymes.

Nous allons créer une action Lightning qui affiche les champs Nom et Adresse e-mail, valide l’adresse e-mail et utilise le prénom et un nombre aléatoire pour créer automatiquement le pseudonyme.

Voici le code du composant invoqué par cette action Lightning.
  • CreateUser.cmp— Le composant Lightning que vous voyez lorsque vous ouvrez l’action. Il contient l’implémentation de l’interface utilisateur qui, quant à elle, inclut les champs texte, les boutons, le nom de l’action, etc.
  • CreateUserController.js— Le contrôleur qui surveille le composant et tout événement d’interface utilisateur ayant lieu, par exemple, le chargement initial, la saisie de texte et les clics sur des boutons. Sa fonction : déléguer ces événements à la classe d’aide, CreateUserHelper.js.
  • CreateUserHelper.js— Le code qui s'occupe de toute la logique métier, comme la validation des champs mot de passe et e-mail.

CreateUser.cmp

<aura:component implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">
    <aura:attribute name="user" type="Test_User__c" default="{}"/>
    <aura:attribute name="hasErrors" type="Boolean" description="Indicate whether there were failures or not" />
    <aura:attribute name="caseStudy" type="String" />
    <aura:attribute name="recordId" type="String"/>
    <aura:attribute name="errorFromCreate" type="String"/>

    <!-- <aura:handler name="init" value="{!this}" action="{!c.init}" />  -->

    <force:recordData aura:id="frd" mode="EDIT" layoutType="FULL"/>
    
    <div class="slds-page-header" role="banner">
    	<p class="slds-text-heading--label">Case Study</p>
        <h1 class="slds-page-header__title slds-m-right--small slds-truncate slds-align-left" title="Case Study Title">{!v.caseStudy}</h1>
    </div>
    <br/>
    
    <aura:if isTrue="{!v.hasErrors}">
        <div class="userCreateError">
            <ui:message title="Error" severity="error" closable="true">
                Please review the error messages.
            </ui:message>
        </div>
    </aura:if>

    <div class="slds-form--stacked">
                
        <div class="slds-form-element">
            <label class="slds-form-element__label" for="firstName">Enter first name: </label>
            <div class="slds-form-element__control">
              <ui:inputText class="slds-input" aura:id="firstName" value="{!v.user.First}" required="true" keydown="{!c.updateNickname}" updateOn="keydown"/>
            </div>
        </div>
        
        <div class="slds-form-element">
            <label class="slds-form-element__label" for="lastName">Enter last name: </label>
            <div class="slds-form-element__control">
              <ui:inputText class="slds-input" aura:id="lastName" value="{!v.user.Last}" required="true" />
            </div>
        </div>
        
        <div class="slds-form-element">
            <label class="slds-form-element__label" for="nickname">Enter nickname: </label>
            <div class="slds-form-element__control">
              <ui:inputText class="slds-input" aura:id="nickname" value="{!v.user.Nickname}" required="false"/>
            </div>
        </div>
        
        <div class="slds-form-element">
        	<label class="slds-form-element__label" for="userEmail">Enter user's email:</label>
            <div class="slds-form-element__control">
        		<ui:inputEmail class="slds-input" aura:id="userEmail" value="{!v.user.Email__c}" required="true"/>
            </div>
        </div>
        
        <div class="slds-form-element">
        	<label class="slds-form-element__label" for="userPassword">Enter user's password:</label>
            <div class="slds-form-element__control">
        		<ui:inputSecret class="slds-input" aura:id="userPassword" value="{!v.user.Password__c}" required="true"/>
            </div>
        </div>
        
        <div class="slds-form-element">
        	<ui:button class="slds-button slds-button--neutral" press="{!c.cancel}" label="Cancel" />
        	<ui:button class="slds-button slds-button--brand" press="{!c.saveUserForm}" label="Save User" />
        </div>
    </div>

</aura:component>

CreateUserController.js

({    
    /**
     * Auto generate the username from firstName on tab
     */
    updateNickname: function(component, event, helper) {
        // Update the nickname field when 'tab' is pressed
        if (event.getParams().keyCode == 9) {
        	var nameInput = component.find("firstName");
        	var nameValue = nameInput.get("v.value");
        	var nickName = component.find("nickname");
            var today = new Date();
        	nickName.set("v.value", nameValue + today.valueOf(today));   
        }
    },
 
    /**
     * Capture the Inputs and invoke the helper.save with the input params 
     */
	saveUserForm : function(component, event, helper) {
        var name = component.get("v.user.First");
        var last = component.get("v.user.Last");
        var password = component.get("v.user.Password__c");
        var email = component.get("v.user.Email__c");
        var nickname = component.get("v.user.Nickname");
        
        var passwordCmp = component.find("userPassword");
        var emailCmp = component.find("userEmail");
        
        helper.validatePassword(component, event, helper);
        helper.validateEmail(component, event, helper);

        if (passwordCmp.get("v.errors") == null && emailCmp.get("v.errors") == null) {
            component.set("v.hasErrors", false);
        	helper.save(component, name + " " + last, password, email, nickname);         
        } else {
            component.set("v.hasErrors", true);
        }
    },
    
    cancel : function(component, event, helper) {
        $A.get("e.force:closeQuickAction").fire();
    }
})

CreateUserHelper.js

({  
    save: function(component, name, password, email, nickname) {
        // Create a user record, save it, and close the panel
        var userRecord = {apiName: 'Test_User__c', fields: {}};
        userRecord.fields.Name = {value: name};
        userRecord.fields.Password__c = {value: password};
        userRecord.fields.Email__c = {value: email};
        userRecord.fields.Nickname__c = {value: nickname};
        userRecord.fields.Case_Study__c = {value: component.get("v.recordId")};
        // get the force:recordData and set the targetRecord
        component.find("frd").set('v.targetRecord', userRecord); 
        // invoke saveRecord of force:recordData
        component.find("frd").saveRecord($A.getCallback(function(response) {
            if (component.isValid() && response.state == "SUCCESS") {
                $A.get("e.force:closeQuickAction").fire();
                var toastEvent = $A.get("e.force:showToast");
                toastEvent.setParams({
                	"title": "Success!",
                    "message": "The test user has been created."
                });
                toastEvent.fire();		
                $A.get('e.force:refreshView').fire();
            } else if (response.state == "ERROR") {
                console.log('There was a problem and the state is: '+ response.state);
            }
        }));
    },
    
    validatePassword : function(component, event, helper) {
        var inputCmp = component.find("userPassword");
        var value = inputCmp.get("v.value");
        
        if (value == undefined) {
           inputCmp.set("v.errors", [{message: "You must enter a password."}]);
        } else if (value.length < 7 || value.length > 15) {
            inputCmp.set("v.errors", [{message: "The password is the wrong length (must be <= 15): " + value.length}]);
        } else if (value.search(/[0-9]+/) == -1) {
            inputCmp.set("v.errors", [{message: "The password must contain at least one number."}]);
        } else if (value.search(/[a-zA-Z]+/) == -1) {
            inputCmp.set("v.errors", [{message: "The password must contain at least one letter."}]);
        } else {
            inputCmp.set("v.errors", null);
        }
	},
    
    validateEmail : function(component, event, helper) {
        var inputCmp = component.find("userEmail");
        var value = inputCmp.get("v.value");
        
        if (value == undefined) {
           inputCmp.set("v.errors", [{message: "You must enter an email."}]);
           return;
        }
        
        var apos = value.indexOf("@");
        var dotpos = value.lastIndexOf(".");

        if (apos<1||dotpos-apos<2){
            inputCmp.set("v.errors", [{message: "Email is not in the correct format: " + value}]);
        } else if (value.substring(apos+1, dotpos) != "gmail") {
            inputCmp.set("v.errors", [{message: "Email must be a gmail account: " + value.substring(apos+1, dotpos)}]);
        } else {
            inputCmp.set("v.errors", null);
        }
	}
})

Une fois le composant Lightning créé, nous l’affectons à une action. Dans les paramètres de gestion de l’objet Étude de cas, nous nous rendons dans Boutons, liens et actions, nous cliquons sur Nouvelle Action, puis nous configurons l’action avec les paramètres suivants :

Champ Valeur
Nom de l’objet Étude de cas
Type d’action Composant Lightning
Composant Lightning c:CreateUser
Hauteur 500px
Étiquette Créer un utilisateur test
Nom CreateUser

Ensuite, nous ajoutons notre nouvelle action Lightning à la présentation de la page Étude de cas. Lorsque les utilisateurs invoquent cette action Lightning depuis une page d’enregistrement d’étude de cas, elle apparaît.

Superposition de l’action Lightning Créer un utilisateur test

L’intérêt de cette action Lightning est qu’elle fonctionne également dans l’application mobile Salesforce.

Action Étude de cas dans l’application Salesforce

Intégrer des API de fournisseurs tiers

Vous utilisez peut-être des boutons JavaScript afin de les intégrer à des systèmes de fournisseurs tiers. Mais pouvez-vous utiliser des actions Lightning pour cela ? Bien sûr que oui. La principale différence est que pour l’intégration à l’aide d’actions Lightning, vous devez utiliser un contrôleur côté serveur. En retour, vous pouvez mieux gérer la sécurité des informations de connexion et vous avez aussi la possibilité d’utiliser Apex pour les appels d’API asynchrones et par lot.

Voyons comment l’intégration à Twilio pour envoyer des SMS est possible. Nous prendrons ici comme exemple le traitement des célébrités dans l’industrie du tourisme de luxe. Nous voulons que les agents de notre service clientèle puissent communiquer avec leurs clients, mais personne ne doit avoir accès aux coordonnées personnelles des clients. Nous créons une action Lightning pour l’objet Contact de manière à ce que les agents puissent envoyer des messages sans voir le numéro de téléphone du contact.

Comme dans notre exemple d’étude de cas, nous créerons le composant Aura et les classes helper, puis une action rapide pour invoquer le composant.

Superposition de l’action Lightning d’envoi de SMS

Cette action Lightning comprend le composant Aura, un contrôleur JavaScript et un contrôleur Apex, qui référence les classes de bibliothèque gérant l’intégration à Twilio.

SendTwilioSMS.cmp

<aura:component controller="TwilioSendSMSController" implements="flexipage:availableForAllPageTypes,force:hasRecordId,force:lightningQuickAction" >
   <aura:attribute name="textMessage" type="String" />
   <aura:attribute name="destinationNumber" type="String" />
   <aura:attribute name="messageError" type="Boolean" />
   <aura:attribute name="recordId" type="String" />

      <aura:handler name="init" value="{!this}" action="{!c.init}" />

   <aura:if isTrue="{!v.messageError}">
      <!-- Load error -->
      <div class="userCreateError">
         <ui:message title="Error" severity="error" closable="true">
            Unable to send message. Please review your data and try again.
         </ui:message>
      </div>
   </aura:if>

   <div class="slds-form--stacked">
      <label class="slds-form-element__label" for="instructMsg">Please enter the message (max 160 char) below: </label>
      <br/>
      <div class="slds-form-element__control">
         <ui:inputText class="slds-input" aura:id="message" label="Text Message" value="{!v.textMessage}" required="true" maxlength="160" size="165" />
      </div>
      <div class="centered">
         <ui:button class="slds-button slds-button--brand" press="{!c.sendMessage}" label="Send Message"/>
      </div>
   </div>
</aura:component>

SendTwilioSmsController.js

({
   init : function(component, event, helper) {
      var action = component.get("c.getPhoneNumber");
      action.setParams({"contactId": component.get("v.recordId")});
      action.setCallback(this, function(response) {
         var state = response.getState();
         if(component.isValid() && state == "SUCCESS"){
            component.set("v.destinationNumber", response.getReturnValue());
         } else {
            component.set("v.messageError", true);
         }
      });
      $A.enqueueAction(action);
   },

      sendMessage : function(component, event, helper) {
      var smsMessage = component.get("v.textMessage");
      var number = component.get("v.destinationNumber");
      var recordId = component.get("v.recordId")

      var action = component.get("c.sendMessages");
      action.setParams({"mobNumber": number, "message": smsMessage, "contactId": component.get("v.recordId")});
      action.setCallback(this, function(response) {
         var state = response.getState();
         if(component.isValid() && state == "SUCCESS"){
            $A.get("e.force:closeQuickAction").fire();
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
               "title": "Success!",
               "message": "SMS has been sent woo hoo!"
            });
            toastEvent.fire();
         } else {
            component.set("v.messageError", true);
         }
      });
      $A.enqueueAction(action);
   }
})

SendTwilioSmsController.apxc

/*
* Apex controller that currently contains only one method to send sms message
*/
global class TwilioSendSMSController {

   /*
   * This method uses the Twilio for Salesforce library class and method to
   * send the message using the Twilio api.
   */
   @AuraEnabled
      webService static String sendMessages(String mobNumber, String message, Id contactId) {
         System.debug('the mobNumber is: '+ mobNumber + ' and the message is: '+ message + ' and contactId is: ' + contactId);

         if (mobNumber == null) {
            mobNumber = getPhoneNumber(contactId);
         }

         try {
            TwilioRestClient client = TwilioAPI.getDefaultClient();

            Map<String,String> params = new Map<String,String> {
               'To' => mobNumber,
               'From' => '15555551234',
               'Body' => message
               };
            TwilioSMS sms = client.getAccount().getSMSMessages().create(params);
            return sms.getStatus();
         } catch(exception ex) {
            System.debug('oh no, it failed: '+ex);
            return 'failed';
         }
      }

      @AuraEnabled
      public static String getPhoneNumber(Id contactId) {
         Contact currentRecord = [SELECT Phone FROM Contact WHERE Id = :contactId];
         return currentRecord.Phone.replace(' ', '').replace('-', '').replace(')', '').replace('(', '');
   }
}

Une fois le composant créé, nous créons une action Lightning. Cette fois, nous l’ajoutons à la présentation de la page Contact afin que les agents puissent y accéder.

Une fois encore, l’action est également accessible dans l’application mobile Salesforce, ce qui est plutôt pratique. Si un prestataire de service de voiture tente de contacter le client à l’aéroport, le chauffeur peut utiliser un appareil mobile pour le faire en toute simplicité.

Action SMS Lightning dans l’application Salesforce

Les actions Lightning sont l’avenir des actions de programmation dans Lightning Experience. Nous espérons que vous commencez à envisager cet ensemble de solutions comme la meilleure alternative aux boutons JavaScript.

Et si vous dépendez d’applications partenaires utilisant des boutons JavaScript, vous serez ravi d’apprendre qu’un grand nombre de nos partenaires ont déjà commencé la migration et la mise à niveau de leurs applications vers Lightning. Vous trouverez davantage d’applications mises à jour pour Lightning Experience via AppExchange.

Au-delà des concepts de base

Si vous souhaitez essayer vous-même Twilio, vous pouvez trouver un package non géré de Twilio pour la classe de bibliothèque Salesforce utilisée dans l’exemple d’intégration à des produits de fournisseurs tiers en vous rendant dans la bibliothèque Github Salesforce : https://github.com/twilio/twilio-salesforce

Avant d’utiliser Twilio pour Salesforce et l’API Twilio, créez un compte Twilio, paramétrez un numéro de téléphone et associez votre compte à Salesforce. Reportez-vous à TwilioApi.cls dans la bibliothèque Github pour obtenir des instructions plus détaillées.