SlideShare une entreprise Scribd logo
1  sur  35
Télécharger pour lire hors ligne
Workshop – Lightning Web Components
Bordeaux Salesforce Developer Group
@martinlezer
Martin Lezer, Group Leader
Productivité améliorée
Utilisation des langages modernes du Web: ES6+,
Elements personnalisés, et Shadow DOM
Conçu pour la performance
Plus de code exécuté par le navigateur au lieu
d’abstractions Javascript pour une expérience plus
rapide
Compatible et facile à utiliser
Exécuté simultanément avec des composants Lightning
existants
Introduction - Lightning Web Components
Un nouveau modèle de programmation construit sur les standards du Web
Aura vs LWC
Workshop
Installation de l’environnement
Installation de l’environnement
• Utilisez le lien correspondant à votre environnement
Installation de Salesforce DX
Operating System
Link to Installer
macOS https://sfdc.co/sfdx_cli_osx
Windows 32-bit https://sfdc.co/sfdx_cli_win
Windows 64-bit https://sfdc.co/sfdx_cli_win64
Debian/Ubuntu 64 https://sfdc.co/sfdx_cli_linux
Download the archive from one of the URLs in the manifest, extract the archive, then run the ./install script.
Debian/Ubuntu x86 https://sfdc.co/sfdx_cli_linux_x86
Download the archive from one of the URLs in the manifest, extract the archive, then run the ./install script.
• Téléchargez l'installeur de Visual Studio Code : https://code.visualstudio.com/
• Installez Visual Studio Code grâce à l'installeur
• Lancez Visual Studio Code à la fin de l'installation
• Cliquez sur l'icône dans la barre de navigation de gauche
• Cherchez l’extension appelée « Salesforce Extension Pack »
• Installez l’extension
• Rechargez Visual Studio Code à la fin de l’installation
Installation de Visual Studio Code
Installation de l’environnement
Lightning Web Components
Development
Les bases
• Fichier HTML:
• nommé suivant la convention: <component>.html
• avec comme balise racine: <template>
• Fichier Javascript:
• nommé suivant la convention: <component>.js
• chaque fichier de composant doit inclure le code suivant:
Structure des fichiers d’un composant
Les bases
import { LightningElement } from 'lwc’;
export default class MyComponent extends LightningElement {
}
// Your code here
• Equivalent aux attributs sur Aura
• Variables Javascript accessibles à certaines
conditions par le template HTML
Propriétés
Les bases
import { LightningElement, api, track } from 'lwc’;
export default class TodoItem extends LightningElement {
@api itemTitle = ''; // public
itemId = ''; // private
@track state = { x: 100, y: 100 }; // internal and reactive
}• Différents types de propriétés:
• privée: variable seulement utilisée dans le
code Javascript
• réactives: si la valeur d’une variable change,
elle est mise à jour dans le template
• publique: accessible par un composant parent
• tracked: variable privée
<template>
<div class="view">
<label>{itemName}</label>
</div>
</template>
Controller Javascript
Template
• Les expressions Aura complexes sont transformées en code Javascript
• Utilisation de getters dans le code Javascript
Expressions HTML et logique Javascript
Les bases
<aura:if isTrue="{!v.page > 1}">
<lightning:buttonIcon iconName="utility:left" variant="border" onclick="{!c.previousPage}"/>
</aura:if>
Code Aura Framework
Code LWC
<template if:false={isFirstPage}>
<lightning-button-icon icon-name="utility:chevronleft" onclick={previousHandler}></lightning-button-icon>
</template>
import { LightningElement, api } from 'lwc’;
export default class Paginator extends LightningElement {
/** The current page number. */
@api pageNumber; get isFirstPage() {
return this.pageNumber === 1;
}
}
Les bases
• Rendu conditionnel
• Itérations
Expressions HTML
<template>
<lightning-card title="HelloConditionalRendering" icon-name="custom:custom14">
<template if:true={areDetailsVisible}>
<div class="slds-m-vertical_medium"> These are the details! </div>
</template>
</lightning-card>
</template>
<template>
<lightning-card title="HelloForEach" icon-name="custom:custom14">
<ul class="slds-m-around_medium">
<template for:each={contacts} for:item="contact">
<li key={contact.Id}> {contact.Name}, {contact.Title} </li>
</template>
</ul>
</lightning-card>
</template>
Equivalent Aura
<aura:iteration items="{!v.items}" itemVar="item">
Equivalent Aura
<aura:if isTrue="{!v.something}">
• Code exécute à l’initialisation
Logique Javascript
Les bases
import { LightningElement } from 'lwc’;
export default class MySampleInit extends LightningElement {
connectedCallback() {
// initialize component
}
}
Equivalent Aura
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
({
doInit: function(cmp) {
// initialize component
}
})
• Utilisation de CSS standard
• Limité au contexte du composant
• Inclus dans un fichier css rattaché au composant
CSS
Les bases
<template>
<h1>To Do List (h1)</h1>
</template>
h1 {
font-size: xx-large;
}
Template
CSS
<!-- contactListItem.html -->
<template>
<a href="#" onclick={selectHandler}>
<lightning-layout vertical-align="center">
<lightning-layout-item>
<img src={contact.Picture__c}></img>
</lightning-layout-item>
<lightning-layout-item padding="around-small">
<p>{contact.Name}</p>
</lightning-layout-item>
</lightning-layout>
</a>
</template>
• Utilisation des standards du web avec le
constructeur CustomEvent()
• Un composant parent peut capter un
événement d’un enfant
Evénements personnalisés
Les bases
• L’enfant défini le nom du l’événement ainsi
que les données associées. Ensuite, il le
dispatch avec la méthode
EventTarget.dispatchEvent()
• Le parent définit une fonction handler de
l’événement
Template enfant
Javascript enfant
// contactListItem.js import { LightningElement, api } from 'lwc’;
export default class ContactListItem extends LightningElement {
@api contact;
selectHandler(event) {
// Prevents the anchor element from navigating to a URL.
event.preventDefault();
// Creates the event with the contact ID data.
const selectedEvent = new CustomEvent(
'selected’,
{ detail: this.contact.Id }
);
// Dispatches the event.
this.dispatchEvent(selectedEvent);
}
}
Les bases
Evénements personnalisés (suite)
Template parent
<!-- eventWithData.html -->
<template>
<lightning-card title="EventWithData" icon-name="custom:custom9">
<lightning-layout class="slds-m-around_medium">
<lightning-layout-item>
<template if:true={listIsNotEmpty}>
<template for:each={contacts.data} for:item="contact">
<c-contact-list-item key={contact.Id} contact={contact} onselected={contactSelected}></c-contact-list-item>
</template>
</template>
</lightning-layout-item>
<lightning-layout-item class="slds-m-left_medium">
<template if:true={selectedContact}>
<img src={selectedContact.Picture__c}></img>
<p>{selectedContact.Name}</p>
<p>{selectedContact.Title}</p>
<p><lightning-formatted-phone value={selectedContact.Phone}></lightning-formatted-phone></p>
<p><lightning-formatted-email value={selectedContact.Email}></lightning-formatted-email></p>
</template>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
</template>
// eventWithData.js
import { LightningElement, wire, track } from 'lwc’;
import getContactList from '@salesforce/apex/ContactController.getContactList’;
export default class EventWithData extends LightningElement {
@track selectedContact;
@wire(getContactList) contacts;
contactSelected(event) {
const contactId = event.detail;
this.selectedContact = this.contacts.data.find(contact => contact.Id === contactId);
}
get listIsNotEmpty() {
return this.contacts && Array.isArray(this.contacts.data) && this.contacts.data.length > 0;
}
}
Javascript parent
Les bases
Evénements personnalisés (suite)
Lightning Web Components
Development
L’intéraction avec les données
L’intéraction avec les données
Wire Service
• Surcouche du Lightning Data Service
• Permet de lire ou créer un enregistrement sans appel Apex, seulement du Javascript
• Appelable grâce à l’annotation @wire
• Les références vers les objets et champs utilisés doivent être importées afin de:
• empêcher la suppression de l’objet ou du champ
• vérifier à l’exécution que les références existent
• vérifier l’inclusion des champs et objets utilisés dans le change set
• L’import des références se fait sous la forme suivante:
import objectName from '@salesforce/schema/object';
import FIELD_NAME from '@salesforce/schema/object.field';
L’intéraction avec les données
Wire Service (suite)
• Lecture d’un enregistrement
<template>
<lightning-card title="My Contact Record" icon-name="standard:contact">
<template if:true={contact.data}>
<div class="slds-m-around_medium">
<p>{name}</p>
<p>{title}</p>
<p><lightning-formatted-phone value={phone}></lightning-formatted-phone></p>
<p><lightning-formatted-email value={email}></lightning-formatted-email></p>
</div>
</template>
</lightning-card>
</template>
Template
L’intéraction avec les données
Wire Service (suite)
• Lecture d’un enregistrement (suite): utilisation de la méthode
// wireGetRecordDynamicContact.js
import { LightningElement, api, wire } from 'lwc’;
import { getRecord } from 'lightning/uiRecordApi’;
const FIELDS = [ 'Contact.Name', 'Contact.Title', 'Contact.Phone', 'Contact.Email', ];
export default class WireGetRecordDynamicContact extends LightningElement {
@api recordId;
@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) contact;
get name() {
return this.contact.data.fields.Name.value;
}
get title() {
return this.contact.data.fields.Title.value;
}
get phone() {
return this.contact.data.fields.Phone.value;
}
get email() {
return this.contact.data.fields.Email.value;
}
}
Javascript Controller
getRecord
L’intéraction avec les données
Wire Service (suite)
• Création d’un enregistrement
Template
<template>
<lightning-card title="LdsCreateRecord" icon-name="standard:record">
<div class="slds-m-around_medium">
<lightning-input label="Id" disabled value={accountId}></lightning-input>
<lightning-input label="Name" onchange={handleNameChange} class="slds-m-bottom_x-small"></lightning-input>
<lightning-button label="Create Account" variant="brand" onclick={createAccount}></lightning-button>
</div>
</lightning-card>
</template>
L’intéraction avec les données
Wire Service (suite)
• Création d’un enregistrement:
Javascript Controller
• Utilisation de la méthode
createRecord()
import { LightningElement, track } from 'lwc’;
import { createRecord } from 'lightning/uiRecordApi’;
import { ShowToastEvent } from 'lightning/platformShowToastEvent’;
import ACCOUNT_OBJECT from '@salesforce/schema/Account’;
import NAME_FIELD from '@salesforce/schema/Account.Name’;
export default class LdsCreateRecord extends LightningElement {
@track accountId;
name = ‘’;
handleNameChange(event) {
this.accountId = undefined;
this.name = event.target.value;
}
createAccount() {
const fields = {};
fields[NAME_FIELD.fieldApiName] = this.name;
const recordInput = { apiName: ACCOUNT_OBJECT.objectApiName, fields };
createRecord(recordInput) .then(account => {
this.accountId = account.id;
this.dispatchEvent(
new ShowToastEvent({
title: 'Success’,
message: 'Account created’,
variant: 'success’,
}),
);
}) .catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record’,
message: error.body.message,
variant: 'error’,
}),
);
});
}
}
L’intéraction avec les données
L’appel aux méthodes Apex
• Nécessaire seulement si le besoin n’est pas couvert par le wire service ou les composants
standards tels que le Lightning Record Form ou les Lightning Record View Form et
Lightning Record Edit Form
• Nécessite l’import de la méthode avec la syntaxe:
• Comme pour le framework Aura, une méthode Apex se rend disponible à l’appel grâce à
l’annotation @AuraEnabled
• Il est possible de lier une propriété ou méthode Javascript à l’appel de la méthode Apex (à
condition qu’elle soit définit comme cachable) avec la syntaxe:
import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodReference';
@wire(apexMethod, { apexMethodParams })
propertyOrFunction;
L’intéraction avec les données
L’appel aux méthodes Apex
• Appel d’une méthode cachable
// ContactController.cls
public with sharing class ContactController {
@AuraEnabled(cacheable=true)
public static List<Contact> getContactList() {
return [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Picture__c != null LIMIT 10];
}
}
Apex
// apexWireMethodToProperty.js
import { LightningElement, wire } from 'lwc’;
import getContactList from '@salesforce/apex/ContactController.getContactList;
export default class ApexWireMethodToProperty extends LightningElement {
@wire(getContactList) contacts;
}
Javascript Controller
L’intéraction avec les données
L’appel aux méthodes Apex
• Appel d’une méthode non cachable: pas de possibilité d’utiliser le wire service
// apexImperativeMethod.js
import { LightningElement, track } from 'lwc’;
import getContactList from '@salesforce/apex/ContactController.getContactList’;
export default class ApexImperativeMethod extends LightningElement {
@track contacts;
@track error;
handleLoad() {
getContactList()
.then(result => {
this.contacts = result;
})
.catch(error => {
this.error = error;
});
}
}
Lightning Web Components Development
Migration Aura vers LWC
• Technologies fondamentalement différentes -> Analyse préalable du composant
• Aura et LWC peuvent cohabiter -> un composant Aura peut inclure un composant LWC
• Commencer par les composants les plus simples -> probablement les composants enfants
(voir notion précédente)
Stratégie
Migration Aura vers LWC
Exercice
Création d’un formulaire d’ajout de contact et affichage
dynamique de la liste des contacts de l’organisation
• Créez une nouvelle organisation Salesforce de type Developer Edition en cliquant ici:
https://developer.salesforce.com/signup
• Activez My Domain
• Activez le Dev Hub
• Dans Visual Studio Code, exécutez les commandes suivantes:
• sfdx force:auth:web:login --setdefaultdevhubusername --setalias DevHub
• Connectez vous à votre developer edition nouvellement créée
• sfdx force:project:create -n workshopLWC
• cd workshopLWC
• sfdx force:org:create -s -f config/project-scratch-def.json -a worshopLWCSScratch
Configuration de Salesforce DX
Exercice
• Dans Visual Studio Code:
• Ouvrez la palette de commande avec le raccourci Ctrl+Shif+P
• Exécutez SFDX: Create Lightning Web Component
• Nommez votre composant listContacts
• Utilisez la librairie de composants standards fournie par Salesforce pour développer votre
composant
• Pour rappel, le composant doit contenir un formulaire de création de contact (voir le wire service
précédemment évoqué) et une liste des contacts en base
• Le formulaire de création doit au moins contenir les champs: prénom, nom et email
• Il serait préférable d’ajouter chacune de ces fonctionnalités dans des cards différentes
Création du Lightning Web Component
Exercice
• Configurez le composant pour qu’il puisse être ajouté aux pages Lightning en utilisant le
code suivant dans le fichier listContact.js-meta.xml:
• Dans Visual Studio Code, une fois le code enregistré, exécutez les commandes:
• sfdx force:source:push
• sfdx force:org:open
• Ajoutez le composant créé à la page Lightning que vous souhaitez puis testez votre
composant !
Création du Lightning Web Component (suite)
Exercice
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="listContacts">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
• Le code correspondant à la correction de l’exercice est disponible sur Github à l’adresse:
https://github.com/mlezer/bordeaux-dev-group-lwc
• Pour aller plus loin, rendez-vous sur https://github.com/trailheadapps/lwc-recipes
Corrrection
Exercice
Kahoot
Rendez-vous sur kahoot.it pour
gagner une batterie externe Astro !
Prochain Meetup – 20 juin
TrailheadDX Global Gathering France
Bordeaux
Paris
Rivieira
Toulouse
Nantes
Lille
Workshop Lightning Web Components

