emoji_objects

VERSION ALPHA
Documentation officielle : link

Généralités


Vue.js 3 est une plateforme de développement front-end moderne, offrant une architecture réactive et une composition de composants performante pour la création d'interfaces utilisateur dynamiques et évolutives. Cette version apporte de nombreuses améliorations en termes de performance, d'API plus propre et de nouvelles fonctionnalités, telles que la composition API, qui simplifie la gestion de l'état et les interactions entre les composants.

Installation de Vue.js


L'installation de Vue.js peut varier en fonction de notre environnement, dans cette partie nous utiliserons les CDN pour pouvoir débuter l'utilisation de Vue.js le plus vite possible.
Un fichier de base utilisant des liens CDN est disponible ici : download

Les variables


En Vue.js, on peut gérer les variables de deux manières principales :

Variables non réactives let ou const

Ce sont des variables JavaScript standard. Les modifications apportées à ces variables ne sont pas automatiquement détectées par Vue.js. On devra mettre à jour manuellement les parties de notre application qui dépendent de ces variables.

Variables réactives ref

La fonction ref crée une référence réactive à une valeur (tableau, objet ou primitive). On accède à la valeur réelle de la variable réactive à l'aide de l'attribut value. Les changements apportés à value sont automatiquement détectés par Vue.js, ce qui met à jour les parties de notre application qui dépendent de cette variable de manière automatique.

Déclarations de variables réactives
                        
                        let users = ref([]);
                        let error = ref(null);
                        let count = ref(0);
                        let message = ref('');

                        message.value = "Bonjour à tous.";
                        
                        
content_copy
Un peu plus sur le const

const garantit que la variable ne peut pas être réassignée à une nouvelle valeur ou référence.
Si c'est un type primitif (nombre, chaîne, booléen, etc.), on ne peut pas changer la valeur.
Si c'est un objet ou un tableau, on ne peut pas changer l'objet ou le tableau référencé, mais on peut modifier ses propriétés ou éléments internes.

Exemple avec un type primitif
                            
                            const x = 10;
                            x = 20; // Erreur ! On ne peut pas réassigner x à 20.
                            
                            
Exemple avec un objet ou un tableau
                            
                            const arr = [1, 2, 3];
                            arr[0] = 10; // Cela fonctionne, car on modifie le contenu du tableau, pas la référence.
                            arr = [4, 5, 6]; // Erreur ! On ne peut pas réassigner la variable 'arr' à un nouveau tableau.

                            const obj = { name: "Toto" };
                            obj.name = "Bob"; // Cela fonctionne, car on modifie une propriété de l'objet.
                            obj = { name: "Charlie" }; // Erreur ! On ne peut pas réassigner 'obj' à un nouvel objet.
                            
                            

Les objets


En Vue.js, les objets permettent de créer des variables contenant plusieurs attributs. Cela facilite la gestion de données complexes en les regroupant de manière structurée.

Création d'un objet
                            
                            const message_object = ref({ 
                                show: false, 
                                message: "", 
                                color: "" 
                            });
                            
                            
content_copy
Modifier une valeur d'un objet
                            
                            function updateVisibility(bool) {
                                message_object.value.show = bool;
                            }    
                            
                            
content_copy
Modifier toutes les valeurs d'un objet
Méthode 1
                            
                            function updateAll(newValues) {
                                Object.assign(message_object.value, newValues);
                            }
                            // Usage
                            updateAll({ show: true, message: "Toto", color: "red" });
                            
                            
content_copy
Méthode 2
                            
                            function updateAll(newValues) {
                                message_object.value = { ...newValues };     // Réaffectation directe avec déstructuration
                            }
                            
                            
content_copy
Utilisation
                        
                        <div v-if="message_object.show">
                            <p :class="[message_object.color]">
                                {{ message_object.message }}
                            </p>
                        </div>
                        
                        
content_copy

Les inputs


On peut gérer les entrées d'utilisateurs dans des éléments de formulaire pour modifier une variable réactive en utilisant la directive v-model. La directive v-model lie l'élément de formulaire à une variable réactive.
De plus, nous utilisons des conditions pour afficher une phrase en fonction de l'âge.

                            
                            <!-- HTML -->
                            <div class="change-value mt-3">
                                <input type="number" v-model="age" placeholder="Entrez votre âge" />
                                <h2 v-if="age >= 18">Vous êtes majeur.</h2>
                                <p v-else-if="age >= 13">Vous êtes mineur mais adolescent.</p>
                                <p v-else>Vous êtes mineur.</p>
                            </div>

                            // VueJs
                            let age = ref(18);
                            
                            
content_copy
Les selects

Les menus déroulants selects sont des composants importants en HTML. Dans cet exemple, nous allons voir comment les manipuler avec Vue.js 3, en sélectionnant une couleur à appliquer à un élément div HTML.

                            
                            <!-- HTML -->
                            <select class="form-select" aria-label="Vue js select example" v-model="selectedOption">
                                <option v-for="option in options" :key="option.value" :value="option.value">
                                    {{ option.text }}
                                </option>
                            </select>
                            <p>Selected option: {{ selectedOption }}</p>

                            <div :class="['box', selectedOption]"></div>

                            
                            
content_copy
emoji_objects

- v-model="selectedOption" : Cette directive lie la valeur sélectionnée dans le menu déroulant au modèle de données selectedOption. Cela permet de gérer et de mettre à jour facilement la valeur sélectionnée.
- option : La balise option est utilisée pour créer des choix individuels dans le menu déroulant. En utilisant v-for pour itérer à travers la liste d'options disponibles, chaque option est configurée avec un attribut value, et key pour une identification unique. Le texte affiché dans chaque balise option est défini par option.text.
- :class : Enfin, la directive de binding est utilisée pour appliquer la couleur au div.

                            
                            // Vue.js
                            // Déclaration et initialisation du tableau d'options
                            const options = [
                                { value: null, text: 'Open this select menu' },
                                { value: "blue", text: 'Blue' },
                                { value: "green", text: 'Green' },
                                { value: "red", text: 'Red' }
                            ];
                            let selectedOption = ref(null);

                            return {
                                options,
                                selectedOption,
                            };

                            
                            
content_copy

Selected option: {{ selectedOptionExample }}

Les cases à cocher

Dans cette partie, il y aura un exemple de comment fonctionne les cases à cocher en Vue.js :

Checkbox
                            
                            <div class="mb-3">
                                <label class="form-label">Sélectionnez vos fruits préférés</label>

                                <div v-for="fruit in fruits" :key="fruit.id" class="form-check">
                                    <input class="form-check-input" type="checkbox" :id="'fruit-' + fruit.id" :value="fruit.id" v-model="selectedFruits"/>
                                    <label :for="'fruit-' + fruit.id" class="form-check-label">
                                        {{ fruit.name }}
                                    </label>
                                </div>
                                <p>Selected option: {{ selectedFruits }}</p>
                            </div>
                            
                            
content_copy
                            
                            const fruits = ref([
                                { id: 1, name: 'Orange'},
                                { id: 2, name: 'Banane'},
                                { id: 3, name: 'Poire'},
                                { id: 4, name: 'Annanas'},
                            ]);
                            
                            
content_copy

Bindings (Liaisons) dynamiques


En Vue.js, nous pouvons manipuler les propriétés des éléments HTML de manière déclarative en utilisant des Bindings. Voici une liste de quelques possibilités pour gérer les attributs d'un élément HTML en Vue.js :

Fonctionnement

la balise Vue est v-bind (ou la syntaxe abrégée :)

Eléments HTML

-disabled

Pour désactiver un bouton en fonction d'une condition :

HTML
Vue
                                        
                                        <button class="btn btn-sm btn-success" @click="toggleDisableBtn">Changer l'état du bouton</button>
                                        <button class="btn btn-sm btn-secondary" :disabled="isBtnDisabled">Bouton</button>
                                        
                                        
