Live-Coding : Créer un chat en Ajax de A à Z

Par Nouvelle-Techno.fr le 15 mai 2020 - Catégories : Javascript Tutoriel Live-Coding

Lire l'article sur le site d'origine

Dans ce live-coding, nous allons créer un chat géré en Ajax.

Cette méthode permet de découvrir ou redécouvrir le fonctionnement d'Ajax.

Attention : ceci est une introduction, cette méthode ne sera pas optimale et l'utilisation des websockets, par exemple, sera plus conseillée pour les sites ayant du trafic.

Base de données

Nous utiliserons une base de données simple contenant deux tables.

La table "users" contiendra 4 champs

La table "messages" contiendra 4 champs

Fichiers de base

Nous mettons en place quelques fichiers de base, téléchargeables sur Github, qui permettront de voir l'interface de chat et de gérer la session des utilisateurs.

Ces fichiers sont structurés comme ceci

Les fichiers sont utilisés comme suit :

Envoi des messages

Une fois connecté, l'utilisateur pourra poster des messages de chat en remplissant le champ en bas de page et en validant (entrée et clic sur la coche)

Partie Javascript

Nous aurons donc besoin d'écouter 2 évènements, l'un sur la zone de texte pour la touche entrée, l'autre sur la coche pour le clic.

window.onload = () => {
    // On va chercher la zone de texte
    let texte = document.querySelector("#texte")
    texte.addEventListener("keyup", verifEntree)
    
    // On va chercher le bouton "valid"
    let valid = document.querySelector("#valid")
    valid.addEventListener("click", ajoutMessage)
}

Nous devons maintenant vérifier si la touche appuyée est la touche entrée, puis exécuter la fonction "ajoutMessage"

function verifEntree(e){
    if(e.key == "Enter"){
        ajoutMessage()
    }
}

La fonction "ajoutMessage" se chargera d'envoyer une requête Ajax à notre serveur pour enregistrer le message

function ajoutMessage() {
    // On récupère la valeur dans le champ "texte"
    let message = document.querySelector("#texte").value

    // On vérifie si on a un message
    if (message != "") {
        // On crée un objet JS pour le message
        let donnees = {}
        donnees["message"] = message

        // On convertit les données en json
        let donneesJson = JSON.stringify(donnees)

        // On envoie les données en POST en Ajax
        // On instancie XMLHttpRequest
        let xmlhttp = new XMLHttpRequest()

        // On gère la réponse
        xmlhttp.onreadystatechange = function(){
            if (this.readyState == 4) {
                if(this.status == 201) {
                    // On a une réponse
                    // On efface le champ texte
                    document.querySelector("#texte").value = ""
                }else{
                    // On reçoit une erreur, on l'affiche
                    let reponse = JSON.parse(this.response)
                    alert(reponse.message)
                }
            }
        }

        // On ouvre la requête
        xmlhttp.open("POST", "ajax/ajoutMessage.php");

        // On envoie la requête avec les données
        xmlhttp.send(donneesJson);
    }
}

Partie PHP

Une fois la partie javascript en place, nous allons devoir traiter les données reçues en PHP pour :

<?php
// Ce fichier ajoute un message dans la base de données
session_start();

// On vérifie la méthode
if($_SERVER['REQUEST_METHOD'] == 'POST'){
    // Bonne méthode
    // On vérifie si l'utilisateur est connecté
    if(isset($_SESSION['user']['id'])){
        // L'utilisateur est connecté
        // On récupère les données
        $donneesJson = file_get_contents('php://input');
        // On convertit les données
        $donnees = json_decode($donneesJson);

        // On vérifie qu'il y a un message
        if(isset($donnees->message) && !empty($donnees->message)){
            // Le message n'est pas vide
            // On peut l'enregistrer
            // On se connecte
            require_once('../inc/bdd.php');

            // On écrit la requête
            $sql = 'INSERT INTO `messages`(`message`, `users_id`) VALUES (:message, :user)';

            // On prépare la requête
            $requete = $db->prepare($sql);

            // On injecte les valeurs
            $requete->bindValue(':message', strip_tags($donnees->message), PDO::PARAM_STR);
            $requete->bindValue(':user', $_SESSION['user']['id'], PDO::PARAM_INT);

            // On exécute la requête en vérifiant qu'elle fonctionne
            if($requete->execute()){
                http_response_code(201);
                echo json_encode(['message' => 'Message enregistré']);
            }else{
                http_response_code(400);
                echo json_encode(['message' => 'Une erreur est survenue']);
            }
            // On libère $db
            $db = null;
        }else{
            // Le message est indéfini ou vide
            http_response_code(400);
            echo json_encode(['message' => 'Le message est vide']);    
        }
    }else{
        // L'utilisateur n'est pas connecté
        http_response_code(400);
        echo json_encode(['message' => 'Vous n\'êtes pas connecté(e)']);
    }
}else{
    // Mauvaise méthode
    http_response_code(405);
    echo json_encode(['message' => 'Mauvaise méthode']);
}

