Page 1 sur 1

Formulaire & Ajax

Posté : 10 sept. 2021, 19:48
par Heavy
Bonjour,

En formation développeur-intégrateur web, je suis bloqué sur un devoir qui porte sur Ajax. Après plusieurs jours de dépatouillage, j'ai enfin réussi à obtenir plus ou moins ce que je voulais, mais le résultat ne correspond pas totalement à la demande et je bloque complètement.

Tout d'abord, la partie de l'énoncé qui me pose problème :
Demande 2
Complétez votre code JavaScript pour fournir le comportement suivant.

Écoutez en JavaScript, la modification de l’élément Select.
Lorsque l’utilisateur choisit une note:
  1. Envoyez au serveur PHP une requête AJAX en envoyant la valeur de l’élément et en récupérant en JavaScript
    l’url du script PHP dans l’attribut ACTION de l’élément FORM.

    Sur le serveur
  2. A l’aide de la valeur du SELECT, il doit retrouver dans son tableau de correspondance (array) sa correspondance américaine (voir Devoir N° 1 de JavaScript perfectionnement)
  3. Votre code PHP doit retourner le message « La notation américaine pour la note X est X». Javascript le récupère
    et l’affiche dans un élément de la page.
Le Javascript doit être unobstrusive.

Demande 3
Dans votre code JavaScript: ne générez plus le formulaire. Celui-ci sera généré par le PHP, sur demande du
Javascript (requête Ajax): voir ci-dessous.
  1. Lorsque la page est chargée (évènement onload), et que l’utilisateur clique sur le bouton “notation”, envoyez
    une requête au serveur php pour récupérer le HTML du formulaire et insérez-le dans le body. Cachez alors le
    bouton notation en lui affectant un attribut style (css) “display:none;”
  2. Si l’utilisateur clique sur un nouveau bouton « close», cachez le formulaire et faites réapparaitre le bouton
    « notation».
  3. Si l’utilisateur reclique sur le bouton « notation», testez si le formulaire est déjà inséré dans le HTML. Si oui,
    réaffichez-le et cachez le bouton, sinon demandez (en JS) le formulaire en Ajax au serveur PHP.