content_copy
                                        
                                        const isBtnDisabled = ref(true);

                                        function toggleDisableBtn() {
                                            isBtnDisabled.value = !isBtnDisabled.value;
                                        }
                                        
                                        
content_copy
Exemple Interactif

-class

Lier une classe CSS à sa version active en fonction d'une variable Vue.js :

HTML
CSS
Vue.js
emoji_objects

Si la classe contient des/un "-" il faut mettre le nom de la classe entre "''".

                                        
                                        <button class="btn btn-sm btn-primary" @click="activeBox">Activer la boîte</button>
                                        <div class="another-class box" :class="{ active: isBoxActive }">
                                            Une boîte à activer.
                                        </div>
                                        
                                        
content_copy
                                        
                                        .another-class { box-shadow: 0px 0px 80px rgba(0, 0, 0, 0.17); }
                                        .box {
                                            width: 150px;
                                            height: 150px;
                                            padding: 10px;
                                            background-color: blueviolet;
                                            color: #fff;
                                        }
                                        .box.active { border: 5px solid green; }
                                        
                                        
content_copy
                                        
                                        const isBoxActive = ref(false);

                                        function activeBox() {
                                            isBoxActive.value = !isBoxActive.value;
                                        }
                                        
                                        
content_copy
Une boîte à activer.
-Gestion de plusieurs classes

On peut ajouter ou enlever des classes CSS en fonction de variables Vue :

HTML
CSS
Vue.js
                                            
                                            <div class="d-flex gap-2">
                                                <button type="button" class="btn btn-sm btn-secondary" @click="addStyleOne">
                                                    {{ styleOne ? '-' : '+' }} Style 1
                                                </button>
                                                <button type="button" class="btn btn-sm btn-secondary" @click="addStyleTwo">
                                                    {{ styleTwo ? '-' : '+' }} Style 2
                                                </button>
                                                <button type="button" class="btn btn-sm btn-secondary" @click="addStyleThree">
                                                    {{ styleThree ? '-' : '+' }} Style 3
                                                </button>
                                            </div>

                                            <div
                                                class="box-ex-binding"
                                                :class="{
                                                    'box-ex-binding-border': styleOne,
                                                    'text-center-box-ex-binding': styleTwo,
                                                    'border-color-box-ex-binding': styleThree
                                                }">
                                                <p>Exemple de boîte.</p>
                                            </div>
                                            
                                            
