Pour votre progression, c'est très important de finir le sujet précédent avant de commencer celui-ci.
Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.
Commençons par une rapide révision des notions des sujets précédents.
Comment s’appelle « 2 »
Oui, c'est la boucle d'événements.
Il y a bien le mot « boucle » dedans.
Il y a bien le mot « événement » dedans.
Oui, c'est la que s’exécute le JS
Vous êtes sur la bonne voie. Il s'agit bien de « exécution » de quelque chose.
Oui, c'est là que se fait l'affichage.
Vous êtes sur la bonne voie. On rafraîchit quoi ?
Oui, il passe l'essentiel de son temps dans la boucle d'événements, à ne rien faire.
Entre 10 et 100 fois par seconde
Oui, le rafraîchissement des écrans se fait généralement 60 fois par seconde (au maximum).
Si le navigateur redessinait tout plus souvent, ce serait un gâchis de ressources (CPU, GPU), car l'écran ne l'afficherait pas plus vite.
Entre 100 et 1000 fois par seconde
Entre 0 et 10 fois par seconde
Plus de 1000 fois par seconde
<script>
console.log('A');
function xyz(){ console.log('B'); }
console.log('C');
document.addEventListener('click',xyz);
console.log('D');
</script>
On suppose qu'on démarre au début du script. Donnez l'ordre d’exécution.
1
2
3
4
5
6
<script type="module">
console.log('A');
await attendre(1000);
console.log('B');
</script>
La fonction attendre renvoie une promesse, qui est toujours tenue, après un certain temps.
On suppose qu'on démarre au début du script. Donnez l'ordre d’exécution.
1
2
3
4
En effet, « await » rend la main au navigateur, qui retourne à la boucle d'événements. L’exécution de ce <script> ne reprend qu'une fois que la promesse est tenue.
La fonction range_ta_chambre('Tom') renvoie une promesse.
On veut utiliser await.
Que faut-il écrire, en une seule ligne, pour afficher « vilain » sur la console si la promesse n'est pas tenue ?
Vous devez utiliser await
Indice: utilisez un système de gestion d'erreurs
Presque!! Il y a un petit détail de syntaxe:
Dans try ... catch, quand vous n'utilisez pas de paramètre dans catch, il faut écrire « catch » et non pas « catch() ».
Vous êtes sur la bonne voie. Vous avez bien utilisé « try », « await » et « catch »
On pourrait effectivement utiliser :
... await range_ta_chambre('Tom').catch( ...)
mais ce n'est pas l'approche qu'on veut utiliser ici.
Non. Vous n'avez pas utilisé await.
Écrivez une requête AJAX sur http://exemple.org/abc qui met la réponse renvoyée par le serveur dans une variable appelée « r » (que vous créerez).
Utilisez « await »
Utilisez la fonction simple_fetch
Presque! Vous avez écrit:
... await simple_fetch('http://'example.org/abc');
Ce qui est correct. Le problème est au début (...).
Il n'est pas demandé d'afficher quelque chose dans la console
Écrivez une requête AJAX sur http://exemple.org/abc qui affiche la réponse
renvoyée par le serveur dans la console.
Cette fois, n'utilisez pas « await »
Utilisez la fonction simple_fetch
Presque! Votre réponse commence par:
simple_fetch('http://example.com/abc').then(r=>console.log ...
Ce qui est correct. Le problème est après
Vous êtes sur la bonne voie! Votre réponse commence par:
simple_fetch('http://example.com/abc').then...
Ce qui est correct. Le problème est après
Non. simple_fetch renvoie une promesse. Vous êtes en train d'afficher immédiatement cette promesse dans la console.
La réponse du serveur n'arrivera que bien plus tard.
Vous avez écrit:
let xyz=simple_fetch ...
simple_fetch renvoie une promesse. Donc xyz contient une promesse, pas la réponse du serveur.
La réponse du serveur n'arrivera que bien plus tard.
L'énoncé indique « Cette fois, n'utilisez pas « await » »
Chatons avec un chat dans un petit chat, qu'on va construire ensemble.
Les fichiers HTML, CSS, et PHP sont fournis ci-dessous.
On va écrire le JS ensemble.
Important: si vous utilisez vscode: n'utilisez pas le serveur intégré (http://localhost:63342). Utilisez le serveur web de votre machine (http://localhost/~__user__nb). Ce TP a besoin de cookies et ils ne semblent pas fonctionner sur le serveur vscode.
Dans ~/public_html créez les fichiers suivants:
chat.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Chat</title>
<link rel="stylesheet" href="chat.css" />
<script src="https://moodle.iutv.univ-paris13.fr/img/bjs2/bjs2-js-lib.js"></script>
</head>
<body>
<h1>Chat</h1>
<div id="chat">
<div id="haut">
<input id="nom" /><input id="changer-nom" type="button" value="Changer"/>
</div>
<div id="messages">
</div>
<div id="bas">
<input id="texte" type="text" /><button id="envoyer" type="button"><span></span></button>
</div>
</div>
<p id="boutons">
<input id="rafraichir" type="button" value="Rafraîchir"/>
<input id="reinitialiser" type="button" value="Réinitialiser"/>
</p>
<script src="chat.js"></script>
</body>
</html>
chat.css
body{
background: linear-gradient(45deg, rgba(255,255,255,1) 0%, rgba(149,222,237,1) 100%);
background-repeat: no-repeat;
padding: 2em;
font-family: sans;
color: #444;
background-attachment: fixed;
}
#haut{
padding: .5em;
}
#nom {
padding: .58em;
margin-right: .5em;
}
#chat{
position: relative;
background-color: white;
width: 30em;
border-radius: 10px;
box-shadow: 6px 6px 8px rgba(0,0,0,.3);
}
#chat::before {
display: block;
content: '';
background-image: url('https://moodle.iutv.univ-paris13.fr/img/bjs2/chat2.svg');
width: 200px;
height: 135px;
position: absolute;
z-index: -1;
top: -10px;
left: 140px;
animation: 20s infinite alternate animchat;
}
@keyframes animchat{
0% {
top: -10px;
}
47% {
top: -10px;
}
50% {
top: -20px;
}
53% {
top: -10px;
}
95% {
transform: rotate(0deg);
}
97% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
#messages{
background-color: #cfc;
padding: .5em;
max-height: 15em;
min-height: 10em;
overflow-y: scroll;
}
.message{
position: relative;
left: -1em;
background-color: #f5f5f5;
border-radius: 10px;
margin: 1em 1em;
padding: .5em;
}
.message.a-moi{
left: 1em;
background-color: #cff;
margin-left: 1em;
text-align: right;
}
.nom{
position: relative;
color:#aa5;
font-size: 12px;
top: -.3em;
}
.message.a-moi .nom{
display: none;
}
#bas{
padding: .5em;
}
#texte {
padding: .4em;
font-size: 100%;
}
#envoyer{
position: relative;
top: -1px;
padding: .58em;
}
#envoyer>span {
border: solid black;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
transform: rotate(-45deg);
}
#boutons {
margin-top: 2em;
}
chat.js
// vide pour l'instant
chat.php
<?php
// ************* Initialisation
$db=connexion_bdd();
ini_set("xdebug.overload_var_dump", "off");
demarrer_session();
header('Access-Control-Allow-Origin: *');
// ************* Quelle action executer ?
switch($_GET['action'] ?? ''){
case 'messages':
messages();
break;
case 'nom':
nom();
break;
case 'changer-nom':
changer_nom();
break;
case 'envoyer':
envoyer();
break;
case 'reinitialiser':
reinitialiser();
break;
case 'test':
echo 'test ok';
break;
default:
echo 'Vous n\'avez pas specifié d\'action';
}
// ************* Les actions
function messages(){
global $db;
$req=$db->prepare("SELECT messages.*,utilisateurs.nom FROM messages,utilisateurs ".
"WHERE messages.utilisateur=utilisateurs.id ORDER BY messages.id ASC");
$req->execute();
$messages=$req->fetchAll(PDO::FETCH_ASSOC);
foreach($messages as &$message){
$message['aMoi']=$message['utilisateur']==$_SESSION['utilisateur'];
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($messages);
}
function nom(){
global $db;
$nom=get_nom();
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['nom'=>$nom]);
}
function changer_nom(){
global $db;
$req=$db->prepare("INSERT INTO messages(texte,utilisateur) VALUES(:texte,:utilisateur)");
$req->execute(['texte'=>'"'.get_nom().'" est devenu "'.$_POST['nom'].'"','utilisateur'=>3]);
$req=$db->prepare("UPDATE utilisateurs SET nom=:nom WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur'],'nom'=>$_POST['nom']]);
header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}
function envoyer(){
global $db;
$req=$db->prepare("INSERT INTO messages(texte,utilisateur) VALUES(:texte,:utilisateur)");
$req->execute(['texte'=>$_POST['texte'],'utilisateur'=>$_SESSION['utilisateur']]);
// Miaou!
if((rand()%15)===0){
$req->execute(['texte'=>rand()%2 ? 'miaou' : 'ron-ron','utilisateur'=>3]);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}
function reinitialiser(){
initialiser_bdd();
header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}
// ************* Les autres fonctions
function creer_utilisateur($nom=false){
global $db;
$req=$db->prepare("INSERT INTO utilisateurs(nom,session) VALUES(:nom,:session)");
$req->execute(['nom'=>$nom===false ? 'anonyme' : $nom,'session'=>session_id()]);
$id=intval($db->lastInsertId());
return $id;
}
// Ouvrir la connexion avec la base de données.
// Si c'est la première fois, initialiser_bdd() est aussi appelée.
function connexion_bdd(){
global $db;
$db=new PDO('pgsql:host=aquabdd;dbname=etudiants', '__user_nb__', 'votremdp');
// Si la table messages n'existe pas encore, appeler initialiser_bdd()
$result = $db->query("SELECT 1 FROM messages LIMIT 1");
if($result===false){initialiser_bdd();}
// Afficher les messages d'erreur
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
return $db;
}
// Supprime les anciennes tables et les recrée à nouveau.
// Crée aussi quelques messages et utilisateurs.
function initialiser_bdd() {
global $db;
// Supprimer les tables si elles existent déjà
$db->exec('DROP TABLE IF EXISTS utilisateurs');
$db->exec('DROP TABLE IF EXISTS messages');
// Créer les tables
// Cette table utilisateurs a un champs "session" seulement
// pour gérer une situaiton particulière (voir demarrer_session())
$db->exec('CREATE TABLE utilisateurs(
id SERIAL PRIMARY KEY,
nom TEXT NOT NULL,
session TEXT NOT NULL
);');
$db->exec('CREATE TABLE messages(
id SERIAL PRIMARY KEY,
utilisateur INT NOT NULL,
texte TEXT NOT NULL
);');
creer_utilisateur('Joe');
creer_utilisateur('Leila');
creer_utilisateur('?');
// Remplir la table messages avec 3 messages
$req=$db->prepare("INSERT INTO messages(utilisateur, texte) VALUES(:utilisateur, :texte)");
$req->execute(['utilisateur'=>1,'texte'=>'Salut tout le monde.']);
$req->execute(['utilisateur'=>1,'texte'=>"Ya quelqu'un ?"]);
$req->execute(['utilisateur'=>2,'texte'=>'Salut.']);
}
// La session permet d'utiliser la variable $_SESSION qui est persistante entre deux appels.
// Ceci utilise un cookie de session.
// On utilise $_SESSION ici pour identifier qui est l'utilisateur actuel.
function demarrer_session(){
global $db;
session_start();
// Cas très particulier: si un utilisateur reinitialise la BDD,
// les autres utilisateurs resteront bloqués dans des sessions invalides.
// On doit donc vérifier si cet utilisateur+session existe bien encore.
if(isset($_SESSION['utilisateur'])){
$req=$db->prepare("SELECT COUNT(*) FROM utilisateurs WHERE id=:id AND session=:session");
$req->execute(['id'=>$_SESSION['utilisateur'],'session'=>session_id()]);
$n=$req->fetchColumn();
if($n==0){unset($_SESSION['utilisateur']);}
}
// Créer un utilisateur la première fois qu'un untilisateur se connecte sur cette session.
if(!isset($_SESSION['utilisateur'])){
$_SESSION['utilisateur']=creer_utilisateur();
$req=$db->prepare("UPDATE utilisateurs SET nom=:nom WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur'],'nom'=>'anonyme-'.$_SESSION['utilisateur']]);
}
}
function get_nom(){
global $db;
$req=$db->prepare("SELECT nom FROM utilisateurs WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur']]);
return $req->fetchColumn();
}
// Pour debugger: Affiche un ou plusieurs paramètres dans un fichier log.
// Il faut au préalable créer le fichier "vlog" avec les droits d'écriture.
function vlog(...$args) {
ob_start();
var_dump(...$args);
$content = ob_get_contents();
ob_end_clean();
file_put_contents('vlog','######'.date('r').': '.$content,FILE_APPEND);
}
?>
Dans le développement web on parle aussi de « frontend » pour ce qui se passe dans le navigateur et de « backend » pour ce qui se passe sur le serveur.
Où sont principalement employées ces technologies ?
SQL
Python
PHP
CSS
Node.js
Pour fonctionner, la partie serveur (PHP) a besoin d'une base de données SQL.
Configurons la BDD.
Dans le PHP, trouvez la fonction connexion_bdd() (ATTENTION: pas l'appel de la fonction... son corps)
Modifiez-y la ligne qui contient vos identifiants:
$db=new PDO('pgsql:host=aquabdd;dbname=etudiants', '__user_nb__', 'votremdp');
Vérifiez que la page suivante n'affiche pas de message d'erreur:
(adaptez l'URL si vous avez une configuration différente)
http://localhost/~__user_nb__/chat.php?action=test
Qu'affiche cette page ?
Votre URL semble incorrecte. Vérifiez que vous avez utilisé la bonne URL, en entier.
Il est indispensable que la BDD fonctionne pour la suite de ce sujet.
Demandez de l'aide à votre enseignant.
chat.php est déjà écrit, vous n'aurez pas à le modifier.
C'est une situation classique dans laquelle on se retrouve quand on développe en « frontend »:
On développe du code JS « frontend » sur le navigateur.
On accède à un service « backend » existant déjà sur un serveur. Ce « backend » fournit une API.
L'API consiste ici, des URL suivantes:
http://localhost/~__user_nb__/chat.php?action=messages
http://localhost/~__user_nb__/chat.php?action=nom
http://localhost/~__user_nb__/chat.php?action=changer-nom
http://localhost/~__user_nb__/chat.php?action=envoyer
http://localhost/~__user_nb__/chat.php?action=reinitialiser
http://localhost/~__user_nb__/chat.php?action=test
On a déjà vu « test ». On verra comment utiliser chacune d'entre-elles.
http://localhost/~__user_nb__/chat.php?action=nom
C'est une requête GET très simple qui fournit le nom de l'utilisateur.
Essayez de l'ouvrir dans votre navigateur.
Quel est le nom retourné ?
http://localhost/~(votre numero utilisateur)/chat.php?action=nom
Au démarrage du JS, on voudrait aller chercher sur le serveur le nom de l'utilisateur.Que faut-il écrire pour afficher sur la console le nom de l'utilisateur ?
- Utilisez simple_fetch
- Important: n'utilisez pas await
- Utilisez une fonction fléchée avec des accolades
- Regardez bien ce qui est retourné par le serveur. On veut afficher uniquement le nom, pas un objet.
Presque! Le début de ce que vous avez écrit est correct:
simple_fetch('http://localhost/~1234567/chat.php?action=nom').then((r)=>{console.log( ...
Le problème est après.
Vous êtes sur la bonne voie! Le début de ce que vous avez écrit est correct:
simple_fetch('http://localhost/~1234567/chat.php?action=nom').then( ...
Le problème est après.
Le début de ce que vous avez écrit est correct:
simple_fetch('http://localhost/~1234567/chat.php?action=nom')
Le problème est après.
Comme on ne peut pas utiliser await, qu'est-ce qu'il faut utiliser ?
Dans le chat.js, cherchez le nom sur le serveur et remplissez le champ texte ayant le id « nom ».
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});
Quand on fait une requête HTTP, on utilise une « méthode ».
La méthode par défaut est « GET ».
Une autre méthode est appelée « POST »
Voici une brève description des URL de l'API:
Quelle méthode faut-il utiliser pour chacune ?
messages
nom
changer-nom
envoyer
reinitialiser
test
Rappel:
Quand l'utilisateur clique sur « Changer », créez une variable appelée « nom » contenant le nom qui se trouve dans le champs texte. Puis affichez cette variable nom dans la console.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
document.getElementById('changer-nom').addEventListener('click',()=>{
const nom=document.getElementById('nom').value;
console.log(nom);
});
Rappel : syntaxe objets
En JS, on crée un objet avec des accolades:
{
propriete1: valeur1,
propriete2: valeur2,
}
On peut, bien sur, l'écrire sur une ligne:
{propriete1: valeur1,propriete2: valeur2,}Écrivez un objet qui contient la propriété parfum associée à la valeur "chocolat" et la propriété prix associée au nombre 2
On demande juste l'objet.
Vous ne devez pas mettre de point virgule « ; »
On demande juste l'objet.
Vous ne devez pas le mettre dans une variable.
Presque! Vérifiez la syntaxe.
On suppose qu'on a déjà:
const nom=document.getElementById('nom').value;
Écrivez un objet ayant une propriété nom associée à la valeur contenue dans la variable nomOui, on peut mettre des guillemets (simples ou doubles) sur les noms des propriétés, mais ce n'est pas nécessaire, si vous n'utilisez pas de caractères spéciaux.
(Par contre, en JSON, c'est obligatoire).
Essayez sans guillemets sur les noms des propriétés.
Oui, c'est la version raccourcie qu'on va voir après. Écrivez ici la version longue.
En JS on crée beaucoup d'objets et on se retrouve souvent dans la situation suivante:
let nom='Tom';
let o={ nom: nom };
ou bien
let a='Joe', b=123;
let o={a:a,b:b};
Quand la valeur de la propriété est une variable ayant le même nom que la propriété, le JS permet de raccourcir :-)
{a:a,b:b} se racourcit en {a,b}
Comment se raccourcit {nom:nom} ?
Bien sur, la valeur d'une propriété peut elle même être un objet.
let joe={ nom:'joe', domicile: {ville:'Villetaneuse',adresse:'123 rue Abc'} }
Écrivez un objet avec une propriété « post » dont la valeur est un objet.
Ce deuxième objet a une propriété « nom » dont la valeur est une variable « nom ».
Raccourcissez si c'est possible.
Dans votre code, après le console.log(nom) on va vouloir faire une requête simple_fetch avec await.
Que faut-il écrire à la place de XYZ pour avoir le droit de le faire ?
document.getElementById('changer-nom').addEventListener('click',XYZ ()=>{
const nom=document.getElementById('nom').value;
console.log(nom);
});
Pas tout à fait. On utilise une fonction fléchée, on ne doit pas indiquer « function »
simple_fetch fonctionne par défaut avec GET.
On peut lui passer en deuxième paramètre un objet contenant une propriété appelée « post » et ayant comme valeur un objet.
simple_fetch fera alors une requête POST et enverra dans cette requête les informations de cet autre objet au serveur.
Par exemple, ceci envoie 'xyz associée à 'abc' et 123 associé à 'def' :
simple_fetch('https://exemple.com/abc',{ post: { abc: 'xyz', 'def': 123 } });
Dans notre cas, on veut envoyer la propriété « nom » associée à la variable nom à l'URL:
http://localhost/~__user_nb__/chat.php?action=changer-nom
document.getElementById('changer-nom').addEventListener('click',async ()=>{Que faut-il écrire à la place de XYZ pour changer le nom sur le serveur (en utilisant await) ?
const nom=document.getElementById('nom').value;
console.log(nom);
XYZ
});
Inspirez vous de la réponse précédente.
Essayez dans votre code, avant de répondre.
Vous avez oublié quelque-chose au tout début.
L'URL que vous avez donné à simple_fetch n'est pas correcte.
Vous êtes sur la bonne voie. Le début de votre réponse est correct:
await simple_fetch('chat.php?action=changer-nom' ...
Le problème est après
document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
});
Un chat sans messages, c'est triste.
Dans les pages suivantes, on va aller chercher les messages et les afficher.
Dans cette partie, on va se contenter de chercher les messages du chat quand l'utilisateur clique sur le bouton rafraîchir.
Quand l'utilisateur clique sur le bouton « Rafraîchir », appelez une fonction (pas anonyme) appelée « rafraichir ».
Créez cette fonction et affichez-y « rafraîchir » dans la console. Prévoyez qu'on utilisera await dans cette fonction.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
document.getElementById('rafraichir').addEventListener('click',rafraichir);
async function rafraichir(){
console.log('rafraichir');
}
L'URL pour chercher les messages est:
http://localhost/~__user_nb__/chat.php?action=messages
Elle renvoie un tableau JSON avec tous les messages du chat, qui est converti par simple_fetch en tableau d'objets.
Que faut-il écrire pour chercher les messages sur le serveur, créer une variable « reponse » et y mettre la liste des messages cherchés ?
Utilisez await.
Essayez dans votre code (dans la fonction rafraîchir) avant de répondre.
(Votre réponse ne de doit pas contenir la fonction rafraîchir, juste la ligne qui permet de chercher et de créer la variable « reponse » )
Vous avez utilisé
await simple_fetch(...
Ce qui est correct, mais vous n'avez pas rangé la réponse du serveur dans la variable « reponse »
L'énoncé demande d'utiliser await, donc vous ne pouvez pas utiliser .then(...)
Vous n'avez pas utilisé simple_fetch
C'est la fonction qu'il faut utiliser ici pour chercher les messages sur le serveur.
Vous avez écrit « console.log »
Ici, on ne veut pas afficher dans la console.
Vous n'avez pas utilisé await
Au tout début du fichier créez le raccourci pour le div « messages »:
const messages=document.getElementById('messages');
La première chose qu'on doit faire avant d'afficher les messages reçus, est d'effacer ceux qui seraient déjà affichés.
(Ce n'est pas utile la première fois, mais ensuite si.)
Après simple_fetch() , ajoutez:
messages.innerHTML='';
« reponse » est un tableau JS. Pour afficher ces messages, il faut parcourir le tableau « reponse » et créer le HTML correspondant à chaque message.
Commençons par parcourir le tableau avec une boucle.
Écrivez la boucle pour parcourir « reponse » et affichez chacun des messages dans la console.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
console.log(reponse[i]);
}
}
La structure qu'on veut créer pour chaque message est la suivante:
<div class="message">
<div class="nom"></div>
<div class="texte"></div>
</div>
On va créer le div à la main, puis le remplir en utilisant innerHTML.
Ensuite on remplira le nom et le texte.
Que faut-il écrire pour créer un élément div et le mettre dans une nouvelle variable appelée « message » ?
Vous êtes sur la bonne voie. Vous utilisez createElement, c'est ce qu'il faut faire.
En vous inspirant de la doc ci-dessus:
async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
messages.append(message);
}
}
Avant le append, utilisez innerHTML pour créer facilement les deux div:
async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
messages.append(message);
}
}
Maintenant qu'on a les deux divs, il va falloir écrire le nom et le texte dedans.
Commençons par le nom.
Normalement on utilise querySelector sur document: document.querySelector
Mais, si on part du document, on ne pourra pas trouver le div nom.
Cependant, querySelector peut s'appliquer sur n'importe quel élément, notamment celui qui se trouve dans la variable « message ». Il permet de démarrer la recherche sur l'élément en question.
Utilisez querySelector pour trouver le div nom dans message et écrivez dans son textContent le nom contenu dans la réponse.
Presque! Le début de votre réponse est correct:
message.querySelector('.nom').textContent=reponse...
Le problème est après.
Indice: « reponse » est un tableau contenant des objets.
Vous êtes sur la bonne voie. Le début de votre réponse est correct:
message.querySelector('.nom' ).textContent
Le problème est après.
Vous êtes sur la bonne voie. Le début de voter réponse est correct:
message.querySelector('.nom' )
Le problème est après. Indice: Pensez à textContent
Non. Avec document.querySelector, vous cherchez dans tous le document. On veut chercher uniquement dans « message »
Vous n'avez pas utilisé querySelector
const messages=document.getElementById('messages');
simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});
document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir();
});
document.getElementById('rafraichir').addEventListener('click',rafraichir);
async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}
}
On voudrait qu'à chaque rafraîchissement, le dernier message soit affiché en bas.
Pour ça, on va utiliser la propriété messages.scrollTop.
C'est un peu compliqué. Voici les modifications à faire:
const messages=document.getElementById('messages');
simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});
document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir(true);
});
document.getElementById('rafraichir').addEventListener('click',rafraichir);
async function rafraichir(forcerScroll=false){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
const scrollEstEnBas=Math.abs(messages.scrollHeight-messages.clientHeight-messages.scrollTop) < 10;
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}
if(scrollEstEnBas || forcerScroll){scroller_en_bas();}
}
function scroller_en_bas(){
setTimeout(()=>messages.scroll({top:100000,left:0,behavior:'smooth'}),0);
}
Ca y est ! Notre chat a des messages.
Mais on ne peut pas encore en envoyer...
En vous inspirant de ce qui a été fait avant, envoyez le message tapé dans le champs texte ayant l'id « texte » quand l'utilisateur appuie sur la flèche.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
document.getElementById('envoyer').addEventListener('click',async ()=>{
const texte=document.getElementById('texte');
if(texte.value===''){return;}
await simple_fetch('chat.php?action=envoyer',{post:{texte:texte.value}});
texte.value='';
rafraichir(true);
});
En vous inspirant de ce qui a été
fait avant, appelez l'API « reinitialiser » quand l'utilisateur appuie sur le bouton « Réinitialiser ».
L'URL est :
http://localhost/~__user_nb__/chat.php?action=reinitialiser
Elle prend un paramètre POST vide: mettez juste un objet vide {}
Après la requête, rechargez la page avec:
window.location.reload();Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
document.getElementById('reinitialiser').addEventListener('click',async ()=>{
await simple_fetch('chat.php?action=reinitialiser',{post:{}});
window.location.reload();
});
Utilisez setInterval pour appeler rafraichir() toutes les secondes.
const messages=document.getElementById('messages');
simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});
document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir(true);
});
document.getElementById('reinitialiser').addEventListener('click',async ()=>{
await simple_fetch('chat.php?action=reinitialiser',{post:{}});
window.location.reload();
});
document.getElementById('rafraichir').addEventListener('click',rafraichir);
setInterval(rafraichir,1000);
document.getElementById('envoyer').addEventListener('click',async ()=>{
const texte=document.getElementById('texte');
if(texte.value===''){return;}
await simple_fetch('chat.php?action=envoyer',{post:{texte:texte.value}});
texte.value='';
rafraichir(true);
});
async function rafraichir(forcerScroll=false){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
const scrollEstEnBas=Math.abs(messages.scrollHeight-messages.clientHeight-messages.scrollTop) < 10;
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}
if(scrollEstEnBas || forcerScroll){scroller_en_bas();}
}
function scroller_en_bas(){
setTimeout(()=>messages.scroll({top:100000,left:0,behavior:'smooth'}),0);
}
Un chat tout seul s'ennuie...
Vous pouvez créer un autre utilisateur en utilisant une fenêtre de navigation privée (Ctrl+Maj+p sur Firefox).
Uniquement si vous êtes en avance:
Ajoutez un bouton, visible uniquement un message qu'on a soi même écrit, permettant de l’effacer.
Étudiez le code PHP.
Ajoutez les code nécessaire en JS et PHP pour que ça marche (que le message soit effectivement effacé sur le serveur).