Contenu connexe

Similaire à Workshop Lightning Web Components

Migrez vos composants Lightning vers Lightning Web Components
Migrez vos composants Lightning vers Lightning Web ComponentsMigrez vos composants Lightning vers Lightning Web Components
Migrez vos composants Lightning vers Lightning Web ComponentsMartin Lezer
 
I don't always write reactive application but when I do, it run on raspberry pi
I don't always write reactive application but when I do, it run on raspberry piI don't always write reactive application but when I do, it run on raspberry pi
I don't always write reactive application but when I do, it run on raspberry piadelegue
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Gregory Renard
 
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Gregory Renard
 
Java dans Windows Azure, l'exemple de JOnAS
Java dans Windows Azure, l'exemple de JOnASJava dans Windows Azure, l'exemple de JOnAS
Java dans Windows Azure, l'exemple de JOnASGuillaume Sauthier
 
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs WebUne visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs WebFrédéric Harper
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express jsAbdoulaye Dieng
 
Introduction à AngularJS
Introduction à AngularJSIntroduction à AngularJS
Introduction à AngularJSAbdoulaye Dieng
 
Asp Au Service Des Mv Ps
Asp Au Service Des Mv PsAsp Au Service Des Mv Ps
Asp Au Service Des Mv PsGregory Renard
 
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - Cours
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - CoursENIB cours CAI Web - Séance 4 - Frameworks/Spring - Cours
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - CoursHoracio Gonzalez
 
Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?GreenIvory
 
Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Martin Latrille
 
Workshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationWorkshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationAntoine Rey
 
Aperçu de RequireJS
Aperçu de RequireJSAperçu de RequireJS
Aperçu de RequireJSVISEO
 
cours8-GL-minfo-1718.pdf
cours8-GL-minfo-1718.pdfcours8-GL-minfo-1718.pdf
cours8-GL-minfo-1718.pdfSliimAmiri
 
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016Tarik Zakaria Benmerar
 

Similaire à Workshop Lightning Web Components (20)

Migrez vos composants Lightning vers Lightning Web Components
Migrez vos composants Lightning vers Lightning Web ComponentsMigrez vos composants Lightning vers Lightning Web Components
Migrez vos composants Lightning vers Lightning Web Components
 
I don't always write reactive application but when I do, it run on raspberry pi
I don't always write reactive application but when I do, it run on raspberry piI don't always write reactive application but when I do, it run on raspberry pi
I don't always write reactive application but when I do, it run on raspberry pi
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
 
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
Visual Basic 9.0 – Visual Studio 2008 Quoi De Neuf 2.0
 
Java dans Windows Azure, l'exemple de JOnAS
Java dans Windows Azure, l'exemple de JOnASJava dans Windows Azure, l'exemple de JOnAS
Java dans Windows Azure, l'exemple de JOnAS
 
