Exercices TP-5

  1. Bienvenue au TP-5
  2. Cours: AJAX
    1. Exemple : Google
    2. Exemple : commentaires
    3. Exemple : commentaires
    4. Ajax
    5. Exemple jQuery .get()
    6. Chronologie client / serveur
    7. Exemple : suggestion
    8. Suggestion : JS
    9. Suggestion : GET
    10. Suggestion : chronologie JS
    11. Suggestion : PHP
    12. Méthode GET
    13. Méthode POST
    14. Exemple : .post()
  3. Révisions
    1. Rappel : programmation événementielle
    2. Fonctionnalité
    3. Ordre d’exécution
    4. Types - choix
    5. Requête AJAX
    6. Ordre exécution AJAX
    7. Création dynamique d'HTML
    8. HTML dynamique
    9. HTML dynamique
    10. Requête AJAX
    11. Bubbling
    12. Bubbling this
    13. Bubbling event.target
  4. Exercice AJAX : suggestion
    1. Fonctionnement
    2. Suggestions : console
    3. Afficher nombre li
    4. Nombre li au démarrage
    5. Choix de la suggestion : problème
    6. Choix de la suggestion
    7. Correction
  5. Exercice : commentaires - pagination AJAX
    1. Commentaires : fichiers
    2. select / change
    3. Correction : select / change
    4. Pagination AJAX
    5. Le fichier PHP
    6. JS
    7. Correction : pagination
    8. Chargement initial de la page.
  6. Exercice : commentaires - bouton « J'aime »
    1. Gestion du bubbling.
    2. Correction : .on()
    3. Numéro du commentaire
    4. Correction : numéro commentaire
    5. Bouton J'aime : Get/POST
    6. PHP et JavaScript
    7. Correction

1. Bienvenue au TP-5

1.1 Bienvenue au TP-5

Pour votre progression, c'est très important de finir le TP précédent avant de commencer celui-ci.

2. Cours: AJAX

2.1 Cours: AJAX

Si vous venez d'assister au cours magistral, passez à la section suivante.


Cours: AJAX

2.2 Exemple : Google

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.

Cours: AJAX

2.3 Exemple : commentaires

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.

Cours: AJAX

2.4 Exemple : commentaires

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.

Cours: AJAX

2.5 Ajax

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.

Cours: AJAX

2.6 Exemple jQuery .get()

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

Cours: AJAX

2.7 Chronologie client / serveur

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

Cours: AJAX

2.8 Exemple : suggestion

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.

Cours: AJAX

2.9 Suggestion : JS

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.

Cours: AJAX

2.10 Suggestion : GET

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.

Cours: AJAX

2.11 Suggestion : chronologie JS

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.

Cours: AJAX

2.12 Suggestion : PHP

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"...

Cours: AJAX

2.13 Méthode GET

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é.

Cours: AJAX

2.14 Méthode POST

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.

Cours: AJAX

2.15 Exemple : .post()

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()

3. Révisions

3.1 Révisions

Commençons ce TP par quelques révisions.

Révisions

3.2 Rappel : programmation événementielle

prenez le temps de bien comprendre de l'ordre d'exécution de ce programme:

Révisions

3.3 Fonctionnalité



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.');


Que font les lignes suivantes ?

Révisions

3.4 Ordre d’exécution


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.');


Quel est l'ordre d'exécution ?

Révisions

3.5 Types - choix


0  console.log('Bonjour');
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.');
Quel est le "type" des expression suivantes ?

Révisions

3.6 Requête AJAX


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 ?


Révisions

3.7 Ordre exécution AJAX


  $(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 ?


Révisions

3.8 Création dynamique d'HTML


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 ?

Révisions

3.9 HTML dynamique

HTML:

<body>
<p></p>
</body>

JS:

...
$('p').html('<span>bonjour</span><span>aurevoir</span>');
$('span').click(function()
{
console.log('ok.');
});
...


Qu'affiche ce programme dans la console quand l'utilisateur clique sur "bonjour" ?

Révisions

3.10 HTML dynamique

HTML:

<body>
<p></p>
</body>

JS:

...
$('span').click(function()
{
console.log('ok.');
});
$('p').html('<span>bonjour</span><span>aurevoir</span>');
...


Qu'affiche ce programme dans la console quand l'utilisateur clique sur "bonjour" ?

Révisions

3.11 Requête AJAX


Le code suivant fait une requete ajax:

$.post('http://exemple.org/ajax.php',
{ id: 456, taille: 1000 },
function(reponse)
{
....
});
Quelle est l'URL effectivement utilisée lors de cette requête ?

Révisions

3.12 Bubbling

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');
});

Révisions