Le JavaScript doit être unobstrusive.
J'ai réussi une partie de cet énoncé : quand on clique sur le bouton notation, la requête est envoyée au serveur PHP et le formulaire inséré dans la page index.html. Et quand on appuie sur le bouton close, le formulaire est caché et le bouton notation réapparait. Mais j'ai un problème :
  • Lorsque je change la valeur du select, le formulaire est bien envoyé mais il me redirige vers la page form.php. Or, ce que je souhaiterais, c'est que le résultat soit également affiché sur la page index.html. Changer le action du formulaire ne fait que recharger la page index.html (et donc le formulaire disparaît...).

    index.html
    <!DOCTYPE html>
    <html lang="fr">
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Correspondance des notes de musique classiques et américaines</title>
            <script src="script.js"></script>
            <link rel="stylesheet" href="style.css">
        </head>
        <body>
            <input type="button" id="notationBtn" value="Notation">
            <div id="phpDiv"></div>
        </body>
    </html>
    script.js
    (function() {
        var jsNotes = {
            init: function() {
                window.addEventListener('load', function(event) {
                    var notationBtn = document.getElementById('notationBtn');
                    notationBtn.addEventListener('click', function(event) {
                        event.preventDefault ? event.preventDefault() : event.returnValue = false;
    
                        var closeBtn = document.createElement('input');
                            closeBtn.type = 'button';
                            closeBtn.id = 'closeBtn';
                            closeBtn.value = 'Close';
                        document.body.appendChild(closeBtn);
    
                        notationBtn.style.display = 'none';
                        closeBtn.style.display = 'block';
                        phpDiv.style.display = 'block';
    
                        if (!document.getElementById('formNotes')) {
                        var xhr = new XMLHttpRequest();
                        xhr.addEventListener('readystatechange', function(event) {
                            if (xhr.readyState == 4) {
                                if (xhr.status == 200) {
                                    var phpDiv = document.getElementById('phpDiv');
                                        phpDiv.innerHTML = xhr.responseText;
                                } else {
                                    alert ('error code ' + xhr.status + ' : ' + xhr.statusText);
                                }
                            }
                        });
                        xhr.open('GET', 'form.php', true);
                        xhr.send();
                        } else {
                            phpDiv.style.display = 'block';
                        }
    
                        var stdNote = document.getElementById('stdNote');
                        stdNote.addEventListener('change', function(event) {
                            var results = document.getElementById('results');
                            phpDiv.appendChild(results);
                        })
    
                        closeBtn.addEventListener('click', function(event) {
                            event.preventDefault();
                            notationBtn.style.display = 'block';
                            closeBtn.style.display = 'none';
                            phpDiv.style.display = 'none';
                        })
                    });
                });
            }
        };
        jsNotes.init();
    })();
    form.php
    <!DOCTYPE html>
    
    <?php
        $notes = array (
            'Do' => 'C',
            'Ré' => 'D',
            'Mi' => 'E',
            'Fa' => 'F',
            'Sol' => 'G',
            'La' => 'A',
            'Si' => 'B'
        );
        $result = '';
    
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (empty($_POST['stdNote'])) {
                $result = '<p>Aucune note sélectionnée.</p>';
            } else {
                $note = $_POST['stdNote'];
                $result = '<p>La note classique '. $note .' correspond à la note américaine '. $notes[$note] .'.</p>';
            }
            echo $result;
            return;
        }
    ?>
    
    <html lang="fr">
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Correspondance des notes de musique classiques et américaines</title>
        </head>
        <body>
            <h1>Correspondance américaine des notes de musique</h1>
    
            <form action="form.php" method="POST" id="formNotes">
                <fieldset>
                    <legend>Correspondance classique > américaine</legend>
                    <label for="stdNote">Sélectionnez une note : </label>
                    <select name="stdNote" id="stdNote" onchange="this.form.submit()">
                        <option value="">Choix</option>
                        <?php foreach ($notes as $stdNote => $usNote): ?>
                            <option value="<?php echo $stdNote ?>"><?php echo $stdNote ?></option>
                        <?php endforeach ?>
                    </select><br>
                    <div id="results"><?php echo $result ?></div>
                </fieldset>
            </form>
        </body>
    </html>
    J'ai beau chercher sur internet, me tourner les méninges, rien n'y fait, je n'arrive pas à faire en sorte que le result soit également inséré dans mon index.html, si quelqu'un peut m'indiquer ce que je fais mal, ou ce que je ne fais pas ?
    Merci d'avance !

Re: Formulaire & Ajax

Posté : 10 sept. 2021, 20:53
par or 1
en commençant par faire la demande 2, ce sera plus simple de faire la demande 3.
lors de la sélection d'une note dans le select, le formulaire est soumis, de la même façon que si l'on cliquait sur l'input submit. ce n'est pas ce qui est demandé. grâce à l'ajax, il ne doit pas y avoir rechargement de la page, comme il n'y a pas rechargement de la page quand on fait apparaitre le formulaire en appuyant sur le bouton "Notation".

Re: Formulaire & Ajax

Posté : 10 sept. 2021, 22:50
par Heavy
Merci or1 pour ta réponse. Je suis effectivement passé à la demande 3 avant de réaliser la 2, étant bloqué sur cette dernière j'ai pensé que transférer la génération du formulaire sur le PHP m'aiderait à y voir plus clair. Visiblement, non. :-#

