Partie 3/3 - Le formulaire CRUD avec AlpineJS

AlpineJS

7 juin 2021

Cet article est la troisième partie d'une série :

 

Rappel du contexte : Lors d'un projet Bolt CMS, nous avons mis en œuvre un formulaire de modification de ses données personnelles dans un annuaire. L’individu disposait d’informations dont les champs (nom, prénom, téléphone, email, adresse, profession ...) et le but était de pouvoir modifier, ajouter ou supprimer ses informations personnelles.

Dans le cadre de notre projet, nous avons couplé AlpineJS et TailwindCSS pour construire notre propre bibliothèque de composants dynamiques sur mesure et l'utiliser sur nos pages web afin de les rendre dynamique.

 

Alors, qu'est ce qu'AlpineJS ?

AlpineJS est une librairie javascript que nous avons utilisé afin de pouvoir rendre les champs modifiables en JS et sauvegarder ces modifications apportés par l'utilisateur sur sa fiche. Cette librairie utilise des directives qui sont des attributs placés dans les balises HTML pour modifier le DOM.

Comment l'installer sur notre projet ?

2 manières sont disponibles afin d'intégrer AlpineJS dans notre projet:

Soit dans un premier cas, depuis un CDN via une balise script:

   

<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.js" defer></script> 
   

Soit dans le deuxième cas, on installe le package AlpineJS depuis npm:

   

npm i alpinejs 
   

Puis on inclut AlpineJS dans nos scripts:

   

import 'alpinejs' 
   

 

Cas d'utilisation

Nous avons commencé par créer une fonction javascript avec AlpineJS qui permettra la modification générale de tous les champs contenant les informations personnelles de l'individu. Cette fonction peut prendre des paramètres en données qui seront ensuite ajouté dans la balise HTML avec l'attribut x-data.

   

function editForm() {
    return {
        text: "Example text. Click to edit",
        isEditing: false,
        toggleEditingState() {
            this.isEditing = !this.isEditing; 
            if (this.isEditing) {
                this.$nextTick(() => {
                    this.$refs.input.focus();
                });
            }
           if(this.isEditing === false) {
                $data = {
                    email: document.getElementById("newEmail").value,
                    id: $person_id
                }
        },
        disableEditing() {
            this.isEditing = false;
        }
    };
} 
   

Afin de pouvoir afficher si le champ du formulaire est éditable, on ajoute un booléen dans la fonction javascript suivant certaines conditions. On l'appellera isEditing dans notre cas en l'initialisant à false puis sur la balise HTML, on déclare l'attribut x-show afin que le booléen soit affiché ou non suivant s'il a été initialisé à true ou false. $nextTick() garantit que les expressions ne sont exécutées qu'une fois qu'Alpine a fait son travail et $refs permet de récupérer un élément du DOM.

L'attribut x-data qui est la clé directive. Il représente "l'état" de tous les composants enfants, sous la forme d'un objet JSON. Lorsque vous attribuez x-data, il est très important de le mettre sur le bon élément. Ainsi, par exemple, si vous souhaitez contrôler un bouton sur un formulaire, vous devez mettre x-data sur un élément parent.

x-text permet de mettre à jour le innerText d'un élément. C'est une sorte d'echo en PHP.

Et enfin, l'attribut x-model permet de synchroniser les éléments d'entrée avec les données du composant. Nous avons l'objet data à l'intérieur de la portée du composant, nous pouvons donc les utiliser dans les entrées et les zones de texte

   

<div class="flex flex-col md:flex-row">
  <div x-data="editForm()" class="p-4">
      <span x-show="!isEditing" class="ml-2 text-sm" x-text="data.email"></span>
      <input id="editEmail-{{ email.id }}" type="email" x-show="isEditing" @keydown.enter="toggleEditingState()" class="ml-2 text-sm p-1 border border-gray-400 bg-gray-100 placeholder-gray-700 py-1 px-4 rounded-lg" x-model="data.email" /> 
   

Si le champ devient modifiable, on ajoute les nouvelles données modifiés sur le champ du formulaire qui, en validant la modification, appellera une requête à l'API en soumettant les nouvelles données liées au champ via son id en tant que JSON Chaîne et ainsi les mettre à jour en utilisant une méthode PUT sur la base de donnée sans pour autant rafraichir la page. Si tout est réussi, le bloc .then est exécuté et s'il y a une erreur dans la réponse, le .catch est exécuté. Le même procédé est utilisé pour ajouter ou supprimer un champ sur le formulaire.

   

function editForm($person_id, $id, $entity='emails') {
    return {
        isEditing: false,
        toggleEditingState() {
            this.isEditing = !this.isEditing; 
            if (this.isEditing) {
                this.$nextTick(() => {
                    this.$refs.email.focus();
                });
            }
            if(this.isEditing === false) {
                $data = {
                    email: document.getElementById("newEmail").value,
                    id: $person_id
                }
                fetch('/api/' + $entity + '/' + $id, {
                    method: 'PUT',
                    headers: { 'Content-Type': 'application/ld+json' },
                    body: JSON.stringify($data)
                })
                    .then(() => {
                        this.message = 'Form sucessfully submitted!';
                        document.location.reload();
                    })
                    .catch(() => {
                        this.message = 'Ooops! Something went wrong!'
                    })
            }
        },
        disableEditing() {
            this.isEditing = false;
        }
    };
} 
   

 

Rendu visuel