Starter Kits
Starter KitsStarter Kits
Starter Kits
 
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs WebUne visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
Une visite guidée d’Internet Explorer 9 et HTML5 pour les développeurs Web
 
Introduction aspnet
Introduction aspnetIntroduction aspnet
Introduction aspnet
 
Initiation à Express js
Initiation à Express jsInitiation à Express js
Initiation à Express js
 
Introduction à AngularJS
Introduction à AngularJSIntroduction à AngularJS
Introduction à AngularJS
 
Asp Au Service Des Mv Ps
Asp Au Service Des Mv PsAsp Au Service Des Mv Ps
Asp Au Service Des Mv Ps
 
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - Cours
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - CoursENIB cours CAI Web - Séance 4 - Frameworks/Spring - Cours
ENIB cours CAI Web - Séance 4 - Frameworks/Spring - Cours
 
Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?
 
Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)
 
Workshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationWorkshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring Integration
 
Aperçu de RequireJS
Aperçu de RequireJSAperçu de RequireJS
Aperçu de RequireJS
 
cours8-GL-minfo-1718.pdf
cours8-GL-minfo-1718.pdfcours8-GL-minfo-1718.pdf
cours8-GL-minfo-1718.pdf
 
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016
Web Components et Polymer 2 - GDG Algiers DevFest 2016 - 3 Décembre 2016
 