J'ai donc récupéré un script que j'avais fais et qui correspond au devoir (minus la partie PHP, évidemment).
(function() {
    var jsNotes = {
        init: function() {
            window.addEventListener('load', function(event) {
                var notationBtn = document.getElementById('notationBtn');
                    notationBtn.style.display = 'block';

                notationBtn.addEventListener('click', function(event) {
                    event.preventDefault ? event.preventDefault() : event.returnValue = false;

                    var closeBtn = document.createElement('input');
                        closeBtn.type = 'button';
                        closeBtn.id = 'closeBtn';
                        closeBtn.value = 'Close';
                        closeBtn.style.display = 'block';
                    document.body.appendChild(closeBtn);

                    notationBtn.style.display = 'none';

                    var h1 = document.createElement('h1');
                        h1.textContent = 'Correspondance des notes de musique classiques et américaines';
                    var form = document.createElement('form');
                        form.action = 'form.php';
                        form.id = 'notesForm';
                        form.name = 'notesForm';
                    var fieldset = document.createElement('fieldset');
                    var legend = document.createElement('legend');
                        legend.textContent = 'Correspondance classique > américaine';
                    var label = document.createElement('label');
                        label.htmlFor = 'selectNote';
                        label.textContent = 'Sélectionnez la note : ';
                    var select = document.createElement('select');
                        select.name = 'selectNote';
                    var option = document.createElement('option');
                        option.value = '';
                        option.textContent = 'Choix';
                    var paragraph = document.createElement('p');

                    document.body.appendChild(h1);
                    document.body.appendChild(form);
                    form.appendChild(fieldset);
                    fieldset.appendChild(legend);
                    fieldset.appendChild(label);
                    fieldset.appendChild(select);
                    select.appendChild(option);
                    fieldset.appendChild(paragraph);

                    const notesArray = {
                        'C' : 'Do',
                        'D' : 'Ré',
                        'E' : 'Mi',
                        'F' : 'Fa',
                        'G' : 'Sol',
                        'A' : 'La',
                        'B' : 'Si'
                    };

                    const keys = Object.keys(notesArray);

                    keys.forEach((key, index) => {
                        var options = document.createElement('option');
                            options.value = key;
                            options.textContent = notesArray[key];
                        select.appendChild(options);
                    });

                    select.addEventListener('change', function(event) {
                        if (select.options[this.selectedIndex].value === '') {
                            paragraph.textContent = 'Aucune note n\'a été sélectionnée.';
                            paragraph.style.backgroundColor = '#FAA0A0';
                        }
                        else {
                            paragraph.textContent = 'La note américaine correspondant à la note ' + select.options[this.selectedIndex].textContent + ' est ' + this.value + '.';
                            paragraph.style.backgroundColor = '#C1E1C1';
                        }
                    });

                    closeBtn.addEventListener('click', function(event) {
                        notationBtn.style.display = 'block';
                        closeBtn.style.display = 'none';
                        h1.style.display = 'none';
                        form.style.display = 'none';
                    })
                });
            });
        }
    };
    jsNotes.init();
})();
Ce code est fonctionnel, il me permet de sélectionner la note dans la liste et de voir le résultat. Mais le problème que j'avais à ce moment-là, c'était que je ne comprenais pas vraiment la demande 2 (d'où le fait que je sois passé à la demande 3 directement). Étant donné que le formulaire est encore généré par Javascript à ce moment-là, j'ai du mal à comprendre comment envoyer la valeur de mon select et récupérer une URL étant donné que la page PHP est encore vide ?

Re: Formulaire & Ajax

Posté : 10 sept. 2021, 23:03
par or 1
un appui sur le bouton notation fait bien un appel ajax.
onchange="this.form.submit()" ne doit pas soumettre le formulaire mais faire un appel ajax.

Re: Formulaire & Ajax

Posté : 10 sept. 2021, 23:36
par Heavy
Donc si je comprends bien, le but serait de remplacer le onchange="this.form.submit()" du script PHP par le nom d'une fonction et de créer cette fonction dans le script JS pour qu'elle permette l'appel Ajax ?

Autant jusque-là ça allait, autant depuis l'introduction d'Ajax je suis totalement perdu. Je ne sais pas si c'est le cours qui explique mal ou moi qui n'y arrive tout simplement pas, mais j'ai du mal avec l'Ajax.

Re: Formulaire & Ajax

Posté : 11 sept. 2021, 00:15
par or 1
et pourtant, un clic sur notation fait bien un appel ajax, et le retour du serveur est bien traité.
xhr.open('GET', 'form.php', true);
appelle form.php
pour la note, il faut d'une manière ou d'une autre passer la note sélectionnée.

faire marcher tous les exemples de :
https://api.jquery.com/jquery.get/
et
https://api.jquery.com/jquery.post/
permet de comprendre ce qu'est l'ajax, même si l'utilisation d'une telle librairie n'est pas permise.
pour bien comprendre l'ajax, il faut utiliser les outils pour le développeur de son navigateur.

Re: Formulaire & Ajax

Posté : 16 sept. 2021, 19:27
par Heavy
Bonjour,

Désolé pour le temps de réponse, j'ai beaucoup tourné et j'ai enfin réussi à générer la réponse dans le fichier PHP et à l'intégrer dans le fichier HTML.
(function() {
    var notes = {
        init: function() {
            window.addEventListener('load', function(event) {
                var notationBtn = document.getElementById('notationBtn');
                    notationBtn.style.display = 'block';

                notationBtn.addEventListener('click', function(event) {
                    event.preventDefault();

                    var closeBtn = document.createElement('input');
                        closeBtn.type = 'button';
                        closeBtn.id = 'closeBtn';
                        closeBtn.value = 'Close';
                        closeBtn.style.display = 'block';
                    document.body.appendChild(closeBtn);

                    notationBtn.style.display = 'none';

                    var h1 = document.createElement('h1');
                        h1.textContent = 'Correspondance des notes de musique classiques et américaines';
                    var form = document.createElement('form');
                        form.action = 'form.php';
                        form.id = 'notesForm';
                        form.name = 'notesForm';
                    var fieldset = document.createElement('fieldset');
                    var legend = document.createElement('legend');
                        legend.textContent = 'Correspondance classique > américaine';
                    var label = document.createElement('label');
                        label.htmlFor = 'selectNote';
                        label.textContent = 'Sélectionnez la note : ';
                    var select = document.createElement('select');
                        select.name = 'selectNote';
                    var option = document.createElement('option');
                        option.value = '';
                        option.textContent = 'Choix';
                    var response = document.createElement('p');
                        response.id = 'response';
                    

                    document.body.appendChild(h1);
                    document.body.appendChild(form);
                    form.appendChild(fieldset);
                    fieldset.appendChild(legend);
                    fieldset.appendChild(label);
                    fieldset.appendChild(select);
                    select.appendChild(option);
                    fieldset.appendChild(response);

                    const notesArray = {
                        'C' : 'Do',
                        'D' : 'Ré',
                        'E' : 'Mi',
                        'F' : 'Fa',
                        'G' : 'Sol',
                        'A' : 'La',
                        'B' : 'Si'
                    };

                    const keys = Object.keys(notesArray);

                    keys.forEach((key, index) => {
                        var options = document.createElement('option');
                            options.value = key;
                            options.textContent = notesArray[key];
                        select.appendChild(options);
                    });

                    select.addEventListener('change', function(event) {
                        var httpRequest = new XMLHttpRequest();
                        var url = form.action;
                        var param1 = select.options[this.selectedIndex].value;
                        var param2 = select.options[this.selectedIndex].textContent;
                        httpRequest.open('GET', url+'?usNote='+param1+'&stdNote='+param2, true)
                        httpRequest.addEventListener('readystatechange', function(event) {
                            if (httpRequest.readyState == 4) {
                                if (httpRequest.status == 200) {
                                    response.innerHTML = httpRequest.responseText;
                                } else {
                                    alert('Error code ' + httpRequest.status + ' : ' +httpRequest.statusText);
                                }
                            }
                        });
                        httpRequest.send();
                    });

                    closeBtn.addEventListener('click', function(event) {
                        notationBtn.style.display = 'block';
                        closeBtn.style.display = 'none';
                        h1.style.display = 'none';
                        form.style.display = 'none';
                    });
                });
            });
        }
    };
    notes.init();
})();
Maintenant il ne me reste plus qu'à générer le formulaire en PHP plutôt qu'en JS.