content_copy
                                            
                                            .box-ex-binding {
                                                width: 100px;
                                                height: 100px;
                                                padding: 10px;
                                                margin-top: 5px;
                                                background-color: blueviolet;
                                            }
                                            .box-ex-binding p {
                                                margin: 0;
                                                text-align: center;
                                            }

                                            // Btn Style 1
                                            .box-ex-binding-border { border-radius: 10px; }
                                            // Btn Style 2
                                            .text-center-box-ex-binding { text-align: center; }
                                            // Btn Style 3
                                            .border-color-box-ex-binding { border: 5px solid #28af1c; }
                                            
                                            
content_copy
                                            
                                            const styleOne = ref(false);
                                            const styleTwo = ref(false);
                                            const styleThree = ref(false);

                                            // Ajoute la class : box-ex-binding-border
                                            function addStyleOne() {
                                                styleOne.value = !styleOne.value;
                                            }

                                            // Ajoute la class : text-center-box-ex-binding
                                            function addStyleTwo() {
                                                styleTwo.value = !styleTwo.value;
                                            }

                                            // Ajoute la class : border-color-box-ex-binding
                                            function addStyleThree() {
                                                styleThree.value = !styleThree.value;
                                            }
                                            
                                            
content_copy
Exemple Interactif

Exemple de boîte.

-Gestion de plusieurs classes et conditions ternaires

Pour une interface utilisateur plus dynamique, il est intéressant de pouvoir personnaliser la couleur d'un bouton selon la valeur d'une variable réactive Vue.js.

                                
                                
                                <button @click="renderDiv" :class="['btn btn-sm',  enableRender ? 'btn-warning' : 'btn-success']">
                                    {{ enableRender ? 'Cacher le rendu' : 'Afficher le rendu' }}
                                </button>

                                // Vue
                                const enableRender = ref(false);

                                function renderDiv() {
                                    enableRender.value = !enableRender.value;
                                }
                                
                                
content_copy
Exemple interactif
{{ enableRender ? 'Désactiver moi.' : 'Activer moi.' }}
-style

Lier des styles CSS à un élément en fonction d'une expression Vue.js :

                            
                            <button :style="{ color: textColor }">Contenu</button>
                            
                            
content_copy
-Attributs booléens

Gérer les attributs booléens des éléments HTML, comme required, checked, readonly, etc.

                            
                            <input type="checkbox" v-model="isChecked" :checked="isChecked" />
                            
                            
content_copy
- Attribuer une classe CSS en fonction d'un booléen

On peut utiliser des opérateurs ternaires pour déterminer quelle classe affecter en fonction d'une valeur booléenne :

                            
                                :class="user.all_payments_true ? 'btn-warning' : 'btn-secondary'"
                            
                            
content_copy
-Attributs généraux

On peut également lier n'importe quel attribut HTML avec v-bind :
Supposons que nous avons une boucle v-for qui parcourt une collection récupérée par une requête Axios. Si on souhaite créer des modals en fonction de cette collection :

                            
                            <tr v-for="(file, index) in files" :key="file.id">
                                <td>
                                    <span v-if="file.comment === null" class="material-icons">visibility_off</span>
                                    <div v-else>
                                        <a data-bs-toggle="modal" :data-bs-target="'#showComment_'+file.id" class="material-icons color_2 cursor">visibility</a>
                                        <!-- Modal comment -->
                                        <div class="modal fade modal-close" :id="'showComment_'+file.id" tabindex="-1" aria-labelledby="" aria-hidden="true">
                                            ...
                                        </div>
                                    </div>
                                </td> <!-- Comments -->
                            </tr>

                            
                            
content_copy
emoji_objects

- :data-bs-target="'#showComment_'+file.id" : Pour utiliser l'attribut data-bs-target dans Vue.js, il faut utiliser la directive v-bind et la syntaxe "'#showComment_ '+file.id"

Manipulation des Tableaux


Création d'un tableau
                        
                        let fruits_1 = ref[];
                        let fruits = ref['Pommes', 'Bananes', 'Cerises'];
                        
                        
content_copy
Ajout d'éléments au tableau
                        
                        let fruits = ref['Pommes', 'Bananes', 'Cerises'];
                        fruits.value.push('Poires');
                        
                        
content_copy
Suppression d'éléments
                        
                        let fruits = ref['Pommes', 'Bananes', 'Cerises'];
                        fruits.value.splice(index, 1);
                        
                        
content_copy
Mise à jour d'un élément
                        
                        let fruits = ref['Pommes', 'Bananes', 'Cerises'];
                        fruits.value[1] = 'Abricot';
                        
                        
content_copy

Les boucles


En Vue.js on peut utiliser des boucles sur des élements HTML, facilitant ainsi la manipulation des données, l'affichage des données.

for
Affichage dans un HTML
for
for of
for in

La directive Vue v-for permet de parcourir une structure de données et d'afficher son contenu dans le HTML.

                                        
                                        <!-- HTML -->
                                        <ul>
                                            <li v-for="fruit in fruits" :key="fruit">
                                                @{{ fruit }}
                                            </li>
                                        </ul>

                                        // VueJs
                                        let fruits = ['Pommes', 'Bananes', 'Cerises'];
                                        
                                        
content_copy

Dans Vue.js, la boucle for s'utilise de façon similaire à d'autres langages de programmation, en utilisant les index :

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function loopWithFor() {
                                            for (let i=0; i < factures.value.length; i++) {
                                                console.log("Nom : "+factures.value[i].name+" Prix : "+factures.value[i].prix);
                                            }
                                        }
                                        
                                        
content_copy

Dans Vue.js, la boucle for of est idéale pour parcourir des itérables (tableaux, chaînes, etc.) quand on n'a pas besoin de l'index :

for of
  • Itère sur les valeurs des objets itérables (tableaux, chaînes, Map, Set, etc.).
  • Ne fonctionne pas directement sur les objets simples.
  • Parcourt les valeurs de l'itérable.

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function loopWithForOf() {
                                            for (let facture of factures.value) {
                                                console.log("Nom : "+facture.name+" Prix : "+facture.prix);
                                            }
                                        }
                                        
                                        
content_copy

La différence principale entre for...of et for...in réside dans leur utilisation et ce qu'ils itèrent :

for in
  • Itère sur les propriétés énumérables d'un objet.
  • Utilisé principalement pour les objets (pas recommandé pour les tableaux).
  • Parcourt les clés (noms de propriétés) de l'objet.

                                        
                                        const personne = ref({
                                            nom: 'ILLOURMANE',
                                            prenom: 'Mahmoud',
                                            age: 26,
                                            profession: 'Ingénieur',
                                            ville: 'Reims'
                                        });

                                        function loopWithForIn() {
                                            for (let propriete in personne.value) {
                                                console.log(propriete + " : " + personne.value[propriete]);
                                            }
                                        }
                                        
                                        
content_copy
forEach
forEach (simple)
forEach (avec 3 paramètres)
forEach (suppression d'une case)

La méthode forEach est une façon très pratique et lisible de parcourir les éléments d'un tableau.

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function loopWithForEach() {
                                            factures.value.forEach(facture => {
                                                console.log("Nom : "+facture.name+" Prix : "+facture.prix);
                                            });
                                        }
                                        
                                        
content_copy

La méthode forEach accepte jusqu'à trois paramètres dans sa fonction de rappel :

                                        
                                        factures.value.forEach((element, index, array) => {
                                            console.log("Nom : "+element.name+" Prix : "+element.prix);
                                        });
                                        
                                        
content_copy
Signification de chaque paramètre

- element : L'élément courant du tableau sur lequel forEach est en train d'itérer.
- index : L'index de l'élément courant dans le tableau.
- array : Le tableau complet sur lequel forEach est appelé.

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function loopWithForEach() {
                                            factures.value.forEach((facture, idx, array) => {
                                                // Afficher les détails de la facture
                                                console.log(`Nom : ${facture.name} | Prix : ${facture.prix}`);

                                                // Afficher l'index de la facture
                                                console.log(`Index : ${idx}`);

                                                // Afficher le tableau complet
                                                console.log(`Tableau complet :`, array);

                                                // Ajouter un commentaire pour chaque facture
                                                console.log(`Commentaire : La facture ${facture.name} a un prix de ${facture.prix} et se trouve à l'index ${idx}.`);
                                            });
                                        }
                                        
                                        
content_copy

Dans cet exemple, le but est de supprimer un champ précis. Il y aura deux approches : l'une consiste à supprimer la case dans le tableau original, et l'autre consiste à utiliser map pour créer un nouveau tableau sans le champ.
Exemple avec l'utilisation de map

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        // SUPPRIME LE CHAMP "NAME" SUR LE TABLEAU ORIGINAL
                                        function removeNameOriginal() {
                                            factures.value.forEach(facture => {
                                              delete row.name;
                                            });
                                        }
                                        
                                        
content_copy
  • ID : {{ facture.id }}, {{ facture.name ? facture.name + ',' : '' }} {{ facture.prix }}
map

La méthode map est utilisée pour transformer les données d'un tableau. Elle crée systématiquement un nouveau tableau contenant les résultats de l'application d'une fonction donnée à chaque élément du tableau original. Cette méthode est particulièrement utile lorsqu'on souhaite effectuer une manipulation uniforme sur tous les éléments sans modifier le tableau d'origine.

map (multiplication)
map (ajout d'une valeur)
map (copie d'un tableau)
                                        
                                        const valeurs = [1, 2, 3, 4, 5];

                                        function loopWithMap1() {
                                            let newValues = valeurs.map(valeur => valeur * 2);
                                            console.log("Nouvelles valeurs : "+newValues);
                                        }
                                        
                                        
content_copy

L'opérateur de décomposition (...) en JavaScript permet d'étendre ou de copier les propriétés d'un objet ou les éléments d'un tableau. Il est très utile lorsqu'on utilise map.
Dans cet exemple, le but est de rajouter la TVA à chacun des prix, et de créer un nouveau tableau contenant la nouvelle propriété :

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function loopWithMap2() {
                                            let facturesAvecTVA = factures.value.map(facture => ({
                                                ...facture,
                                                prixTTC: (facture.prix * 1.20).toFixed(2),
                                            }));
                                            console.log("Factures avec TVA :", facturesAvecTVA);
                                        }
                                        
                                        
content_copy

Dans cet exemple, le but est de montrer comment en utilisant map on peut copier un tableau en n'incluant pas un champ spécifique du tableau originale.

                                        
                                        const factures = ref([
                                            { id: 1, name: 'toto', prix: 45.4, },
                                            { id: 2, name: 'tata', prix: 14.5, },
                                            { id: 3, name: 'titi', prix: 78.8, },
                                            { id: 4, name: 'tutu', prix: 22.35, },
                                        ]);

                                        function removeNameCopy() {
                                            // Crée une nouvelle copie du tableau sans le champ 'name'
                                            return factures.value.map(({ name, ...rest }) => rest);
                                        }
                                        
                                        
content_copy
emoji_objects

On utilise map pour créer un nouveau tableau, où pour chaque objet, il utilise la déstructuration avec l'opérateur rest (...rest) pour exclure la propriété name.

Tableau originale :
  • ID : {{ facture.id }}, NAME : {{ facture.name }}, PRICE : {{ facture.prix }}
Nouveau tableau
  • ID : {{ facture.id }}, PRICE : {{ facture.prix }}

Les conditionnelles


En Vue.js on peut utiliser des conditionnelles sur des élements HTML, facilitant ainsi la manipulation des données, l'affichage des données.

                        
                        <!-- HTML -->
                        <div>
                            <p v-if="isLoggedIn">Bienvenue, utilisateur !</p>
                            <p v-else>Veuillez vous connecter.</p>
                        </div>

                        // VueJs
                        let isLoggedIn = ref(false);
                        
                        
content_copy

Les formulaires


Dans cette partie nous allons regarder comment on peut manipuler les formulaires.

Les formulaires

Le but de cette section est de montrer comment créer un formulaire et récupérer les données :

@submit

Lorsqu'on crée un formulaire en Vue.js, il faut prendre en compte la manière de le gérer. On utilise des liaisons d'événements, dont il existe deux principaux types :

@submit="myFun"
@submit.prevent
@submit.prevent="submitForm"

- Comportement : Avec cette approche, on associe l'événement submit à une méthode spécifique définie dans l'objet Vue (dans cet exemple, la méthode s'appelle myFun).

- Utilisation : On l'utilise lorsqu'on souhaite exécuter une logique personnalisée lors de la soumission du formulaire, comme valider les données ou envoyer une requête Axios.

- Effet : Lorsque le formulaire est soumis, la méthode myFun est appelée. Si cette méthode ne contient pas event.preventDefault(), le comportement par défaut de soumission du formulaire se produira.

                                        
                                        <form @submit="myFun">
                                            <!-- Champ Nom -->
                                            <div>
                                                <label for="nom">Nom:</label>
                                                <input type="text" v-model="nom">
                                            </div>

                                            <!-- Champ Prénom -->
                                            <div>
                                                <label for="prenom">Prénom:</label>
                                                <input type="text" v-model="prenom">
                                            </div>

                                            <!-- Champ Date de Naissance -->
                                            <div>
                                                <label for="date_naissance">Date de Naissance:</label>
                                                <input type="date" v-model="dateNaissance">
                                            </div>

                                            <!-- Champ Adresse Mail -->
                                            <div>
                                                <label for="email">Adresse Mail:</label>
                                                <input type="email" v-model="email">
                                            </div>

                                            <!-- Champ Mot de Passe -->
                                            <div>
                                                <label for="mot_de_passe">Mot de Passe:</label>
                                                <input type="password" v-model="motDePasse">
                                            </div>

                                            <button type="submit">Envoyer</button>
                                        </form>

                                        <!-- Affichage des données du formulaire -->
                                        <div>
                                            <h2>Données du formulaire:</h2>
                                            <p>Nom: {{ nom }}</p>
                                            <p>Prénom: {{ prenom }}</p>
                                            <p>Date de Naissance: {{ dateNaissance }}</p>
                                            <p>Email: {{ email }}</p>
                                            <p>Mot de Passe: {{ motDePasse }}</p>
                                        </div>
                                        
                                        
content_copy
                                        
                                        // Code vue.js

                                        // Variables réactives
                                        const nom = ref('');
                                        const prenom = ref('');
                                        const dateNaissance = ref('');
                                        const email = ref('');
                                        const motDePasse = ref('');

                                        function myFun() {
                                            event.preventDefault();
                                            console.log("ok");
                                        }

                                        // Retourner les variables pour les utiliser dans le template
                                        return {
                                            nom,
                                            prenom,
                                            dateNaissance,
                                            email,
                                            motDePasse,

                                            myFun
                                        };
                                        
                                        
content_copy

- Comportement : Utilise la directive .prevent pour empêcher l'action par défaut de l'événement submit, qui, dans un formulaire classique, est l'envoi des données au serveur et le rechargement de la page.

- Utilisation : Cette approche n'appelle pas de fonction spécifique, ce qui la rend moins lisible.

                                        
                                        <form @submit.prevent>
                                            <!-- Champ Nom -->
                                            <div>
                                                <label for="nom">Nom:</label>
                                                <input type="text" v-model="nom">
                                            </div>

                                            <!-- Champ Prénom -->
                                            <div>
                                                <label for="prenom">Prénom:</label>
                                                <input type="text" v-model="prenom">
                                            </div>

                                            <!-- Champ Date de Naissance -->
                                            <div>
                                                <label for="date_naissance">Date de Naissance:</label>
                                                <input type="date" v-model="dateNaissance">
                                            </div>

                                            <!-- Champ Adresse Mail -->
                                            <div>
                                                <label for="email">Adresse Mail:</label>
                                                <input type="email" v-model="email">
                                            </div>

                                            <!-- Champ Mot de Passe -->
                                            <div>
                                                <label for="mot_de_passe">Mot de Passe:</label>
                                                <input type="password" v-model="motDePasse">
                                            </div>

                                            <button type="submit">Envoyer</button>
                                        </form>

                                        <!-- Affichage des données du formulaire -->
                                        <div>
                                            <h2>Données du formulaire:</h2>
                                            <p>Nom: {{ nom }}</p>
                                            <p>Prénom: {{ prenom }}</p>
                                            <p>Date de Naissance: {{ dateNaissance }}</p>
                                            <p>Email: {{ email }}</p>
                                            <p>Mot de Passe: {{ motDePasse }}</p>
                                        </div>
                                        
                                        
content_copy
                                        
                                        // Code vue.js

                                        // Variables réactives
                                        const nom = ref('');
                                        const prenom = ref('');
                                        const dateNaissance = ref('');
                                        const email = ref('');
                                        const motDePasse = ref('');


                                        // Retourner les variables pour les utiliser dans le template
                                        return {
                                            nom,
                                            prenom,
                                            dateNaissance,
                                            email,
                                            motDePasse
                                        };
                                        
                                        
content_copy

- Utilisation : Cette approche combine les deux méthodes précédentes. Elle empêche la soumission du formulaire tout en appelant la fonction correspondante.

                                        
                                        <form @submit.prevent="submitForm">
                                            <!-- Champ Nom -->
                                            <div>
                                                <label for="nom">Nom:</label>
                                                <input type="text" v-model="nom">
                                            </div>

                                            ...
                                            <button type="submit">Envoyer</button>
                                        </form>

                                        
                                        
content_copy

Watch & WatchEffect

Les fonctions watchEffect et watch permettent toutes deux d'observer et de réagir aux changements des données réactives. Cependant, elles se distinguent par leur fonctionnement et leurs cas d'utilisation spécifiques.

watchEffect
watch

- Fonctionnement : elle exécute une fonction immédiatement lors de la création, puis à chaque fois que les données réactives utilisées à l'intérieur de cette fonction changent le code de la fonction s'exécute de nouveau.

Exemple d'utilisation de watchEffect

Dans cet exemple le but est d'activer ou désactiver un bouton en fonction de la taille d'un tableau. Nous avons un tableau réactif que l'on peut modifier en ajoutant ou supprimant des éléments. Le bouton (Supprimer) sera désactivé si le tableau ne contient qu'un seul élément. Le bouton (Ajouter) sera désactivé si on atteint 10 éléments dans le tableau.

                                        
                                        <!-- Code HTML -->
                                        <p>Nombre d'éléments : {{ items.length }}</p>
                                        <button class="btn btn-primary" @click="addItem" :disabled="isAddedDisabled">Ajouter un élément</button>
                                        <button class="btn btn-danger" @click="removeItem" :disabled="isRemoveDisabled">Supprimer un élément</button>

                                        <div class="items">
                                            <div v-for="(item, index) in items" :key="index" :class="['item', item.color]">
                                                {{ item.value }}
                                            </div>
                                        </div>
                                        
                                        
content_copy

                                        
                                        // Tableau réactif où chaque élément contient une valeur et une couleur associée
                                        const items = ref([ {value:'Elément 1', color: getRandomColor()} ]);
                                        // Variable réactif pour contrôler l'état du bouton "Supprimer"
                                        const isRemoveDisabled = ref(false);
                                        // Variable réactif pour contrôler l'état du bouton "Ajouter"
                                        const isAddedDisabled = ref(false);

                                        // Fonction pour ajouter un élément au tableau avec une couleur aléatoire
                                        function addItem() {
                                            if(items.value.length <= 9) {
                                                items.value.push({
                                                    value: `Elément ${items.value.length + 1}`,
                                                    color: getRandomColor(),
                                                });
                                            }
                                        }

                                        // Fonction pour supprimer un élément du tableau
                                        function removeItem() {
                                            if(items.value.length > 0) {
                                                items.value.pop();
                                            }
                                        }

                                        function getRandomColor() {
                                            const colors = ['green', 'red', 'blueviolet'];
                                            return colors[Math.floor(Math.random() * colors.length)];
                                        }

                                        // watchEffect pour activer/désactiver le bouton "Supprimer"
                                        watchEffect(() => {
                                            isRemoveDisabled.value = items.value.length <= 1;
                                            isAddedDisabled.value = items.value.length >= 10;
                                        });
                                        
                                        
content_copy
Affecter directement une fonction à un watchEffect

Plutôt que d'écrire le code avec la syntaxe () => { ... }, il est possible de créer une fonction séparée et de l'affecter directement.

                                        
                                        function buttonsEffect() {
                                            isRemoveDisabled.value = items.value.length <= 1;
                                            isAddedDisabled.value = items.value.length >= 10;
                                        }

                                        watchEffect(buttonsEffect);
                                        
                                        
content_copy

Nombre d'éléments : {{ items.length }}

{{ item.value }}

Lorsqu'on utilise watch, il est nécessaire de spécifier explicitement les propriétés à surveiller. Dans notre exemple, nous surveillons la longueur du tableau item.
- Fonctionnement : Dans le cas d'un tableau, il est important de déterminer si l'on souhaite appeler watch à chaque modification du tableau ou uniquement lorsque sa taille change. Cela donne lieu à des comportements différents, comme dans les deux exemples suivants :

                                        
                                        // Surveillance uniquement de la longueur du tableau 'items'
                                        watch(() => items.value.length, (newLength) => {
                                            isRemoveDisabled.value = newLength <= 1;
                                            isAddedDisabled.value = newLength >= 10;
                                        }, { immediate: true });

                                        // Surveillance de tout changement dans le tableau 'items'
                                        watch(() => items.value, (newLength) => {
                                            isRemoveDisabled.value = newLength <= 1;
                                            isAddedDisabled.value = newLength >= 10;
                                        }, { immediate: true });
                                        
                                        
content_copy
Explication des différences :

- Surveiller la longueur (items.value.length) : La méthode watch sera déclenchée uniquement lorsque des éléments seront ajoutés ou supprimés du tableau (lorsque la taille change).
- Surveiller le tableau en entier (items.value) : Ici, la méthode sera déclenchée pour toute modification dans le tableau, que ce soit un ajout, une suppression ou même un changement dans les éléments du tableau, à condition que l'on utilise l'option { deep: true } pour une surveillance en profondeur des objets internes.

emoji_objects

La fonction watch ne s'exécute pas immédiatement après le chargement de la page, sauf si l'on utilise l'option {immediate: true}.

L'option deep

L'option deep dans Vue 3 est utilisée dans le watch pour surveiller en profondeur les objets ou les tableaux réactifs. Par défaut, watch ne détecte pas les changements au sein des propriétés internes d'un objet ou d'un tableau réactif, à moins que l'objet entier ne soit remplacé. En d'autres termes, si on modifies directement une propriété ou un élément interne, watch ne sera pas déclenché.

Lorsqu'on ajoutes l'option { deep: true }, on indiques à Vue de surveiller toutes les propriétés ou éléments internes de l'objet ou du tableau, de manière récursive. Cela signifie que le watch sera déclenché même si on modifies une propriété interne sans remplacer l'objet dans sa totalité.

Exemple
                                            
                                            const obj = ref({ name: "Mahmoud", age: 26 });

                                            watch(obj, (newVal) => {
                                                console.log("L'objet a changé !");
                                            });

                                            // Si on modifies une propriété interne de l'objet
                                            obj.value.name = "ILLOURMANE"; // Le 'watch' ne sera pas déclenché ici
                                            
                                            
content_copy
                                            
                                            const obj = ref({ name: "Mahmoud", age: 26 });

                                            watch(obj, (newVal) => {
                                                console.log("L'objet a changé !");
                                            }, { deep: true });

                                            // Modification d'une propriété interne
                                            obj.value.name = "ILLOURMANE"; // Le 'watch' sera déclenché cette fois
                                            
                                            
content_copy
emoji_objects

Utiliser l'option deep: true peut avoir un impact sur les performances si on surveilles de grands objets ou des tableaux avec beaucoup de propriétés imbriquées.

Nous allons maintenant reprendre l'exemple précédent, mais cette fois en utilisant watch :

                                            
                                            <!-- Le même code HTML que watchEffect -->
                                            
                                            
content_copy
                                            
                                            // Seul le code watch change

                                            // Utilisation de watch pour surveiller la longueur du tableau items
                                            // la fonction de rappel est déclenchée avec la nouvelle longueur comme 'newLength'
                                            watch(() => items.value.length, (newLength) => {
                                                isRemoveDisabled.value = newLength <= 1;
                                                isAddedDisabled.value = newLength >= 10;
                                            }, { immediate: true });
                                            
                                            
content_copy
Watch & fonction

Lorsqu'on surveille une variable réactive, on lui fournit une fonction qui sera appelée à chaque fois que la variable change :

Approche N°1
                                        
                                        const nameRegex = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
                                        const lastName = ref('Mahmoud');

                                        function validateName(nameToValidate) {
                                            if (nameRegex.test(nameToValidate)) {
                                                console.log("OK");
                                            } else {
                                                console.log("KO");
                                            }
                                        }

                                        watch(lastName, (newValue, oldValue) => {
                                                validateName(newValue);
                                            }, { immediate: true }
                                        );
                                        
                                        
content_copy
Approche N°2
                                        
                                        // Regex
                                        const nameRegex = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
                                        const lastName = ref('Mahmoud');

                                        function validateName() {
                                            if (nameRegex.test(lastName.value)) {
                                                console.log("OK");
                                            } else {
                                                console.log("KO");
                                            }
                                        }

                                        watch(lastName, validateName, { immediate: true });
                                        
                                        
content_copy
Conclusion sur les deux approches

- Approche 1 : On peut passer n'importe quelle valeur à la fonction validateName, ce qui la rend plus flexible et réutilisable. Cela est utile si plusieurs variables doivent être validées avec la même fonction.

- Approche 2 : On accède directement à lastName.value dans validateName, ce qui rend cette méthode plus simple et directe, surtout si validateName sera toujours utilisé avec lastName. Cette approche est légèrement plus concise et peut être préférée lorsqu'il n'est pas nécessaire de passer des arguments supplémentaires.

Exemple interactif

Nombre d'éléments : {{ items.length }}

{{ item.value }}

Exemple complet de validation d'un formulaire

HTML
Vue.js
Exemple
HTML
                                        
                                        <form @submit.prevent="submitForm">
                                            <div class="mb-3 last-name">
                                                <label class="form-label">Nom <strong class="c_red">*</strong></label>
                                                <div class="input-group">
                                                    <span class="input-group-text material-icons">badge</span>
                                                    <input type="text" class="form-control" v-model="lastName" required>
                                                </div>
                                            </div>
            
                                            <div class="mb-3 first-name">
                                                <label class="form-label">Prénom <strong class="c_red">*</strong></label>
                                                <div class="input-group">
                                                    <span class="input-group-text material-icons">badge</span>
                                                    <input type="text" class="form-control" v-model="firstName" required>
                                                </div>
                                            </div>
            
                                            <div class="mb-3 email">
                                                <label class="form-label">Adresse mail <strong class="c_red">*</strong></label>
                                                <div class="input-group">
                                                    <span class="input-group-text material-icons">alternate_email</span>
                                                    <input type="email" class="form-control" v-model="emailAddress" required>
                                                </div>
                                            </div>
            
                                            <div class="mb-3 phone-number">
                                                <label class="form-label">Numéro de téléphone</label>
                                                <div class="input-group">
                                                    <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">{{ phoneIndicator }}</button>
                                                    <ul class="dropdown-menu">
                                                        <li v-for="(code, country) in countryCodes" :key="country">
                                                            <a class="dropdown-item" @click="selectCode(code)">{{ country }} ({{ code }})</a>
                                                        </li>
                                                    </ul>
                                                    <input type="number" class="form-control" v-model="phoneNumber">
                                                </div>
                                            </div>
            
                                            <div class="mb-3 date-birth">
                                                <label class="form-label">Date de naissance</label>
                                                <div class="input-group">
                                                    <span class="input-group-text material-icons">calendar_month</span>
                                                    <input type="date" class="form-control" v-model="dateOfBirth">
                                                </div>
                                            </div>
            
                                            <div class="d-grid">
                                                <button class="btn btn-sm btn-success btn-rounded" :disabled="!isFormValid">Ajouter un utilisateur</button>
                                            </div>
                                        </form>
                                        
                                        
content_copy
VUE
                                        
                                        // Regex
                                        const nameRegex = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
                                        const phoneNumberRegex = /^[0-9]{9}$/;
                                        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            
                                        // Champs du formulaire
                                        const lastName = ref('');
                                        const firstName = ref('');
                                        const emailAddress = ref('');
                                        const phoneIndicator = ref('Indicatif');
                                        const phoneNumber = ref(null);
                                        const dateOfBirth = ref(null);
            
                                        // États de validation
                                        const isLastNameValid = ref(false);
                                        const isFirstNameValid = ref(false);
                                        const isEmailValid = ref(false);
                                        const isPhoneNumberValid = ref(true);
            
                                        const countryCodes = ref({
                                            "Algérie": "+213",
                                            "Allemagne": "+49",
                                            "Angleterre": "+44",
                                            "Belgique": "+32",
                                            "Canada": "+1",
                                            "Espagne": "+34",
                                            "France": "+33",
                                            "Italie": "+39",
                                            "Luxembourg": "+352",
                                            "USA": "+1"
                                        });
            
                                        // #region Fonctions de validations
                                            const validateName = (name, valueToValidate) => {
                                                valueToValidate.value = name && nameRegex.test(name);
                                            }
            
                                            const validateEmail = () => {
                                                isEmailValid.value = emailAddress.value && emailRegex.test(emailAddress.value);
                                            }
            
                                            const validatePhone = () => {
                                                // Si le champ est vide, on considère qu'il est valide car optionnel
                                                isPhoneNumberValid.value = !phoneNumber.value || phoneNumberRegex.test(phoneNumber.value);
                                            }
                                        // #endregion END/Fonctions de validations
            
                                        // #region Watchers
                                            watch(lastName, () => validateName(lastName.value, isLastNameValid))
                                            watch(firstName, () => validateName(firstName.value, isFirstNameValid))
                                            watch(emailAddress, validateEmail)
                                            watch(phoneNumber, validatePhone)
                                        // #region END/Watchers
            
                                        // Computed pour vérifier la validité globale du formulaire
                                        const isFormValid = computed(() => {
                                            return isLastNameValid.value && isFirstNameValid.value && isEmailValid.value && isPhoneNumberValid.value;
                                        })
            
                                        // Fonction de soumission du formulaire
                                        function submitForm() {
                                            if (isFormValid.value) {
                                                // Logique de soumission du formulaire
                                                console.log('Formulaire soumis')
                                            } else {
                                                console.log('Formulaire invalide')
                                            }
                                        }
            
                                        function selectCode(code) {
                                            phoneIndicator.value = code;
                                        }
                                        
                                        
content_copy
Exemple interactif
badge
badge
calendar_month
{{ formMessage }}

Fonctions


En Vue.js on peut définir les fonctions de différentes manières :

Function Expression
Syntaxe

La première définition utilise la syntaxe de fonction fléchée const incrementCount = () => { count.value++; };. C'est une Function Expression qui assigne une fonction anonyme à une constante const. Les fonctions fléchées sont plus courtes et peuvent être utilisées de manière plus concise.

Portée

Dans le cas d'une expression de fonction, la fonction utilise la portée léxicale lexical scope. Cela signifie que this dans la fonction fléchée est lié à la portée dans laquelle elle est définie (c'est-à-dire this sera le même que dans la fonction parent). Cela rend la gestion de la portée de this plus simple.

                        
                        const incrementCount = () => {
                            count.value++;
                        };
                        
                        
content_copy
Function Declaration
Syntaxe

La deuxième définition est une déclaration de fonction classique function incrementCount() { count.value++; }. Elle déclare une fonction nommée de manière plus traditionnelle.

Portée

Dans le cas d'une Function Declaration, this est dynamique et dépend de l'endroit où la fonction est appelée. Cela peut conduire à une confusion ou des erreurs dans certains contextes.

                        
                        function incrementCount() {
                            count.value++;
                        }
                        
                        
content_copy
emoji_objects

En résumé, les deux définitions de fonction montrées sont équivalentes en termes de comportement, mais utilisent des syntaxes et des portées différentes.
La fonction fléchée (arrow function) est souvent préférée en Vue 3 pour sa concision et sa gestion plus claire de this.

Composants et paramètres


Le but de Vue.js est de créer des composants réutilisables. Pour ce faire, nous avons besoin que ces composants acceptent des paramètres lors de leur appel. Cela nous permet d'utiliser le même composant, qui effectue une tâche spécifique, sur plusieurs pages tout en affichant ou en traitant des données différentes.

Du parent vers l'enfant

Dans ce premier exemple, le but est de créer un composant qui accepte en paramètre un endpoint HTTP d'API (ou autre) et qui retourne un message (à l'intérieur du composant enfant).

Vue.js 1/2
Vue.js 2/2
Appel du composant
Laravel
Flask
Hapi Js
Composant 1/2
emoji_objects

Pour cet exemple, il est préférable de travailler dans un véritable projet où Vue.js est installé. Le composant actuel doit être préalablement déclaré pour pouvoir être utilisé.

                                        
                                        <template>
                                            <div>
                                                <p>{{ message }}</p>
                                            </div>
                                        </template>

                                        <script setup>
                                            import { ref, defineProps, onMounted } from 'vue';

                                            // Définir les props que le composant acceptera
                                            const props = defineProps({
                                                endPoint: {
                                                    type: String,
                                                    required: true
                                                }
                                            });
                                            const message = ref('');
                                        </script>

                                        <style scoped>
                                        </style>
                                        
                                        
content_copy
Composant 2/2 (Requête Axios)
                                        
                                        // A ajouter dans le code du 1/2
                                        // ...

                                        // Requête Axios et affichage

                                        onMounted(async ()=> {
                                            printMessage();
                                        });

                                        /*
                                        * Permet d'afficher le message retourner par le endPoint
                                        **/
                                        async function printMessage() {
                                            try {
                                                const response = await getRequest();
                                                const statusCode = response.status;

                                                if (statusCode === 200) {
                                                    message.value = response.data.message;
                                                }
                                            } catch (error) {
                                                // Aucune gestion d'erreur dans cet exemple
                                                console.error("ERREUR : " + error);
                                            }
                                        }

                                        /*
                                        * Permet d'effectuer une requête Axios
                                        **/
                                        async function getRequest() {
                                            try {
                                                const response = await axios.get(`${props.endPoint}`);
                                                return response;
                                            } catch (error) {
                                                throw(error);
                                            }
                                        }
                                        
                                        
content_copy
Appel du composant
emoji_objects

Il est important de prendre en compte les particularités des moteurs de templates basés sur HTML.
En HTML, les noms d'attributs sont insensibles à la casse, ce qui signifie qu'ils sont automatiquement convertis en minuscules.
Ainsi, lorsqu'on définit une propriété comme firstNumber dans un composant, il est parfois/généralement nécessaire de l'adapter en first-number lors de son utilisation dans un moteur de template.

                                        
                                        // Appel du composant dans un template HTML
                                        <test-component-params end-point="/get-message"></test-component-params>
                                        
                                        
content_copy

Laravel

                                        
                                        // Le endpoint est /get-message
                                        public function returnMessage() {
                                            // Le message a retourner
                                            $message = "Un composant avec des paramètres c'est chouette.";

                                            return response()->json([
                                                'message' => $message,
                                            ], 200);
                                        }
                                        
                                        
content_copy

Flask

                                        
                                        @app.route('/get-message', methods=['GET'])
                                        def return_message():
                                            if request.method != 'GET':
                                                return jsonify({"error": "Method Not Allowed"{), 405

                                            # Le message a retourner
                                            message = "Un composant avec des paramètres c'est chouette."

                                            return jsonify({'message': message{), 200
                                        
                                        
content_copy

Hapi Js

                                        
                                        server.route({
                                            method: 'GET',
                                            path: '/get-message',
                                            handler: (request, h) => {
                                                // Le message à retourner
                                                const message = "Un composant avec des paramètres c'est chouette.";

                                                return h.response({
                                                    message: message
                                                }).code(200);
                                            }
                                        });
                                        
                                        
content_copy
Composants et paramètres sur Vue.js 2
emoji_objects

Sur les codes de vue.js 2.4 des erreurs peuvent être présentent.

Vue.js 2.4
Appel du composant

Vue.js 2.4

                                        
                                        var app = new Vue({
                                            el: '#app',
                                            props: {
                                                endPoint: {
                                                    type: String,
                                                    required: true
                                                }
                                            },
                                            data() {
                                                return {
                                                    message: ''
                                                };
                                            },
                                            mounted() {
                                                // Requête Axios vers l'endPoint fourni
                                                this.printMessage();
                                            },
                                            methods: {
                                                async printMessage() {
                                                    try {
                                                        const response = await axios.get(this.endPoint);
                                                        if (response.status === 200) {
                                                            this.message = response.data.message;
                                                        }
                                                    } catch (error) {
                                                        console.error('Erreur lors de la requête :', error);
                                                    }
                                                }
                                            }
                                        });
                                        
                                        
content_copy
Appel du composant
                                        
                                        
<test-component-params end-point="/get-message"></test-component-params>
content_copy

Du composant enfant vers le parent

Le but de cet exemple est de retourner une valeur d'un composant enfant vers le composant parent qui l'appel.

Enfant (HTML)
Enfant (Vue.js)
Parent (HTML)
Parent (Vue.js)
Compsant enfant

On commence par créer le composant HTML ou la requête HTTP que l'on souhaite transmettre au composant parent.

                                        
                                        <template>
                                            <span>Saisir un âge</span>
                                            <input type="number" v-model="age">
                                            <button class="button" @click="sendDataToParent()">Envoyer</button>
                                        </template>
                                        
                                        
content_copy
Compsant enfant

Dans la section du code, il est nécessaire d'importer l'événement defineEmits. Ensuite, nous devons créer une variable au sein d'un tableau qui contiendra toutes les variables à transmettre au composant parent.
Grâce à la fonction sendDataToParent, nous appelons la méthode emit de Vue.js, en spécifiant quelle variable du tableau emit nous souhaitons utiliser pour transmettre notre variable age.

                                        
                                        <script setup>
                                            import { ref, defineEmits } from 'vue';

                                            // Création d'un émetteur d'événements
                                            const emit = defineEmits(['dataToReceive']);
                                            // La variable à transmettre
                                            const age = ref(null);

                                            // La fonction qui émit la donnée
                                            function sendDataToParent() {
                                                if (!age.value) {
                                                    console.warn("LA SAISIE DE L'AGE EST OBLIGATOIRE.");
                                                    return;
                                                }
                                                emit('dataToReceive', age.value);
                                            }
                                        </script>
                                        
                                        
content_copy
Composant parent

Dans le composant parent, on appelle le composant et on spécifie ce qu'il faut faire lorsque l'on reçoit la variable de la part du composant enfant. On utilise la syntaxe @nom_variable_attendu="fonction_qui_la_manipulera".

                                        
                                            <child-component
                                                @dataToReceive="handleReceiveData"
                                            >
                                            </child-component>
                                        
                                        
content_copy
Composant parent

Ensuite, on manipule la donnée reçue comme on le souhaite.

                                        
                                        const data = ref(null);
                                        function handleReceiveData(data) {
                                            data.value = data;
                                        }
                                        
                                        
content_copy
Composants et paramètres sur Vue.js 2
Vue.js 2.4
Appel du composant

Vue.js 2.4

                                        
                                        var app = new Vue({
                                            el: '#app',
                                            data() {
                                                return {
                                                    age: null,
                                                };
                                            },
                                            methods: {
                                                sendDataToParent() {
                                                    if (!this.age) {
                                                        console.warn("LA SAISIE DE L'AGE EST OBLIGATOIRE.");
                                                        return;
                                                    }
                                                    // Émettre l'événement avec la donnée
                                                    this.$emit('dataToReceive', this.age);
                                                }
                                            }
                                        });
                                        
                                        
content_copy
Appel du composant depuis le parent
                                        
                                        
<template> <div> <child-component @dataToReceive="handleData" /> <>Âge reçu de l'enfant : {{ receivedAge }}</> </div> </template> ... data() { return { receivedAge: null, }; }, methods: { handleData(age) { this.receivedAge = age; }, },
content_copy

Opérations CRUD


Dans cette section, nous examinerons en détail les diverses opérations CRUD (Create, Read, Update, Delete) en utilisant Vue.js 3, Laravel 10, Flask et Hapi Js.

Une requête Axios

Le code suivant montre le squelette type d'une requête Axios, il démontre comment vérifier les différents codes HTTP renvoyés par le serveur :

                        
                        // Cette fonction effectue une requête Axios POST
                        async function postAddRole() {
                            const dataToSend = {
                                roleName: roleName.value
                            };

                            try {
                                const response = await axios.post('/role/create-roles', dataToSend);
                                return response;
                            } catch (err) {
                                throw err;
                            }
                        }

                        async function handleAddRole(event) {
                            event.preventDefault();

                            try {
                                const response = await postAddRole();
                                const statusCode = response.status;

                                // A CE STADE ON NE PEUT CAPTER QUE LA PLAGE DE 2XX
                                if (statusCode === 200) {
                                    console.log("REQUETE OK");
                                    return;
                                } else {
                                    console.log("Erreur requête");
                                    return;
                                }
                            } catch (err) {
                                // VERIFICATION DE SI L'ERREUR A UNE REPONSE ET UN CODE DE STATUT
                                if (err.response) {
                                    // LA REQUETE A ETE FAITE ET LE SERVEUR A REPONDU AVEC UN CODE DE STATUT QUI SORT DE LA PLAGE DE 2XX
                                    console.log('Erreur dans err.response :', err.response);
                                    const statusCode = err.response.status;

                                    // EXEMPLE DE CAPTURE SPECIFIQUE
                                    if (statusCode === 400) {
                                        console.log('Erreur 400 : Mauvaise requête');
                                        console.log('Détails de l\'erreur 400 :', err.response.data);
                                    } else {
                                        // GESTION D'AUTRES CODES D'ERREUR HTTP
                                        console.log('Erreur HTTP :', statusCode);
                                        console.log('Détails de l\'erreur :', err.response.data);
                                    }
                                } else if (err.request) {
                                    // LA REQUETE A ETE FAITE MAIS AUCUNE REPONSE N'A ETE RECUE
                                    console.log('Aucune réponse reçue :', err.request);
                                } else {
                                    // QUELQUE CHOSE S'EST MAL PASSE LORS DE LA CONFIGURATION DE LA REQUETE
                                    console.log('Erreur :', err.message);
                                }
                            }
                        }
                        
                        
content_copy

Gestion des erreurs

Pour simplifier la gestion des erreurs attendues côté client, on peut utiliser une fonction qui permet d'indiquer en paramètres les erreurs attendues et de les traiter plus facilement.

                        
                        /**
                        * Gère les erreurs HTTP de manière flexible et personnalisée.
                        *
                        * @param {Error} error - L'objet erreur de la requête HTTP.
                        * @param {number[]} arrayHttpErrors - Un tableau contenant les codes d'erreur HTTP à surveiller.
                        */
                        function handleErrors(error, arrayHttpErrors) {
                            if (error.response) {
                                const { status, data } = error.response;
                                // Vérifie si le code d'erreur figure dans le tableau spécifié
                                if (arrayHttpErrors.includes(status)) {
                                    const errorMessage = data.errors || data.error || 'Erreur non spécifiée';
                                    console.error(`Erreur ${status}:`, errorMessage);

                                    // Gestion spéciale pour le statut 422
                                    if (status === 422 && Array.isArray(data.errors)) {
                                        console.error('Détails des erreurs de validation:', data.errors);
                                    }
                                    return;
                                }
                            } else if (error.request) {
                                console.error('Erreur de requête sans réponse:', error.request);
                            } else {
                                console.error('Erreur inconnue:', error.message);
                            }
                        }
                        
                        
content_copy

Create

Dans cette section, nous allons aborder l'opération de création Create et examiner comment créer une ressource en utilisant Axios.

Laravel
Flask
Hapi Js

Laravel

                                    
                                    public function handleCrudPost(Request $request) {
                                        $validatedData = $request->validate([
                                            'nom' => 'required|string|regex:/^[a-zA-Z\s-]+$/|min:2|max:60',
                                            'prenom' =>'required|string|regex:/^[a-zA-Z\s-]+$/|min:2|max:60',
                                        ]);

                                        return response()->json([
                                            'message' => 'Ressource créée.',
                                        ], 200);
                                    }
                                    
                                    
content_copy

Flask

                                    
                                    @app.route('/crud-post', methods=['POST'])
                                    def submit_form():
                                        data = request.get_json()
                                        nom = data.get('nom', '').strip()
                                        prenom = data.get('prenom', '').strip()

                                        # Vérification des champs
                                        if not (nom and prenom):
                                            return jsonify({'message': 'Tous les champs sont obligatoires.'}), 400

                                        nom_regex = r'^[a-zA-Z\s-]+$'
                                        if not (re.match(nom_regex, nom) and re.match(nom_regex, prenom)):
                                            return jsonify({'message': 'Champs invalides.'}), 400

                                        return jsonify({'message': 'Formulaire soumis avec succès !'}), 200
                                    
                                    

Hapi Js

                                    
                                    server.route({
                                        method: 'POST',
                                        path: '/handle-crud-post',
                                        options: {
                                            validate: {
                                                payload: Joi.object({
                                                    nom: Joi.string().pattern(/^[a-zA-Z\s-]+$/).min(2).max(60).required(),
                                                    prenom: Joi.string().pattern(/^[a-zA-Z\s-]+$/).min(2).max(60).required()
                                                }),
                                                failAction: (request, h, err) => {
                                                    // Renvoie une réponse d'erreur en cas d'échec de la validation
                                                    return h.response({ message: err.details[0].message }).code(400).takeover();
                                                }
                                            }
                                        },
                                        handler: (request, h) => {
                                            return h.response({
                                                message: 'Ressource créée.'
                                            }).code(200);
                                        }
                                    });
                                    
                                    
Formulaire HTML

Nous allons commencer par créer un formulaire avec deux champs :

                            
                            // CSS
                            .bg-danger { background-color: rgb(221, 62, 62); }
                            .bg-success { background-color: #2dd288; }

                            <form @submit="handleForm">
                                // csrf
                                <div class="mb-3">
                                    <label for="labelInputEmail" class="form-label">Nom</label>
                                    <input type="text" class="form-control" v-model="nom" aria-describedby="nom">
                                </div>

                                <div class="mb-3">
                                    <label for="labelInputEmail" class="form-label">Prénom</label>
                                    <input type="text" class="form-control" v-model="prenom" aria-describedby="prenom">
                                </div>

                                <button class="btn btn-success" :disabled="!isFormValid">Envoyer les données</button>
                            </form>

                            <div v-if="showMessage" :class="['message-info', bgColor]">
                                {{ message }}
                            </div>
                            
                            
content_copy
Code Vue

Maintenant, nous allons écrire le code Vue pour gérer le bouton de validation, la liaison des champs et l'affichage des messages :

                            
                            // Consts
                            const nomRegex = /^[a-zA-Z\s-]+$/;

                            // Variables
                            let nom = ref('');
                            let prenom = ref('');
                            let isFormValid = ref(false);

                            let message = ref('');
                            let error = ref('');

                            let showMessage = ref(false);
                            let bgColor = ref(null);

                            watchEffect(() => {
                                // Vérifie si tous les champs sont remplis
                                isFormValid.value = nomRegex.test(nom.value.trim()) &&
                                                    nomRegex.test(prenom.value.trim());
                            });

                            async function postRequest() {
                                const dataToSend = {
                                    nom: nom.value,
                                    prenom: prenom.value
                                };

                                try {
                                    const response = await axios.post('crud-post', dataToSend);
                                    return response;
                                } catch (err) {
                                    throw err;
                                }
                            }

                            function resetForm() {
                                nom.value = '';
                                prenom.value = '';
                            }

                            function showMessageInfo(message_, backgroundColor) {
                                showMessage.value = true;
                                message.value = message_;
                                bgColor.value = backgroundColor;

                                setTimeout(() => {
                                    showMessage.value = false;
                                }, 3000);
                            }

                            async function handleForm(event) {
                                event.preventDefault();
                                if (!isFormValid.value) { return; }

                                try {
                                    const response = await postRequest();
                                    const statusCode = response.status;

                                    if (statusCode === 200) {
                                        message.value = response.data.message;
                                        showMessageInfo(message, 'bg-success');
                                        resetForm();
                                    } else {
                                        message.value = response.data.message;
                                        showMessageInfo(message, 'bg-danger');
                                    }
                                } catch (err) {
                                    console.error('Erreur lors de la requête API :', err);
                                    message.value = 'Une erreur s'est produite : ' + err.message;
                                    showMessageInfo(message, 'bg-danger');
                                }
                            }

                            return {
                                loading,

                                nom,
                                prenom,
                                isFormValid,

                                showMessage,
                                message,
                                bgColor,

                                handleForm,
                            }
                            
                            
content_copy

Read

Dans cette section, nous allons voir l'opération Read et comment lire des ressources avec Axios et Laravel.

Laravel
Flask
Hapi Js

Laravel

                                    
                                    public function getInfo() {
                                        // Liste des utilisateurs
                                        $users = [
                                            ['id' => 1, 'name' => 'Mahmoud'],
                                            ['id' => 2, 'name' => 'Toto'],
                                            ['id' => 3, 'name' => 'Tata'],
                                            ['id' => 4, 'name' => 'Titi'],
                                        ];

                                        return response()->json([
                                            'users' => $users,
                                        ], 200);
                                    }
                                    
                                    
content_copy

Flask

                                    
                                    @app.route('/getInfo', methods=['GET'])
                                    def get_info():
                                        if request.method != 'GET':
                                            return jsonify({"error": "Method Not Allowed"}), 405

                                        # Liste des utilisateurs
                                        users = [
                                            {'id': 1, 'name': 'Mahmoud'},
                                            {'id': 2, 'name': 'Puline'},
                                            {'id': 3, 'name': 'Farid'},
                                            {'id': 4, 'name': 'Gaya'},
                                        ]

                                        return jsonify({'users': users}), 200
                                    
                                    

Hapi Js

                                    
                                    server.route({
                                        method: 'GET',
                                        path: '/get-info',
                                        handler: (request, h) => {
                                            // Liste des utilisateurs
                                            const users = [
                                                { id: 1, name: 'Mahmoud' },
                                                { id: 2, name: 'Toto' },
                                                { id: 3, name: 'Tata' },
                                                { id: 4, name: 'Titi' },
                                            ];

                                            return h.response({
                                                users: users
                                            }).code(200);
                                        }
                                    });
                                    
                                    
Code HTML
                        
                        <canvas ref="myChart"></canvas>
                        
                        
content_copy
Code Vue

Dans notre code Vue.js, nous allons récupérer les données du contrôleur avec une requête GET, puis créer un graphique avec Chart.js.

                        
                        let ventes = ref(null);
                        let error = ref(null);
                        let myChart = ref(null);

                        // Requête Axios
                        async function getData() {
                            try {
                                const response = await axios.get('get-info');
                                ventes.value = response.data.ventes;
                            } catch (err) {
                                console.log('Erreur lors de la requête API :', err.message);
                            } finally {
                                initializeChart();
                            }
                        }

                        // Code du chart
                        function initializeChart() {
                            if (ventes.value === null) {
                                console.log("ERREUR : Aucune donnée.");
                                return;
                            }

                            const ctx = myChart.value.getContext('2d');

                            new Chart(ctx, {
                                type: 'bar',
                                data: {
                                    // On extrait les mois ['Janvier', 'Février', 'Mars']
                                    labels: ventes.value.map(vente => vente.mois),
                                    datasets: [{
                                        label: 'Ventes',
                                        // On extrait les valeurs [140, 240, 350]
                                        data: ventes.value.map(vente => vente.data),
                                        borderWidth: 1
                                    }]
                                },
                                options: {
                                    scales: {
                                        y: {
                                            beginAtZero: true
                                        }
                                    }
                                }
                            });
                        }

                        onMounted(async () => {
                            getData();
                        });

                        return {
                            loading,

                            ventes,
                            myChart,
                        }
                        
                        
content_copy

Update

Dans cette section, nous allons aborder l'opération de mise à jour Update et explorer comment mettre à jour une ressource en utilisant Axios.

Delete

Dans cette section, nous allons aborder l'opération de suppression Delete et étudier comment supprimer une ressource en utilisant Axios.