Plus de Bordeaux Salesforce Developer Group

Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...
Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...
Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...Bordeaux Salesforce Developer Group
 
Introduction to Mulesoft and Salesforce Spring '19 release features
Introduction to Mulesoft and Salesforce Spring '19 release featuresIntroduction to Mulesoft and Salesforce Spring '19 release features
Introduction to Mulesoft and Salesforce Spring '19 release featuresBordeaux Salesforce Developer Group
 

Plus de Bordeaux Salesforce Developer Group (13)

Salesforce Spring '21 - Release Overview
Salesforce Spring '21 - Release OverviewSalesforce Spring '21 - Release Overview
Salesforce Spring '21 - Release Overview
 
Summer '20 Release Overview
Summer '20 Release OverviewSummer '20 Release Overview
Summer '20 Release Overview
 
Why and how to build your career on Salesforce ?
Why and how to build your career on Salesforce ?Why and how to build your career on Salesforce ?
Why and how to build your career on Salesforce ?
 
Salesforce Spring'20 Features
Salesforce Spring'20 FeaturesSalesforce Spring'20 Features
Salesforce Spring'20 Features
 
Dreamforce Global Gathering
Dreamforce Global Gathering Dreamforce Global Gathering
Dreamforce Global Gathering
 
Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...
Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...
Winter '20 Salesforce Release for Admins and Developers + New Salesforce Mobi...
 
Workshop - Lightning Web Components
Workshop - Lightning Web ComponentsWorkshop - Lightning Web Components
Workshop - Lightning Web Components
 
Introduction to Mulesoft and Salesforce Spring '19 release features
Introduction to Mulesoft and Salesforce Spring '19 release featuresIntroduction to Mulesoft and Salesforce Spring '19 release features
Introduction to Mulesoft and Salesforce Spring '19 release features
 
Introduction to Lightning Web Components
Introduction to Lightning Web ComponentsIntroduction to Lightning Web Components
Introduction to Lightning Web Components
 
Bordeaux FR Developers Group - Dreamforce 18 Global Gathering
Bordeaux FR Developers Group  - Dreamforce 18 Global GatheringBordeaux FR Developers Group  - Dreamforce 18 Global Gathering
Bordeaux FR Developers Group - Dreamforce 18 Global Gathering
 
Lightning Components Best Practices by Fabien Taillon
Lightning Components Best Practices by Fabien TaillonLightning Components Best Practices by Fabien Taillon
Lightning Components Best Practices by Fabien Taillon
 
Dreamforce global gathering
Dreamforce global gatheringDreamforce global gathering
Dreamforce global gathering
 
Salesforce Winter'18 - Platform Events - Salesforce DX
Salesforce Winter'18 - Platform Events - Salesforce DXSalesforce Winter'18 - Platform Events - Salesforce DX
Salesforce Winter'18 - Platform Events - Salesforce DX
 

