Pour votre progression, c'est très important de finir le TP précédent avant de commencer celui-ci.
Si vous venez d'assister au cours magistral, passez à la section suivante.
Quand un utilisateur commence à taper une recherche dans Google, Google lui propose une liste de suggestions.
Il est impossible d'inclure dans la page d'origine toutes les suggestions possibles. Le navigateur va donc demander au serveur la liste de suggestions au fur et à mesure que l'utilisateur écrit. Ceci se fait sans recharger la page.
Dans ce qu'on a vu jusqu'à maintenant, toutes les interactions avec le serveur se faisaient au moment du chargement de la page.
Ici, la liste des suggestions est cherchée à partir du serveur, à partir du JS et après la fin du chargement de la page.
Dans ce deuxième exemple, l'utilisateur appuie sur un bouton « J'aime » dans les commentaires d'une vidéo sur Youtube. Son action est enregistrée sur le serveur, mais la page ne se recharge pas.
Le fonctionnement habituel en HTML du bouton consiste à envoyer une requête POST et afficher une nouvelle page. Le rechargement de la page est désagréable pour l'utilisateur. C'est lent, la vidéo s'interrompt, il perd sa position dans la page...
Ici, la requête sur le serveur se fait sans rechargement de la page.
Sur la même page Youtube, l'affichage des commentaires se fait après la fin de de l'affichage de la page. A la place des commentaires, un message indique pendant un bref instant « chargement en cours... ».
Par ailleurs, l'utilisateur peut trier les commentaires, sans recharger la page. Une vidéo peut avoir des milliers de commentaires. Ils ne peuvent être chargés qu'à la demande.
AJAX est une approche dans laquelle on communique avec le serveur, à partir du JavaScript, sans recharger la page.
La requête au serveur peut prendre du temps. Il serait très désagréable que le navigateur soit bloqué pendant cette attente. La requête est donc faite de manière "asynchrone" : on lance la requête en JS et on fourni une fonction qui sera appelée plus tard, lorsque que la requête sera finie.
Le "X" de AJAX vient de "XML". Historiquement la communication entre le serveur et le client se faisait en XML ... aujourd'hui on préfère un autre format appelé JSON.
La fonction jQuery .get() permet de faire une requête AJAX en utilisant la méthode "GET".
Remarquez la syntaxe « $.get » : c'est une fonction qui est appellée directement sur l'objet jQuery ($) et pas sur une liste d'éléments jQuery.
Ici, $.get prend 3 arguments :
1) l'URL vers lequel on fait la requête
2) des données GET à envoyer au serveur
3) la fonction qui sera appelée quand la requête aura réussi
Important: cette fonction (3) n'est pas appelée tout de suite, lors de l'appel de $.get ... mais plus tard, en cas de succès de la requête
Reprenons l'exemple des suggestions dans la recherche Google. Il est très important de bien comprendre la chronologie et de savoir ce qui se passe sur le client et sur le serveur. En pratique, les échanges peuvent devenir compliqués.
1) Client au serveur « bonjour google.fr, je veux la page https://google.fr »
2) Le serveur de Google exécute un programme qui génère la page HTML
3) Serveur au Client : voici la page au format HTML
4) Le client affiche la page reçue (simplifié, en pratique il y a de nombreuses autres requêtes pour le CSS, le JS, les images...)
5) L'utilisateur commence à taper « javas ». Un programme JavaScript sur le client réagit à l'événement clavier et lance une requête AJAX au serveur.
6) Requête AJAX au serveur
7) Le serveur reçoit la requête et exécute un programme (par exemple PHP) qui va chercher des suggestions commençant par « javas » dans une Base de Données (ex: sql).
8) Le serveur envoie les suggestions au client
9) Le JavaScript sur le client affiche les suggestions
On va voir un exemple similaire aux suggestions Google, très simplifié.
Le HTML est très simple:
- un champs texte <input> pour que l'utilisateur puisse taper sa recherche.
- en dessous, une liste <ul> / <li> pour afficher les suggestions.
Le début du JS est classique :
$('#recherche') est une liste jQuery contenant uniquement le champs texte. On écoute les événements du clavier dans ce champs texte grâce à « .keyup() ».
Quand l'utilisateur relâche une touche (keyup), la fonction $.get est appelée.
Sont fournis en argument : L'URL, les données pour le serveur et la fonction à appeler après la requête.Quand la requête réussi, la fonction (ligne 4) est appelée avec en argument (reponse) le HTML renvoyé par le serveur.
Cet HTML est affiché dans <ul id="suggestions">Comme la liste est peut-être caché, il faut l'afficher.
Il manque dans cet exemple le code pour remplir le champs texte quand on clique sur un élément de la liste.
Le 2e argument indique les données fournies au serveur avec la méthode GET.
Dans la méthode GET, les données sont inclues dans l'URL en utilisant le séparateur "?" puis ensuite les séparateurs "&".
Remarque: on aurait pu mettre ces informations directement dans l'URL de l'argument 1... mais il faudrait les encoder correctement (espaces et autres caractères spéciaux). jQuery le gère plus simplement.
En JS, les fonctions anonymes permettent d'écrire très simplement du code événementiel et différé. Cette simplicité peut nous faire oublier la chronologie compliquée de l’exécution de ce programme.
Dans le PHP, les arguments GET sont récupérés dans le tableau global $_GET.
Dans cet exemple, le programme fait une requête SQL à la base de données pour chercher tous les mots qui commencent pas "a".
On construit alors le HTML contenant les suggestions (<li>...</li>...) .
Cet HTML est envoyé au client tout simplement avec "echo"...
Chaque fois qu'on écrit une requête AJAX, comme chaque fois qu'on écrit un formulaire, il faut choisir entre la méthode GET et la méthode POST.
La principale motivation de ce choix est définie par les normes :
les requêtes GET sont "idempotentes", elles peuvent être répétées sans conséquences.
Les données des requêtes GET sont transmises dans l'URL. Ceci a conduit de nombreuses personnes à penser, à tord, que le choix entre GET et POST était une question de sécurité.
Le requêtes POST sont choisies pour des actions qui ne peuvent pas être répétées sans conséquences.
Les données sont transmises dans les entêtes de la requête et pas dans l'URL. Elles ne sont pas visibles dans l'URL, mais elles ne sont pas pour autant "cryptés". L'argument de sécurité est souvent mal compris.
Dans cet exemple, l'utilisateur clique sur le bouton "J'aime" en dessous d'un commentaire.
Cette action va modifier l'état du serveur (+1 à la valeur j'aime sur ce commentaire dans la base de données). Il faut donc utiliser POST.
$.post() s'utilise de la même manière que $.get()
Commençons ce TP par quelques révisions.
prenez le temps de bien comprendre de l'ordre d'exécution de ce programme:
0 console.log('Bonjour');
1 $(document).ready(function()
{
2 console.log('Doc prêt');
3 $('img').click(function(e)
{
4 console.log('Image cliquée');
5 $(this).hide();
});
6 console.log("Fin mise en place");
});
7 console.log('Ok.');
0 console.log('Bonjour');
$(document).ready(function()
{
2 console.log('Doc prêt');
$('img').click(function(e)
{
console.log('Image cliquée');
5 $(this).hide();
});
6 console.log("Fin mise en place");
});
7 console.log('Ok.');
0 console.log('Bonjour');Quel est le "type" des expression suivantes ?
1 $(document).ready(function()
2 {
3 console.log('Doc prêt');
4 $('img').click(function(e)
5 {
6 console.log('Image cliquée');
7 $(this).hide();
8 });
9 console.log("Fin mise en place");
10 });
11 console.log('Ok.');
Le code suivant fait une requete ajax:
$.get('http://exemple.org/ajax.php',
{ id: 456, taille: 1000 },
function(reponse)
{
....
});
Quelle est l'URL effectivement utilisée lors de cette requête ?
Vous êtes sur la bonne voie, mais ce n'est pas encore toute à fait ça.
$(document).ready(function()
{
0 console.log('Doc prêt');
$('img').click(function(e)
{
1 console.log('Image cliquée');
$.get('http://exemple.org/ajax.php',
{ id: 456, taille: 1000 },
function(reponse)
{
2 console.log('reponse');
});
3 console.log('Image cliquée');
});
4 console.log("Fin mise en place");
});
Quel est l'ordre d'exécution ?
HTML:
<body>
<p></p>
</body>
JS:
...
console.log($('span').length);
$('p').html('<span>bonjour</span><span>aurevoir</span>');
console.log($('span').length);
...
( Rappel: La fonction jQuery .html() permet de "remplir" un élément avec du HTML fourni en argument.)
Qu'affiche ce programme dans la console ?
HTML:
<body>
<p></p>
</body>
JS:
...
$('p').html('<span>bonjour</span><span>aurevoir</span>');
$('span').click(function()
{
console.log('ok.');
});
...
HTML:
<body>
<p></p>
</body>
JS:
...
$('span').click(function()
{
console.log('ok.');
});
$('p').html('<span>bonjour</span><span>aurevoir</span>');
...
Le code suivant fait une requete ajax:
$.post('http://exemple.org/ajax.php',Quelle est l'URL effectivement utilisée lors de cette requête ?
{ id: 456, taille: 1000 },
function(reponse)
{
....
});
Rappel du cours :
Dans l'exemple suivant, sur quels éléments peut cliquer l'utilisateur pour que "OK" soit affiché dans la console.
<body>
<ul>
<li>abc</li>
<li>de <span>fg</span></li>
</ul>
<p>hij</p>
</body>
$('ul').click(function()
{
console.log('OK');
});
Rappel du cours :
<body>
<ul>
<li>abc</li>
<li>de <span>fg</span></li>
</ul>
<p>hij</p>
</body>
$('ul').click(function()Quel élément est encadré en rouge quand l'utilisateur clique sur<span>fg</span>
{
$(this).css('border','1px solid red');
});
Rappel du cours :
<body>
<ul>
<li>abc</li>
<li>de <span>fg</span></li>
</ul>
<p>hij</p>
</body>
$('ul').click(function(e)Quel élément est encadré en rouge quand l'utilisateur clique sur<span>fg</span>
{
$(e.target).css('border','1px solid red');
});
============================================
Si vous travaillez de chez vous, vous n'aurez pas accès à l'environnement PHP de l'IUT. Vous devez donc installer Apache, PHP et une base de données SQL sur votre machine.
Apache et MySQL/MariaDB peuvent être installés directement dans Linux. Vous n'avez pas besoin de logiciels comme XAMPP.
Pour les installer sur Ubuntu ou Debian, tapez :
sudo apt install apache2 mariadb-server mariadb-client
Les fichier web (PHP, HTML, CSS...) doivent être mis dans /var/www/html
Pour éviter de travailler en tant que root, changez le propriétaire de ce répertoire:
sudo chown [votre nom d'utilisateur] /var/www/html/
Il existe des logiciels comme XAMPP ou WAMP, facilitant l'installation d'Apache, PHP et MariaDB.
Si vous n'en avez pas déjà installé, téléchargez et installez XAMPP depuis https://www.apachefriends.org/fr/index.html
Par défaut, les fichier web (PHP, HTML, CSS...) doivent être mis dans c:/xampp/htdocs
============================================
On va commencer l'AJAX par l'exemple "suggestion" vu en cours.
Il s'agit de vérifier que tout fonctionne bien.
Créez les 4 fichiers suivants.
Ils doivent tous être placés dans le même répertoire, accessibles par votre serveur web.
(Donc, à l'IUT, ils doivent être dans un un sous-répertoire de public_html)
Vérifiez qu'ils sont bien accesibles avec l'url de votre serveur web.
(à l'IUT: http://localhost/~1234567/... )
suggestions.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>suggestions</title>
<link type="text/css" rel="stylesheet" href="suggestions.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="suggestions.js"></script>
</head>
<body>
<!--------------------->
<div><input id="recherche" /><button>chercher</button></div>
<ul id="suggestions">
</ul>
<!--------------------->
</body>
</html>
suggestions.css
body
{
font-family: sans;
}
#recherche
{
width: 300px;
}
#suggestions
{
position: absolute;
display: none;
list-style: none;
padding: 0;
margin: 0;
border: 1px solid #aaa;
width: 305px;
box-shadow: 0 0 2px rgba(0,0,0,.2);
}
#suggestions li
{
margin: .2em;
}
#suggestions li:hover
{
background-color: #eee;
}
suggestions.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#recherche').keyup(function(e)
{
console.log("Évènement keyup");
$.get('http://localhost/~1234567/js/tp-5/suggestions.php',
{mot: $('#recherche').val()},
function(reponse)
{
console.log("Réponse reçue du serveur: ",reponse);
$('#suggestions').html(reponse);
$('#suggestions').show();
});
});
console.log("La mise en place est finie. En attente d'événements...");
});
suggestions.php
<?php
// Une liste de mots, juste pour l'exemple.
// En pratique on chercherait dans une base de données.
$tousLesMots=array('crayon', 'stylo', 'feutre', 'taille-crayon', 'pointe', 'mine', 'gomme', 'dessin', 'coloriage', 'rayure', 'peinture', 'pinceau', 'couleur', 'craie', 'papier', 'feuille', 'cahier', 'carnet', 'carton', 'ciseaux', 'découpage', 'pliage', 'pli', 'colle', 'affaire', 'boîte', 'casier', 'caisse', 'trousse', 'cartable', 'jouet', 'jeu', 'pion', 'dé', 'domino', 'puzzle', 'cube', 'perle', 'chose', 'forme : carré', 'rond', 'pâte à modeler', 'tampon', 'livre', 'histoire', 'bibliothèque', 'image', 'album', 'titre', 'bande dessinée', 'conte', 'dictionnaire', 'magazine', 'catalogue', 'page', 'ligne', 'mot', 'enveloppe', 'étiquette', 'affiche', 'alphabet', 'appareil', 'caméscope', 'cassette', 'cédé', 'cédérom', 'chaîne', 'chanson', 'chiffre', 'contraire', 'différence', 'doigt', 'écran', 'écriture', 'film', 'fois', 'idée', 'instrument', 'intrus', 'lettre', 'liste', 'magnétoscope', 'main', 'micro', 'modèle', 'musique', 'nom', 'nombre', 'orchestre', 'ordinateur', 'photo', 'point', 'poster', 'pouce', 'prénom', 'question', 'radio', 'sens', 'tambour', 'télécommande', 'téléphone', 'télévision', 'trait', 'trompette', 'voix', 'xylophone', 'zéro');
$mot=$_GET['mot'];
// Retenir uniquement les mots qui contiennent $mot
$suggestions=preg_grep('/'.preg_quote($mot).'/',$tousLesMots);
// Max 10 réponse
$suggestions=array_slice($suggestions, 0, 10);
// Construire le HTML à renvoyer au client
$resultat='';
foreach($suggestions as $suggestion)
{
$resultat.='<li>'.htmlentities($suggestion).'</li>';
}
// Envoyer le HTML au client.
echo $resultat;
Combien de suggestions sont affichées quand on tape juste "z" ?
La console permet de visualiser les requêtes Ajax.
Il faut l'activer: dans la console cliquez sur l’icône "filtrer", puis sur XHR
(sur d'autres versions de Firefox: cliquez sur l'onglet "Net" et cochez "XHR")
On a déjà ajouté des console.log(...), mais les requêtes dans dans la console donnent plus d'informations.
Ouvrez une requête Ajax dans la console, comme indiqué sur la figure.
Regardez bien le contenu des onglets suivants : En-têtes, Paramètres, Réponse.
Que faut-il écrire pour afficher dans la console le nombre de <li> contenus dans un document ?
Ajoutez la ligne
console.log($('li').length);dans suggestions.js, comme ceci :
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#recherche').keyup(function(e)
{
console.log("Évènement keyup");
$.get('http://localhost/~1234567/js/tp-5/suggestions.php',
{mot: $('#recherche').val()},
function(reponse)
{
console.log("Réponse reçue du serveur: ",reponse);
$('#suggestions').html(reponse);
$('#suggestions').show();
});
});
console.log($('li').length);
console.log("La mise en place est finie. En attente d'événements...");
});
Quel chiffre est affiché dans la console ?
On veut maintenant remplir le champs texte avec une suggestion quand l'utilisateur clique dessus.
Est-ce que le code suivant affiche bien "Évènement mousedown" quand on clique sur une suggestion ?
suggestions.js:
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#recherche').keyup(function(e)
{
console.log("Évènement keyup");
$.get('http://localhost/~1234567/js/tp-5/suggestions.php',
{mot: $('#recherche').val()},
function(reponse)
{
console.log("Réponse reçue du serveur: ",reponse);
$('#suggestions').html(reponse);
$('#suggestions').show();
});
});
console.log($('li').length);
$('li').mousedown(function()
{
console.log("Évènement mousedown");
});
console.log("La mise en place est finie. En attente d'événements...");
});
Ces <li> sont crées dans le navigateur, plus tard, quand la réponse AJAX est reçue, à la ligne suivante :
$('#suggestions').html(reponse);
C'est une situation très fréquente en AJAX.
C'est aussi une situation que l'on a déjà rencontré dans le TP-4:
Dans le tableau joueurs on voulait effacer une ligne crée après le démarrage du programme...
La solution est de profiter du "bubbling". Pour rappel, voici le transparent du cours:
Dans notre cas : quand l'utilisateur clique sur un <li>, l'événement est d'abord envoyé au <li>, puis ensuite à son parent, le <ul>.
Le <ul> existe bien depuis le début, donc on peut installer un gestionnaire d'événements sur lui, dès le démarrage.
Une fois que l'utilisateur a choisi une suggestion, il faut cacher la liste des suggestions.
Voici une première correction, simple, mais qui pose un problème:
$('#suggestions').mousedown(function(e)
{
console.log("Évènement mousedown");
$('#recherche').val($(e.target).text());
$('#suggestions').hide();
});
Le problème est le suivant:
L'utilisateur peut cliquer dans la marge "entre deux lignes".
Essayez, pour voir ce qui se passe.
Dans ce cas le mousedown est arrivé directement sur le <ul> (#suggestions) et pas dans un <li>. C'est à dire que e.target est "#suggestions" et pas un <li>.
La solution est de vérifier que e.target est bien un <li>:
if($(e.target).is('li')){ ...}
Comme c'est une situation fréquente, jQuery fourni une fonction qui permet de le faire facilement : .on()
Ce qui donne :
$('#suggestions').on('mousedown' 'li',function(e){...});
Ce qui se traduit en français par « écouter tous les événements 'mousedown' arrivant sur '#suggestions' et ses descendants, mais ne retenir que ceux qui se produisent dans un élément donné par le sélecteur "li" »
Ce qui donne :
$('#suggestions').on('mousedown','li',function(e)
{
console.log("Évènement mousedown");
$('#recherche').val($(this).text());
$('#suggestions').hide();
});
Remarquez que dans ".on()", "this" désigne le "li" et non pas le "#suggestions".
... c'est un peu compliqué à suivre, mais on en aura besoin souvent ...
Dans les pages suivantes, on va construire, ensemble, un système d'affichage de commentaires en AJAX.
Ce système ressemble un peu à celui de Youtube.
On veut pouvoir afficher, et modifier le commentaires sans recharger la page, pour éviter d'interrompre la vidéo.
Ici, la vidéo est juste une image.
Pour éviter la complexité de la gestion d'une base de données, des fonctions vous seront fournies pour lire et et écrire les commentaires dans $_SESSION. C'est pratique pour le TP, mais ça ne marche pas du tout quand il y-a plusieurs utilisateurs.
Créez les fichiers suivants.
Ils doivent tous être placés dans le même répertoire, accessibles par votre serveur web.
Créez aussi un fichier commentaires.js vide.
commentaires.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>commentaires</title>
<link type="text/css" rel="stylesheet" href="commentaires.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="commentaires.js"></script>
</head>
<body>
<!--------------------->
<div id="principal">
<h2>Cours de JavaScript : Ajax</h2>
<img src="http://moodle.iutv.univ-paris13.fr/img/js/exo-commentaires-video.png"/>
</div>
<div id="block-commentaires">
<h3>Commentaires</h3>
<select id="pages">
<option value="0" > 1 à 5</option>
<option value="5" > 6 à 10</option>
<option value="10">11 à 15</option>
<option value="15">16 à 20</option>
</select>
<div id="commentaires">
</div>
<a id="reinitialiser" href="commentaires.php?reinitialiser">réinitialiser</a>
</div>
<!--------------------->
</body>
</html>
commentaires.css
body
{
font-family: sans;
width: 600px;
margin-left: auto;
margin-right: auto;
background-color: #eee;
}
#principal
{
background-color: white;
padding: 10px;
}
#principal img
{
width: 580px;
height: auto;
}
#block-commentaires
{
background-color: white;
min-height: 300px;
padding: 10px;
margin-top: 10px;
font-size: 14px;
}
#pages-commentaires
{
}
#commentaires
{
margin-top: 10px;
}
.commentaire
{
margin: 19px 0;
}
.commentaire .nom
{
color: #2793E6;
font-weight: bold;
margin-right: 13px;
}
.commentaire .date
{
color: #888;
}
.commentaire .contenu-com
{
margin: 3px 0;
}
.commentaire .pied-com
{
font-size: 11px;
color: #888;
line-height: 20px;
}
.commentaire .repondre
{
font-weight: bold;
}
.commentaire .jaime
{
font-size: 13px;
color: #2793E6;
}
.commentaire .jaime-plus
{
display: inline-block;
width: 18px;
height: 18px;
background-image: url(http://moodle.iutv.univ-paris13.fr/img/js/ytp.png);
vertical-align: middle;
}
.commentaire .jaime-moins
{
display: inline-block;
width: 18px;
height: 18px;
background-image: url(http://moodle.iutv.univ-paris13.fr/img/js/ytm.png);
vertical-align: middle;
}
#reinitialiser
{
font-size: 10px;
float: right;
}
commentaires.php
<?php
session_start();
setlocale(LC_TIME, "fr_FR.utf8");
header('Content-Type: text/html; charset=utf-8');
require_once 'commentaires-fonctions.php';
// Cas particulier: réinitialiser les commentaires
if(isset($_GET['reinitialiser']))
{
reinitialiser_commentaires();
die('Commentaires réinitialisés ok.');
}
// Chercher tous les commentaires et trier
$commentaires=commentaires();
$commentaires=trier_par_date($commentaires);
// Lire les données GET envoyées par le client
$debut=(int)$_GET['debut'];
$fin =(int)$_GET['fin' ];
// Construire le HTML à envoyer au client
$html='';
for($i=$debut;$i<=$fin;$i++)
{
$com=$commentaires[$i];
$html.=commentaire_rendu_en_html($com);
$html.="\n";
}
// Envoyer le HTML au client
echo $html;
commentaires-fonctions.php
<?php
// Racourci pour éviter les problèmes d'affichage des caractères HTML (<>&'") et les failles de sécurité XSS
function e($texte)
{
return htmlspecialchars($texte,ENT_QUOTES,'UTF-8');
}
// Trier par date déscendante
function trier_par_date($c)
{
usort($c,'s');
return $c;
}
function s($a, $b){return $a['date'] == $b['date'] ? 0 : (($a['date'] < $b['date']) ? 1 : -1);}
// La liste des commentaires.
// Les commentaires sont stockés dans la variable de SESSION.
// C'est pratique pour le TP, ca nous évite d'avoir besoin d'une base de données.
// Bien évidemment, ca ne marche pas du tout pour une vraie application.
function commentaires()
{
if(!isset($_SESSION['commentaires']))
{
$_SESSION['commentaires']=liste_initiale_commentaires();
}
return $_SESSION['commentaires'];
}
function reinitialiser_commentaires()
{
$_SESSION['commentaires']=liste_initiale_commentaires();
}
// Enregister la liste des commentaires.
// Les commentaires sont stockés dans la variable de SESSION.
// C'est pratique pour le TP, ca nous évite d'avoir besoin d'une base de données.
// Bien évidemment, ca ne marche pas du tout pour une vraie application.
function enregistrer_commentaires($commentaires)
{
$_SESSION['commentaires']=$commentaires;
}
function liste_initiale_commentaires()
{
return
array(
array('id'=>101,'nom'=>'Karim','date'=>1425283400,'contenu'=>"J'aime beaucoup ces cours de JavaScript !",'jaime'=>5),
array('id'=>102,'nom'=>'Joe' ,'date'=>1425283700,'contenu'=>"Ah bon ? Moi je préfère les tartes aux fraises.",'jaime'=>-1),
array('id'=>103,'nom'=>'Karim','date'=>1425284060,'contenu'=>"T'es pas sur Marmiton là...",'jaime'=>-4),
array('id'=>104,'nom'=>'Driss','date'=>1425284080,'contenu'=>"T'as compris quelque chose à Ajax ?",'jaime'=>0),
array('id'=>105,'nom'=>'Lian' ,'date'=>1425284120,'contenu'=>"Ouais... c'est facile avec jQuery.",'jaime'=>2),
array('id'=>106,'nom'=>'Naïma','date'=>1425284320,'contenu'=>"Ces trucs de client / serveur ca m'embrouille.",'jaime'=>0),
array('id'=>107,'nom'=>'Lian' ,'date'=>1425284520,'contenu'=>"C'est simple... le client c'est le JS ... et le serveur le PHP.",'jaime'=>1),
array('id'=>108,'nom'=>'Naïma','date'=>1425284620,'contenu'=>"Oui, mais le HTML, il est où ?",'jaime'=>0),
array('id'=>109,'nom'=>'Driss','date'=>1425284820,'contenu'=>"Dans la base de données, évidemment.",'jaime'=>-8),
array('id'=>110,'nom'=>'Karim','date'=>1425284920,'contenu'=>"Mais non! T'as rien compris.",'jaime'=>-1),
array('id'=>111,'nom'=>'Lian' ,'date'=>1425285120,'contenu'=>"Le HTML est envoyé par le serveur au navigateur.",'jaime'=>1),
array('id'=>112,'nom'=>'Driss','date'=>1425285180,'contenu'=>"Elle sert à quoi alors la BDD ?",'jaime'=>0),
array('id'=>113,'nom'=>'Karim','date'=>1425285120,'contenu'=>"Le PHP prend les infos de la BDD, fait du HTML avec et l'envoie au navigateur.",'jaime'=>5),
array('id'=>114,'nom'=>'Joe' ,'date'=>1425285220,'contenu'=>"J'ai faim.",'jaime'=>-5),
array('id'=>115,'nom'=>'Naïma','date'=>1425285320,'contenu'=>"C'est bientot la pause ?",'jaime'=>2),
array('id'=>116,'nom'=>'Joe' ,'date'=>1425285420,'contenu'=>"Encore 5 minutes...",'jaime'=>0),
array('id'=>117,'nom'=>'Lian' ,'date'=>1425285620,'contenu'=>"Vous pensez qu'à manger.",'jaime'=>0),
array('id'=>118,'nom'=>'Karim','date'=>1425285720,'contenu'=>"C'est la pause :-)",'jaime'=>10),
array('id'=>119,'nom'=>'Lian' ,'date'=>1425285750,'contenu'=>"Moi je reste travailler.",'jaime'=>-4),
array('id'=>120,'nom'=>'Naïma','date'=>1425285770,'contenu'=>"Chacun son truc...",'jaime'=>0),
);
}
// Renvoyer l'indice dans le tableau du commentaire ayant l'id $id
function commentaires_chercher_cle_de_id($commentaires,$id)
{
foreach($commentaires as $k=>$c){if($c['id']==$id){return $k;}}
return false;
}
// Retourne le HTML nécessaire pour afficher un seul commentaire.
function commentaire_rendu_en_html($com)
{
return
'<div class="commentaire" data-com-id="'.$com['id'].'">'."\n".
' <div class="entete-com">'."\n".
' <span class="nom" >'.e($com['nom']).'</span>'."\n".
' <span class="date">'.strftime('%e %b, %H:%M',$com['date']).'</span></div>'."\n".
' <div class="contenu-com">'.e($com['contenu']).'</div>'."\n".
' <div class="pied-com">'."\n".
' <span class="repondre">Répondre</span> '."\n".
' <span class="jaime">'.($com['jaime']!==0 ? $com['jaime'] : '').'</span> '."\n".
' <span class="jaime-plus"></span> '."\n".
' <span class="jaime-moins"></span> '."\n".
' </div>'."\n".
'</div>'."\n";
}
On va commencer par le plus simple:
uniquement afficher dans la console le numéro de la page quand l'utilisateur sélectionne une nouvelle page.
Pour ça on peut utiliser l'événement .change()
C'est la première fois qu'on le voit. Il s'utilise comme tous les événements jQuery (.click(), .mousedown()...)
Il permet de réagir au changement de valeur dans certains éléments de formulaire.
Pour récupérer la valeur sélectionnée, on utilise .val() (comme pour d'autres éléments de fonctionnaire).
Écrivez le programme commentaires.js
commentaires.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#pages').change(function()
{
console.log($('#pages').val());
});
});
Quand l'utilisateur sélectionne une page (1 à 5, 6 à 10 ...) on voudrait aller chercher les commentaires correspondants, en utilisant AJAX.
La première question à se poser est :
Est-ce qu'il faut une requête GET ou POST ?
Lisez attentivement les deux fichiers PHP.
Essayez de vous souvenir comment sont passées les données GET dans une URL.
Dans votre navigateur, en accédant directement à http://localhost/~12345.../commentaires.php...
essayez d'afficher uniquement les commentaires 9,10 et 11.
Regardez aussi le code HTML généré (ctrl+U) et essayez de bien le comprendre.
Quelle URL faut-il taper dans le navigateur pour afficher uniquement les commentaires 9,10 et 11 ?
(on demande l'URL en entier)
Essayez dans votre navigateur, puis copiez la réponse ci-dessous que quand ca marche,.
Maintenant qu'on a bien compris comment utiliser le fichier commentaires.php, on va pouvoir compléter le JS.
Faites la requête AJAX et affichez la nouvelle page de commentaires.
Voila... c'est à vous.
Indication: attention, la fonction .val() renvoie un string !
commentaires.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#pages').change(function()
{
$.get('http://localhost/~1234567/tp-5/commentaires.php',
{debut: parseInt($('#pages').val()),
fin: parseInt($('#pages').val())+4,
},
function(reponse)
{
console.log("Une réponse a été reçue du serveur");
$('#commentaires').html(reponse);
});
});
});
Lors du chargement initial de la page, les commentaires ne sont pas affichés.
On pourrait tout simplement reproduire le code JS précédent dans .change(...) pour l'appeler au premier chargement.
Il y a une astuce plus simple:
Il suffit de déclencher, à la main, un événement change, avec: $('#pages').change();
Remarquez qu'ici, il n'y a pas d'argument à .change()
Ce qui donne :
commentaires.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#pages').change(function()
{
$.get('http://localhost/~1234567/tp-5/commentaires.php',
{debut: parseInt($('#pages').val()),
fin: parseInt($('#pages').val())+4,
},
function(reponse)
{
console.log("Une réponse a été reçue du serveur");
$('#commentaires').html(reponse);
});
});
$('#pages').change();
});
Maintenant passons au bouton "J'aime".
Quand l'utilisateur clique sur le "doigt vers le haut", on veut augmenter la valeur "jaime" pour ce commentaire sur le serveur et aussi augmenter la valeur affichée.
On va voir ça, ensemble, dans les pages suivantes, en plusieurs étapes.
La première étape est d'afficher un message dans la console quand l'utilisateur clique sur <span class="jaime-plus"></span>
Ces <span> n'existent pas au démarrage. Il va falloir utiliser le bubbling à l'aide de la fonction ".on()".
Regardez comment cette fonction a été utilisée précédemment.
Ajoutez le nécessaire le code nécessaire pour afficher "ok" dans la console, dans commentaires.js
commentaires.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#pages').change(function()
{
$.get('http://localhost/test/js/tp-5/commentaires.php',
{debut: parseInt($('#pages').val()),
fin: parseInt($('#pages').val())+4,
},
function(reponse)
{
console.log("Une réponse a été reçue du serveur");
$('#commentaires').html(reponse);
});
});
$('#pages').change();
$('#commentaires').on('mousedown','.jaime-plus',function(e)
{
console.log("ok");
});
});
Maintenant, il s'agit de déterminer le numéro du commentaire cliqué.
A l''endroit indique *ICI* on peut récupérer le <span> cliqué avec $(this)
$('#commentaires').on('mousedown','.jaime-plus',function(e)Regardez en détail comment est structuré le HTML d'un commentaire.
{
console.log("ok");
*ICI*
});
Écrivez à la place de "*ICI*" le code pour afficher dans la console le numéro du commentaire cliqué.
$('#commentaires').on('mousedown','.jaime-plus',function(e)
{
console.log("ok");
var commentaire=$(this).parent().parent();
console.log(commentaire.attr('data-com-id'));
});
Maintenant qu'on a les informations nécessaires, on peut commencer à réfléchir à la requête AJAX.
La première question à se poser est :
Est-ce qu'il faut une requête GET ou POST ? Il vous reste à faire la requête AJAX en JS et à compléter la réponse du serveur en PHP.
Si c'est "ok", on doit calculer et afficher la nouvelle valeur de "jaime".
Attention: erreur subtile et courante à éviter :
La variable "this" dans la fonction qui traite la réponse du serveur n'est pas la même que la variable "this" dans la fonction qui traite le click.
Si vous voulez réutiliser le this du click, vous devez l'enregistrer dans une variable.
Le PHP est assez simple:
il s'agit juste de modifier le champs 'jaime' du commentaire dont on connaît le "id"
Vous pouvez utiliser les fonctions de commentaires-fonctions.php, notamment, commentaires_chercher_cle_de_id(...)
On veut que le serveur envoie au client le texte simple "ok" ou "erreur" selon les cas.
Votre fichier PHP peut ressembler à ceci:
commentaires-jaime.php
<?php
session_start();
require_once 'commentaires-fonctions.php';
// Chercher tous les commentaires
$commentaires=commentaires();
...
...
enregistrer_commentaires($commentaires);
echo 'ok';
commentaires.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#pages').change(function()
{
$.get('http://localhost/test/js/tp-5/commentaires.php',
{debut: parseInt($('#pages').val()),
fin: parseInt($('#pages').val())+4,
},
function(reponse)
{
console.log("Une réponse a été reçue du serveur");
$('#commentaires').html(reponse);
});
});
$('#pages').change();
$('#commentaires').on('mousedown','.jaime-plus',function(e)
{
// éviter la sélection désagréable quand on clique
e.preventDefault();
var commentaire=$(this).parent().parent();
var idCommentaire=parseInt(commentaire.attr('data-com-id'));
$.post('http://localhost/test/js/tp-5/commentaires-jaime.php',
{
id: idCommentaire
},
function(reponse)
{
console.log('Réponse recue:',reponse);
if(reponse==='ok')
{
var jaime=commentaire.find('.jaime');
var val=jaime.text()==='' ? 0 : parseInt(jaime.text());
jaime.text(val+1);
}
});
});
});
commentaires-jaime.php
<?php
session_start();
require_once 'commentaires-fonctions.php';
// Chercher tous les commentaires
$commentaires=commentaires();
$id=(int)$_POST['id'];
$cle=commentaires_chercher_cle_de_id($commentaires,$id);
if($cle===false){echo 'erreur';exit(1);}
$commentaires[$cle]['jaime']++;
enregistrer_commentaires($commentaires);
echo 'ok';