3.13 Bubbling this

Rappel du cours :


<body>
<ul>
<li>abc</li>
<li>de <span>fg</span></li>
</ul>
<p>hij</p>
</body>


$('ul').click(function()
{
$(this).css('border','1px solid red');
});
Quel élément est encadré en rouge quand l'utilisateur clique sur<span>fg</span>

Révisions

3.14 Bubbling event.target

Rappel du cours :


<body>
<ul>
<li>abc</li>
<li>de <span>fg</span></li>
</ul>
<p>hij</p>
</body>


$('ul').click(function(e)
{
$(e.target).css('border','1px solid red');
});
Quel élément est encadré en rouge quand l'utilisateur clique sur<span>fg</span>
(le code changé par rapport à la question précédente est en gras)

4. Exercice AJAX : suggestion

4.1 Exercice AJAX : suggestion

============================================

Travail de chez vous

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.

Sur LINUX

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/

Sur Windows

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

Indications
Dans les deux cas (Linux, Windows), vous pouvez accéder à ces fichiers dans votre navigateur simplement avec http://localhost
Dans les énoncés de ce TP, remplacez "http://localhost/~1234567/" par "http://localhost/"

Important: vous ne pourrez pas faire les TP à partir de maintenant si votre PHP ne fonctionne pas. Contactez votre enseignant si vous avez des difficultés à faire fonctionner le PHP.

============================================

Exercice AJAX : suggestion

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/... )

Indications importantes:


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;




Exercice AJAX : suggestion

4.2 Fonctionnement

Combien de suggestions sont affichées quand on tape juste "z" ?

Exercice AJAX : suggestion

4.3 Suggestions : console

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.

Exercice AJAX : suggestion

4.4 Afficher nombre li

Que faut-il écrire pour afficher dans la console le nombre de <li> contenus dans un document ?

Exercice AJAX : suggestion

4.5 Nombre li au démarrage

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 ?


Exercice AJAX : suggestion

4.6 Choix de la suggestion : problème

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...");
});



Exercice AJAX : suggestion

4.7 Choix de la suggestion

En effet, au démarrage du programme, on ne peut pas installer un gestionnaire d'événements sur les <li>... car ils n'existent pas encore !

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.

Indication 2

Une fois que l'utilisateur a choisi une suggestion, il faut cacher la liste des suggestions.

Exercice AJAX : suggestion

4.8 Correction

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  ...

5. Exercice : commentaires - pagination AJAX

5.1 Exercice : commentaires - pagination AJAX

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.

Partie PHP

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.



Exercice : commentaires - pagination AJAX

5.2 Commentaires : fichiers

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";
}


Exercice : commentaires - pagination AJAX

5.3 select / change

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

Exercice : commentaires - pagination AJAX

5.4 Correction : select / change

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());
});
});

Exercice : commentaires - pagination AJAX

5.5 Pagination AJAX

Pagination AJAX

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 ?

Exercice : commentaires - pagination AJAX

5.6 Le fichier PHP

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,.

Exercice : commentaires - pagination AJAX

5.7 JS

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 !

Exercice : commentaires - pagination AJAX

5.8 Correction : pagination

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);
});
});
});

Exercice : commentaires - pagination AJAX

5.9 Chargement initial de la page.

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 :

6. Exercice : commentaires - bouton « J'aime »

6.1 Exercice : commentaires - bouton « J'aime »

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.

Exercice : commentaires - bouton « J'aime »

6.2 Gestion du bubbling.

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

Exercice : commentaires - bouton « J'aime »

6.3 Correction : .on()

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");
});


});



Exercice : commentaires - bouton « J'aime »

6.4 Numéro du commentaire

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)
{
console.log("ok");
*ICI*
});
Regardez en détail comment est structuré le HTML d'un commentaire.

Écrivez à la place de "*ICI*" le code pour afficher dans la console le numéro du commentaire cliqué.

Exercice : commentaires - bouton « J'aime »

6.5 Correction : numéro commentaire


	$('#commentaires').on('mousedown','.jaime-plus',function(e)
{
console.log("ok");
var commentaire=$(this).parent().parent();
console.log(commentaire.attr('data-com-id'));
});

Exercice : commentaires - bouton « J'aime »

6.6 Bouton J'aime : Get/POST

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 ?

Exercice : commentaires - bouton « J'aime »

6.7 PHP et JavaScript

 Il vous reste à faire la requête AJAX en JS et à compléter la réponse du serveur en PHP.

Indications JS
La réponse du serveur sera du texte simple: soit "ok" soit "erreur".

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.

Indications PHP

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';



Exercice : commentaires - bouton « J'aime »

6.8 Correction

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';