Afficher la liste des messages

Pour afficher la liste des messages, notre page d'accueil appellera un fichier PHP en Ajax à intervalle régulier (toutes les secondes dans notre exemple) qui fonctionnera comme suit :

Nous allons donc devoir conserver l'id du dernier message affiché afin de ne charger que les messages nécessaires.

Le javascript

Dans notre fichier javascript, nous commençons par créer une variable globale permettant de conserver le dernier id chargé.

// Variables globales
let lastId = 0

Nous allons ensuite exécuter une fonction "chargeMessages" toutes les secondes (par exemple) en ajoutant la ligne ci-dessous dans "window.onload"

setInterval(chargeMessages, 1000)

Enfin, notre fonction "chargeMessages" enverra l'id du dernier message en Ajax à notre fichier "chargeMessages.php" et recevra les messages nouvellement créés (ou les 5 derniers si on recharge la page) puis les affichera dans la discussion.

function chargeMessages() {
    // On charge les messages en Ajax
    // On instancie XMLHttpRequest
    let xmlhttp = new XMLHttpRequest()

    // On gère la réponse
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4) {
            if (this.status == 200) {
                // On a une réponse
                // On convertit le JSON en objet JS
                let messages = JSON.parse(this.response)

                // On retourne la liste pour traiter l'ID le plus élevé en dernier
                messages.reverse();

                // On récupère la div "discussion"
                let discussion = document.querySelector("#discussion")

                // On boucle sur les messages
                for (let message of messages) {
                    // On transforme la date en objet JS
                    let dateMessage = new Date(message.created_at)

                    // On ajoute le message avant le contenu déjà en place
                    discussion.innerHTML = `<p>${message.pseudo} a écrit le ${dateMessage.toLocaleString()} : ${message.message}</p>` + discussion.innerHTML

                    // On met à jour l'id
                    lastId = message.id
                }
            }else{
                // On gère les erreurs
                let erreur = JSON.parse(this.response)
                alert(erreur.message)
            }
        }
    }

    // On ouvre la requête
    xmlhttp.open("GET", "ajax/chargeMessages.php?lastId="+lastId)

    // On envoie la requête
    xmlhttp.send()
}

Le PHP

Il reste à créer le fichier "chargeMessages.php" qui récupérera les derniers messages publiés et les renverra en JSON.

Nous aurons 2 cas

Le code sera le suivant

<?php
// On vérifie la méthode utilisée par la requête ajax
if($_SERVER['REQUEST_METHOD'] == 'GET'){
    // On est en GET
    // On vérifie si on a un id
    if(isset($_GET['lastId'])){
        // On récupère l'id et on nettoie
        $lastId = (int)strip_tags($_GET['lastId']);

        $filtre = ($lastId > 0) ? " WHERE `messages`.`id` > $lastId" : '';

        // On va chercher les messages
        // On se connecte à la bdd
        require_once('../inc/bdd.php');

        // On écrit la requête
        $sql = 'SELECT `messages`.`id`, `messages`.`message`, `messages`.`created_at`, `users`.`pseudo` FROM `messages` LEFT JOIN `users` ON `messages`.`users_id` = `users`.`id`'.$filtre.' ORDER BY `id` DESC LIMIT 5';

        // On exécute la requête
        $requete = $db->query($sql);

        // On récupère les données
        $messages = $requete->fetchAll();

        // On convertit en json
        $messagesJson = json_encode($messages);

        // On envoie
        echo $messagesJson;
    }
}else{
    // Mauvaise méthode
    http_response_code(405);
    echo json_encode(['message' => 'Mauvaise méthode']);
}

Et voilà, un petit chat opérationnel !

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat

Les fichiers de cet article sont disponibles sur Github

#Tutoriel #Javascript #Ajax #PHP #Live-Coding