Workshop Lightning Web Components

  • 1. Workshop – Lightning Web Components Bordeaux Salesforce Developer Group @martinlezer Martin Lezer, Group Leader
  • 2. Productivité améliorée Utilisation des langages modernes du Web: ES6+, Elements personnalisés, et Shadow DOM Conçu pour la performance Plus de code exécuté par le navigateur au lieu d’abstractions Javascript pour une expérience plus rapide Compatible et facile à utiliser Exécuté simultanément avec des composants Lightning existants Introduction - Lightning Web Components Un nouveau modèle de programmation construit sur les standards du Web
  • 5. Installation de l’environnement • Utilisez le lien correspondant à votre environnement Installation de Salesforce DX Operating System Link to Installer macOS https://sfdc.co/sfdx_cli_osx Windows 32-bit https://sfdc.co/sfdx_cli_win Windows 64-bit https://sfdc.co/sfdx_cli_win64 Debian/Ubuntu 64 https://sfdc.co/sfdx_cli_linux Download the archive from one of the URLs in the manifest, extract the archive, then run the ./install script. Debian/Ubuntu x86 https://sfdc.co/sfdx_cli_linux_x86 Download the archive from one of the URLs in the manifest, extract the archive, then run the ./install script.
  • 6. • Téléchargez l'installeur de Visual Studio Code : https://code.visualstudio.com/ • Installez Visual Studio Code grâce à l'installeur • Lancez Visual Studio Code à la fin de l'installation • Cliquez sur l'icône dans la barre de navigation de gauche • Cherchez l’extension appelée « Salesforce Extension Pack » • Installez l’extension • Rechargez Visual Studio Code à la fin de l’installation Installation de Visual Studio Code Installation de l’environnement
  • 8. • Fichier HTML: • nommé suivant la convention: <component>.html • avec comme balise racine: <template> • Fichier Javascript: • nommé suivant la convention: <component>.js • chaque fichier de composant doit inclure le code suivant: Structure des fichiers d’un composant Les bases import { LightningElement } from 'lwc’; export default class MyComponent extends LightningElement { } // Your code here
  • 9. • Equivalent aux attributs sur Aura • Variables Javascript accessibles à certaines conditions par le template HTML Propriétés Les bases import { LightningElement, api, track } from 'lwc’; export default class TodoItem extends LightningElement { @api itemTitle = ''; // public itemId = ''; // private @track state = { x: 100, y: 100 }; // internal and reactive }• Différents types de propriétés: • privée: variable seulement utilisée dans le code Javascript • réactives: si la valeur d’une variable change, elle est mise à jour dans le template • publique: accessible par un composant parent • tracked: variable privée <template> <div class="view"> <label>{itemName}</label> </div> </template> Controller Javascript Template
  • 10. • Les expressions Aura complexes sont transformées en code Javascript • Utilisation de getters dans le code Javascript Expressions HTML et logique Javascript Les bases <aura:if isTrue="{!v.page > 1}"> <lightning:buttonIcon iconName="utility:left" variant="border" onclick="{!c.previousPage}"/> </aura:if> Code Aura Framework Code LWC <template if:false={isFirstPage}> <lightning-button-icon icon-name="utility:chevronleft" onclick={previousHandler}></lightning-button-icon> </template> import { LightningElement, api } from 'lwc’; export default class Paginator extends LightningElement { /** The current page number. */ @api pageNumber; get isFirstPage() { return this.pageNumber === 1; } }
  • 11. Les bases • Rendu conditionnel • Itérations Expressions HTML <template> <lightning-card title="HelloConditionalRendering" icon-name="custom:custom14"> <template if:true={areDetailsVisible}> <div class="slds-m-vertical_medium"> These are the details! </div> </template> </lightning-card> </template> <template> <lightning-card title="HelloForEach" icon-name="custom:custom14"> <ul class="slds-m-around_medium"> <template for:each={contacts} for:item="contact"> <li key={contact.Id}> {contact.Name}, {contact.Title} </li> </template> </ul> </lightning-card> </template> Equivalent Aura <aura:iteration items="{!v.items}" itemVar="item"> Equivalent Aura <aura:if isTrue="{!v.something}">
  • 12. • Code exécute à l’initialisation Logique Javascript Les bases import { LightningElement } from 'lwc’; export default class MySampleInit extends LightningElement { connectedCallback() { // initialize component } } Equivalent Aura <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> ({ doInit: function(cmp) { // initialize component } })
  • 13. • Utilisation de CSS standard • Limité au contexte du composant • Inclus dans un fichier css rattaché au composant CSS Les bases <template> <h1>To Do List (h1)</h1> </template> h1 { font-size: xx-large; } Template CSS
  • 14. <!-- contactListItem.html --> <template> <a href="#" onclick={selectHandler}> <lightning-layout vertical-align="center"> <lightning-layout-item> <img src={contact.Picture__c}></img> </lightning-layout-item> <lightning-layout-item padding="around-small"> <p>{contact.Name}</p> </lightning-layout-item> </lightning-layout> </a> </template> • Utilisation des standards du web avec le constructeur CustomEvent() • Un composant parent peut capter un événement d’un enfant Evénements personnalisés Les bases • L’enfant défini le nom du l’événement ainsi que les données associées. Ensuite, il le dispatch avec la méthode EventTarget.dispatchEvent() • Le parent définit une fonction handler de l’événement Template enfant Javascript enfant // contactListItem.js import { LightningElement, api } from 'lwc’; export default class ContactListItem extends LightningElement { @api contact; selectHandler(event) { // Prevents the anchor element from navigating to a URL. event.preventDefault(); // Creates the event with the contact ID data. const selectedEvent = new CustomEvent( 'selected’, { detail: this.contact.Id } ); // Dispatches the event. this.dispatchEvent(selectedEvent); } }
  • 15. Les bases Evénements personnalisés (suite) Template parent <!-- eventWithData.html --> <template> <lightning-card title="EventWithData" icon-name="custom:custom9"> <lightning-layout class="slds-m-around_medium"> <lightning-layout-item> <template if:true={listIsNotEmpty}> <template for:each={contacts.data} for:item="contact"> <c-contact-list-item key={contact.Id} contact={contact} onselected={contactSelected}></c-contact-list-item> </template> </template> </lightning-layout-item> <lightning-layout-item class="slds-m-left_medium"> <template if:true={selectedContact}> <img src={selectedContact.Picture__c}></img> <p>{selectedContact.Name}</p> <p>{selectedContact.Title}</p> <p><lightning-formatted-phone value={selectedContact.Phone}></lightning-formatted-phone></p> <p><lightning-formatted-email value={selectedContact.Email}></lightning-formatted-email></p> </template> </lightning-layout-item> </lightning-layout> </lightning-card> </template>
  • 16. // eventWithData.js import { LightningElement, wire, track } from 'lwc’; import getContactList from '@salesforce/apex/ContactController.getContactList’; export default class EventWithData extends LightningElement { @track selectedContact; @wire(getContactList) contacts; contactSelected(event) { const contactId = event.detail; this.selectedContact = this.contacts.data.find(contact => contact.Id === contactId); } get listIsNotEmpty() { return this.contacts && Array.isArray(this.contacts.data) && this.contacts.data.length > 0; } } Javascript parent Les bases Evénements personnalisés (suite)
  • 18. L’intéraction avec les données Wire Service • Surcouche du Lightning Data Service • Permet de lire ou créer un enregistrement sans appel Apex, seulement du Javascript • Appelable grâce à l’annotation @wire • Les références vers les objets et champs utilisés doivent être importées afin de: • empêcher la suppression de l’objet ou du champ • vérifier à l’exécution que les références existent • vérifier l’inclusion des champs et objets utilisés dans le change set • L’import des références se fait sous la forme suivante: import objectName from '@salesforce/schema/object'; import FIELD_NAME from '@salesforce/schema/object.field';
  • 19. L’intéraction avec les données Wire Service (suite) • Lecture d’un enregistrement <template> <lightning-card title="My Contact Record" icon-name="standard:contact"> <template if:true={contact.data}> <div class="slds-m-around_medium"> <p>{name}</p> <p>{title}</p> <p><lightning-formatted-phone value={phone}></lightning-formatted-phone></p> <p><lightning-formatted-email value={email}></lightning-formatted-email></p> </div> </template> </lightning-card> </template> Template
  • 20. L’intéraction avec les données Wire Service (suite) • Lecture d’un enregistrement (suite): utilisation de la méthode // wireGetRecordDynamicContact.js import { LightningElement, api, wire } from 'lwc’; import { getRecord } from 'lightning/uiRecordApi’; const FIELDS = [ 'Contact.Name', 'Contact.Title', 'Contact.Phone', 'Contact.Email', ]; export default class WireGetRecordDynamicContact extends LightningElement { @api recordId; @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) contact; get name() { return this.contact.data.fields.Name.value; } get title() { return this.contact.data.fields.Title.value; } get phone() { return this.contact.data.fields.Phone.value; } get email() { return this.contact.data.fields.Email.value; } } Javascript Controller getRecord
  • 21. L’intéraction avec les données Wire Service (suite) • Création d’un enregistrement Template <template> <lightning-card title="LdsCreateRecord" icon-name="standard:record"> <div class="slds-m-around_medium"> <lightning-input label="Id" disabled value={accountId}></lightning-input> <lightning-input label="Name" onchange={handleNameChange} class="slds-m-bottom_x-small"></lightning-input> <lightning-button label="Create Account" variant="brand" onclick={createAccount}></lightning-button> </div> </lightning-card> </template>
  • 22. L’intéraction avec les données Wire Service (suite) • Création d’un enregistrement: Javascript Controller • Utilisation de la méthode createRecord() import { LightningElement, track } from 'lwc’; import { createRecord } from 'lightning/uiRecordApi’; import { ShowToastEvent } from 'lightning/platformShowToastEvent’; import ACCOUNT_OBJECT from '@salesforce/schema/Account’; import NAME_FIELD from '@salesforce/schema/Account.Name’; export default class LdsCreateRecord extends LightningElement { @track accountId; name = ‘’; handleNameChange(event) { this.accountId = undefined; this.name = event.target.value; } createAccount() { const fields = {}; fields[NAME_FIELD.fieldApiName] = this.name; const recordInput = { apiName: ACCOUNT_OBJECT.objectApiName, fields }; createRecord(recordInput) .then(account => { this.accountId = account.id; this.dispatchEvent( new ShowToastEvent({ title: 'Success’, message: 'Account created’, variant: 'success’, }), ); }) .catch(error => { this.dispatchEvent( new ShowToastEvent({ title: 'Error creating record’, message: error.body.message, variant: 'error’, }), ); }); } }
  • 23. L’intéraction avec les données L’appel aux méthodes Apex • Nécessaire seulement si le besoin n’est pas couvert par le wire service ou les composants standards tels que le Lightning Record Form ou les Lightning Record View Form et Lightning Record Edit Form • Nécessite l’import de la méthode avec la syntaxe: • Comme pour le framework Aura, une méthode Apex se rend disponible à l’appel grâce à l’annotation @AuraEnabled • Il est possible de lier une propriété ou méthode Javascript à l’appel de la méthode Apex (à condition qu’elle soit définit comme cachable) avec la syntaxe: import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodReference'; @wire(apexMethod, { apexMethodParams }) propertyOrFunction;
  • 24. L’intéraction avec les données L’appel aux méthodes Apex • Appel d’une méthode cachable // ContactController.cls public with sharing class ContactController { @AuraEnabled(cacheable=true) public static List<Contact> getContactList() { return [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Picture__c != null LIMIT 10]; } } Apex // apexWireMethodToProperty.js import { LightningElement, wire } from 'lwc’; import getContactList from '@salesforce/apex/ContactController.getContactList; export default class ApexWireMethodToProperty extends LightningElement { @wire(getContactList) contacts; } Javascript Controller
  • 25. L’intéraction avec les données L’appel aux méthodes Apex • Appel d’une méthode non cachable: pas de possibilité d’utiliser le wire service // apexImperativeMethod.js import { LightningElement, track } from 'lwc’; import getContactList from '@salesforce/apex/ContactController.getContactList’; export default class ApexImperativeMethod extends LightningElement { @track contacts; @track error; handleLoad() { getContactList() .then(result => { this.contacts = result; }) .catch(error => { this.error = error; }); } }
  • 26. Lightning Web Components Development Migration Aura vers LWC
  • 27. • Technologies fondamentalement différentes -> Analyse préalable du composant • Aura et LWC peuvent cohabiter -> un composant Aura peut inclure un composant LWC • Commencer par les composants les plus simples -> probablement les composants enfants (voir notion précédente) Stratégie Migration Aura vers LWC
  • 28. Exercice Création d’un formulaire d’ajout de contact et affichage dynamique de la liste des contacts de l’organisation
  • 29. • Créez une nouvelle organisation Salesforce de type Developer Edition en cliquant ici: https://developer.salesforce.com/signup • Activez My Domain • Activez le Dev Hub • Dans Visual Studio Code, exécutez les commandes suivantes: • sfdx force:auth:web:login --setdefaultdevhubusername --setalias DevHub • Connectez vous à votre developer edition nouvellement créée • sfdx force:project:create -n workshopLWC • cd workshopLWC • sfdx force:org:create -s -f config/project-scratch-def.json -a worshopLWCSScratch Configuration de Salesforce DX Exercice
  • 30. • Dans Visual Studio Code: • Ouvrez la palette de commande avec le raccourci Ctrl+Shif+P • Exécutez SFDX: Create Lightning Web Component • Nommez votre composant listContacts • Utilisez la librairie de composants standards fournie par Salesforce pour développer votre composant • Pour rappel, le composant doit contenir un formulaire de création de contact (voir le wire service précédemment évoqué) et une liste des contacts en base • Le formulaire de création doit au moins contenir les champs: prénom, nom et email • Il serait préférable d’ajouter chacune de ces fonctionnalités dans des cards différentes Création du Lightning Web Component Exercice
  • 31. • Configurez le composant pour qu’il puisse être ajouté aux pages Lightning en utilisant le code suivant dans le fichier listContact.js-meta.xml: • Dans Visual Studio Code, une fois le code enregistré, exécutez les commandes: • sfdx force:source:push • sfdx force:org:open • Ajoutez le composant créé à la page Lightning que vous souhaitez puis testez votre composant ! Création du Lightning Web Component (suite) Exercice <?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="listContacts"> <apiVersion>45.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> <target>lightning__HomePage</target> </targets> </LightningComponentBundle>
  • 32. • Le code correspondant à la correction de l’exercice est disponible sur Github à l’adresse: https://github.com/mlezer/bordeaux-dev-group-lwc • Pour aller plus loin, rendez-vous sur https://github.com/trailheadapps/lwc-recipes Corrrection Exercice
  • 33. Kahoot Rendez-vous sur kahoot.it pour gagner une batterie externe Astro !
  • 34. Prochain Meetup – 20 juin TrailheadDX Global Gathering France Bordeaux Paris Rivieira Toulouse Nantes Lille