11484 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,
J'ai un problème sur le retour d'une fonction ajax. Il s'agit d'une requête Sql avec des variables issues d'un formulaire.
Mon retour ajax html se met à jour correctement uniquement si je clique deux fois sur mon élément déclencheur (même a 5s d'interval). Smiley confused
Je ne comprend pas pourquoi, mais j’aimerais simuler un double click si un simple click est détecté pour recevoir mon retour, ou comprendre pourquoi je dois cliquer 2 fois au lieu d'une...
Voici mon code Ajax:

$(document).ready(function(){
        $(".form-check-label").click(function(){
            $.ajax({
                type: "POST",
                url: "updater.php",
                data: $("#formu").serialize(),
                dataType : 'html',

                success: function (code_html, statut) {
                    $('.affiche').html(code_html);
                },

                error : function(resultat, statut, erreur){

                },

                complete : function(resultat, statut){

                }
            });

        });

    });

et mon code php :


<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto">
</head>
<body>

<?php
if (empty($_POST['forme'])){
    $_POST['forme'] = "rond";
};
if (empty($_POST['capacite'])){
    $_POST['capacite'] = "4";
};
if (empty($_POST['type_air'])){
    $_POST['type_air'] = "bulles";
};

$forme = $_POST['forme'];
$capacite = $_POST['capacite'];
$type_air = $_POST['type_air'];
$dimension = $_POST['dimension'];
$prix = $_POST['prix'];

$con = mysqli_connect('localhost','root','','spa');
if (!$con) {
    die('Could not connect: ' . mysqli_error($con));
}

mysqli_select_db($con,"index");
$sql="SELECT * FROM spa 
WHERE forme = '".$forme."'
AND nombre_personne >= '".$capacite."'
AND type_air = '".$type_air."'
AND dimension_sol <= '".$dimension."'
AND prix <= '".$prix."'
"
;

$result = mysqli_query($con,$sql);

while($row = mysqli_fetch_array($result)) {

    echo "<div class='bloc-spa'>";

        echo " <a href=" . $row['lien'] . "> ";

            echo " <div class='image-container'> ";
                echo " <img src='img/spa/" . $row['image'] . " ' class='card-img-top' alt=" . $row['image'] . "> ";
            echo " </div>";

            echo " <div class='card-body'>" . $row['designation'] . "</div> ";
            echo " <div  class='price-box'>" . $row['prix'] . ".00€</div> ";

        echo " </a> ";

    echo "</div>";

}

mysqli_close($con);

?>

</body>
</html>




Merci à tous pour votre aide Smiley sweatdrop
Modifié par louyi (15 Oct 2020 - 09:21)
Salut,

euh la question m'a l'air inquiétante.
A mon avis, il faudrait plutôt chercher pourquoi tu as besoin de faire un "double clique" (plutôt "cliquer deux fois" si il y a 5s entre chaque clique) que d'essayer de faire une magouille bizarre pour qu'un 2e clique se lance tout seul.

Ensuite en regardant rapidement, ton code m'a l'air assez inquiétant niveau sécurité / injection SQL. Globalement prendre une valeur inconnue, la mettre au milieu de ta requête et exécuter la requête, c'est prendre de gros risque ..
Il ne faut JAMAIS faire confiance aux entrées de l’utilisateur, il faudrait voir du coté des requêtes préparés ou du nettoyage de paramètres

Bon courage
Merci pour ta remarque, j'ai fait une requête préparée à la place, je focalisais sur Ajax Smiley rolleyes
Voici le code modifié :


<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto">
</head>
<body>

<?php
if (empty($_POST['forme'])){
    $_POST['forme'] = "rond";
};
if (empty($_POST['capacite'])){
    $_POST['capacite'] = "4";
};
if (empty($_POST['type_air'])){
    $_POST['type_air'] = "bulles";
};


include('php/sql-spa.php'); /// Connexion file to PDO database

/////////////////////////////////
$forme = $_POST['forme'];
$capacite = $_POST['capacite'];
$type_air = $_POST['type_air'];
$dimension = $_POST['dimension'];
$prix = $_POST['prix'];

$req = <<<EOF
SELECT
    *
FROM
    spa
WHERE
    forme = (:forme)
AND
    nombre_personne >= (:nombre_personne)
AND
    type_air = (:type_air)
AND
    dimension_sol <= (:dimension)
AND
    prix <= (:prix)
EOF;

// binValue PREPARE //
$stmt = $database->prepare($req);
$stmt->bindValue('forme', $forme, PDO::PARAM_STR);
$stmt->bindValue('nombre_personne', $capacite, PDO::PARAM_INT);
$stmt->bindValue('type_air', $type_air, PDO::PARAM_STR);
$stmt->bindValue('dimension', $dimension, PDO::PARAM_STR);
$stmt->bindValue('prix', $prix, PDO::PARAM_INT);

if (!$stmt->execute()) {
    echo "Erreur sur la selection";
} else {
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
};

$rowcount= count($products);

echo "<div class='totalItems'>";
echo  "           <button>Afficher " . $rowcount . " résultats</button>";
echo "</div>";



foreach($products as $row) {
    echo "<div class='bloc-spa'>";

    echo " <a href=" . $row['lien'] . "> ";

    echo " <div class='image-container'> ";
    echo " <img src='img/spa/" . $row['image'] . " ' class='card-img-top' alt=" . $row['image'] . "> ";
    echo " </div>";

    echo " <div class='card-body'>" . $row['designation'] . "</div> ";
    echo " <div  class='price-box'>" . $row['prix'] . ".00€</div> ";

    echo " </a> ";

    echo "</div>";
}

?>

</body>
</html>



Voyez vous ce que je n'ai pas codé correctement pour avoir le résultat au simple clique et non au deuxième? Smiley sweatdrop Smiley sweatdrop Smiley sweatdrop
Modifié par louyi (15 Oct 2020 - 09:33)
Salut

Ton ajax doit appeller uniquement du PHP

updater.php

dans ce fichier, il ne faut pas de "<html>" ou de "<body>". uniquement ton PHP avec UN SEUL ECHO, tu met tout dans une variable et il faut envoyer cette variable à la fin.
Modérateur
Bonjour,

Je viens de fabriquer une petite démo. Le problème ne peut venir que de la page (dont on n'a pas le code) dans lequel se trouve le formulaire et le script ajax.

Car ton script php que tu nous as montré et que je suppose être "updater.php" fonctionne (à peu près) en l'état (sauf qu'il faut peut-être corrigé ce qui concerne le champ "dimensions" (je l'ai mis en INT dans ma base de test)). Même si on y laisse les balises <html>, <body>, etc. Ceci dit, JENCAL a tout à fait raison de signaler qu'il ne faut pas les mettre.

Je ne vois pas où il y aurait un double-click à faire.

Voici le script de test avec le formulaire que j'ai utilisé (avec un vieux jquery, mais j'ai la flemme de mettre à jour dans mon environnement de test vu que jquery me file des boutons dès que je l'utilise) :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto">
<script src="jquery-3.3.1.min.js"></script>
</head>
<body>
<h1>Test</h1>
<form id="formu">
<input name="forme" type="text" value="rond">
<input name="capacite" type="text" value="4">
<input name="type_air" type="text" value="bulles">
<input name="dimension" type="text" value="100">
<input name="prix" type="text" value="100">
<button type="button" class="form-check-label">Go</button>
</form>
<div class="affiche">Contenu</div>
<script>
	$(document).ready(function(){
        $(".form-check-label").click(function(){
            $.ajax({
                type: "POST",
                url: "z206-update.php",
                data: $("#formu").serialize(),
                dataType : 'html',
                success: function (code_html, statut) {
                    $('.affiche').html(code_html);
                },

                error : function(resultat, statut, erreur){
					$('.affiche').html("Argh !");
                },

                complete : function(resultat, statut){
                }
            });

        });

    });
</script>
</body>
</html>

Amicalement,
Modérateur
Bonjour,

Et voici le code de "z206-update.php", qui correspond à ton "updater.php. Essentiellement, j'ai retiré les balises au début et à la fin, et j'ai remplacé $stmt->bindValue('dimension', $dimension, PDO::PARAM_STR); par $stmt->bindValue('dimension', $dimension, PDO::PARAM_INT); Les autres modifications sont cosmétiques.

<?php
if (empty($_POST['forme'])){
    $_POST['forme'] = "rond";
};
if (empty($_POST['capacite'])){
    $_POST['capacite'] = "4";
};
if (empty($_POST['type_air'])){
    $_POST['type_air'] = "bulles";
};

include('php/sql-spa.php'); /// Connexion file to PDO database

$database=new PDO('mysql:host='.$db_host.';dbname='.$db_name,$db_id,$db_pwd);

/////////////////////////////////
$forme = $_POST['forme'];
$capacite = $_POST['capacite'];
$type_air = $_POST['type_air'];
$dimension = $_POST['dimension'];
$prix = $_POST['prix'];

$req = <<<EOF
SELECT
    *
FROM
    spa
WHERE
    forme = (:forme)
AND
    nombre_personne >= (:nombre_personne)
AND
    type_air = (:type_air)
AND
    dimension_sol <= (:dimension)
AND
    prix <= (:prix)
EOF;

// binValue PREPARE //
$stmt = $database->prepare($req);
$stmt->bindValue('forme', $forme, PDO::PARAM_STR);
$stmt->bindValue('nombre_personne', $capacite, PDO::PARAM_INT);
$stmt->bindValue('type_air', $type_air, PDO::PARAM_STR);
$stmt->bindValue('dimension', $dimension, PDO::PARAM_INT);
$stmt->bindValue('prix', $prix, PDO::PARAM_INT);

if (!$stmt->execute()) {
    echo "Erreur sur la selection";
} else {
    $products = $stmt->fetchAll(PDO::FETCH_ASSOC);
};

$rowcount= count($products);

echo "<div class='totalItems'>";
echo  "           <button>Afficher " . $rowcount . " résultats</button>";
echo "</div>";

foreach($products as $row) {
    echo "<div class='bloc-spa'>";

    echo " <a href=" . $row['lien'] . "> ";

    echo " <div class='image-container'> ";
    echo " <img src='img/spa/" . $row['image'] . " ' class='card-img-top' alt=" . $row['image'] . "> ";
    echo " </div>";

    echo " <div class='card-body'>" . $row['designation'] . "</div> ";
    echo " <div  class='price-box'>" . $row['prix'] . ".00€</div> ";

    echo " </a> ";

    echo "</div>";
}

?>

Amicalement,
Modifié par parsimonhi (19 Oct 2020 - 12:11)
Merci pour ta réponse Smiley smile
Malgré tes corrections, il se produit toujours le même problème, le résultat s'affiche uniquement au 2eme clique.

Le problème vient plutôt de mon script Ajax ?
Merci encore de prendre du temps pour m'aider !
Je clique sur des input type radio (visible dans mon script ajax : $(".form-check-label").click(function()).
C'est une classe que j'ai mis sur tout mes box radio de mon formulaire, pour actualiser à chaque clique, dans l'idée d'un filtre comme trier des articles en temps réel sur n'importe quel site e-commerce.
Mais ça ne fonctionne qu'au deuxième clique Smiley sweatdrop
Modifié par louyi (19 Oct 2020 - 12:31)
Modérateur
Bonjour,

Bon, on avance.

C'est soit dans ton formulaire que se situe le problème, soit dans le choix de l'évènement déclencheur, soit les deux.

1) pour certains inputs, ce serait mieux d'avoir un évènement se déclenchant suite à un "change" plutôt qu'un "click" (dans ton ajax, tu dupliques le code pour le "click" et dans le code dupliqué, tu mets "change" au lieu de "click").
2) il y a peut-être autre chose dans ce formulaire qui empêche le "click" de déclencher une action dès le premier clic. Il faudrait voir le code html du formulaire.
3) ça peut dépendre des navigateurs utilisés aussi (même si je ne crois pas trop à cette hypothèse dans le cas présent).

Edit : question : y-t-il d'autres actions en javascript pour ce formulaire ?

Edit2 : essaie éventuellement ce code pour la partie ajax
	$(document).ready(function(){
        
         $(".form-check-label").on("input change click",function(){
            $.ajax({
                type: "POST",
                url: "z206-update.php",
                data: $("#formu").serialize(),
                dataType : 'html',
                success: function (code_html, statut) {
                    $('.affiche').html(code_html);
                },

                error : function(resultat, statut, erreur){
					$('.affiche').html("Argh !");
                },

                complete : function(resultat, statut){
                }
            });

        });

    });


Amicalement,
Modifié par parsimonhi (19 Oct 2020 - 13:23)
Voici le code HTML du formulaire :

<?php
include('php/sql-spa.php');

$_POST['forme'] = "rond";
$_POST['capacite'] = "4";
$_POST['type_air'] = "bulles";

?>

<!doctype html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" href="css/config-spa.css">

    <title>Configurateur Spa</title>

</head>
<body>
<form id='formu' action="config-spa-success.php" method="post">

    <div class="container">

        <h1>Je choisis mon spa</h1>

        <div class="sortContainer">

            <div class="sortBox forme row1">
                <div class="sortTitle">
                    Forme de mon spa
                </div>

                <div class="sortIconBox">

                    <div class="sortItem forme">
                        <input class="form-check-input" type="radio" name="forme" id="Rond" value="Rond" required>
                        <label class="form-check-label" for="Rond"> <img src="img/spa/spa-rond.png" alt="spa rond">
                            <div class="text">
                                Rond
                            </div>
                        </label>
                    </div>

                    <div class="sortItem forme">
                        <input class="form-check-input" type="radio" name="forme" id="Carré" value="Carré" required>
                        <label class="form-check-label" for="Carré"> <img src="img/spa/spa-carre.png" alt="spa carré">
                            <div class="text">
                                Carré
                            </div>
                        </label>
                    </div>

                    <div class="sortItem forme">
                        <input class="form-check-input" type="radio" name="forme" id="Octo" value="Octo" required>
                        <label class="form-check-label" for="Octo"> <img src="img/spa/spa-octo.png" alt="spa octogonal">
                            <div class="text">
                                Octogonal
                            </div>
                        </label>
                    </div>

                </div>

                </div>

            <div class="row row2">
            <div class="col-sm sortBox capacite">
                <div class="sortTitle">
                    Capacité minimum
                </div>
                <div class="sortIconBox">

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="capacite" id="4" value="4" required>
                        <label class="form-check-label" for="4">
                            <div class="text">
                                4
                            </div>
                        </label>
                    </div>

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="capacite" id="6" value="6" required>
                        <label class="form-check-label" for="6">
                            <div class="text">
                                6
                            </div>
                        </label>
                    </div>

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="capacite" id="7" value="7" required>
                        <label class="form-check-label" for="7">
                            <div class="text">
                                7
                            </div>
                        </label>
                    </div>

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="capacite" id="8" value="8" required>
                        <label class="form-check-label" for="8">
                            <div class="text">
                                8
                            </div>
                        </label>
                    </div>

                </div>
            </div>
            <div class="col-sm sortBox type">
                <div class="sortTitle">
                    Type de massage
                </div>

                <div class="sortIconBox">

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="type_air" id="bulles" value="bulles" required>
                        <label class="form-check-label" for="bulles">
                            <div class="text">
                                Bulles
                            </div>
                        </label>
                    </div>

                    <div class="sortItem">
                        <input class="form-check-input" type="radio" name="type_air" id="jets" value="jets" required>
                        <label class="form-check-label" for="jets">
                            <div class="text">
                                Jets
                            </div>
                        </label>
                    </div>

                </div>

            </div>
            </div>
       
            <div class="row row5">
                <div class="col-sm sortBox dimensions">
                    <div class="sortTitle">
                        Dimensions au sol
                    </div>
                    <div class="slider">
                        <input type = "range" min="223" max="287" name="dimension" value="287" class="slider" id="dimension">
                        <p><span id="cm">287</span>cm</p>
                    </div>
                    <script>
                        var slider1 = document.getElementById("dimension");
                        var output1 = document.getElementById("cm");
                        output1.innerHTML = slider1.value;

                        slider1.oninput = function() {
                            output1.innerHTML = this.value;
                        }
                    </script>
                </div>

                <div class="col-sm sortBox prix">
                    <div class="sortTitle">
                        Prix
                    </div>

                    <div class="slider">
                        <input type="range" min="329" max="1129" name="prix" value="1129" class="slider" id="prix">
                        <p><span id="value">1129</span>.00€</p>
                    </div>
                    <script>
                        var slider2 = document.getElementById("prix");
                        var output2 = document.getElementById("value");
                        output2.innerHTML = slider2.value;

                        slider2.oninput = function() {
                            output2.innerHTML = this.value;
                        }
                    </script>

                </div>

            </div>

        </div>

        <div class="alert alert-warning alert-bloc1" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close"></button>
            <strong>Veuillez sélectionner vos options. </strong>
        </div>

        <!--<div class="totalItems">
            <button>Afficher <?php echo count($reponse); ?> résultats</button>
        </div>-->

        <div class="affiche">
            <button type="submit">VOIR MES SPAS</button>
        </div>

        <!--<div class="affiche">
            Texte à afficher
        </div>-->

    </div>

</form>

<script>
    $(document).ready(function(){
        $(".form-check-label").on("input change click",function(){
            $.ajax({
                type: "POST",
                url: "updater.php",
                data: $("#formu").serialize(),
                dataType : 'html',
                success: function (code_html, statut) {
                    $('.affiche').html(code_html);

                },

                error : function(resultat, statut, erreur){
                    $('.affiche').html("Argh !");
                },

                complete : function(resultat, statut){
                }

            });

        });

    });


</script>

</body>
</html>




Je dois écrire la fonction ajax 'onchange' sur chaque input? Je pensais qu'avec jQuery il n'y avait pas besoin .

PS: je ne sais pas si il y a un lien, mais j'ai bien écris REQUIRED sur chaque input, mais si j'essaye de valider le formulaire sans choisir une option, je n'ai pas l'alerte qui stipule qu'il faut cocher par defaut (et le form ne passe pas).
Modifié par louyi (19 Oct 2020 - 13:50)
Modérateur
Bonjour,

Non, tu n'as pas besoin d'un ajax pour chaque input.

1) si on clique sur les labels des radios, ça marche direct. Si on clique sur les radios eux-même, ça ne marche pas parce que ces boutons radios n'ont pas la même classe que les labels et que ton code jquery ne déclenche que sur la classe des labels.

Je pense que ce que tu prenais pour 2 clics était en fait un clic sur le radio puis un clic sur son label (à moins que ta feuille de style fasse recouvrir les radios par leurs labels).

2) Pour les sliders, ils n'ont pas la classe "form-check-label", donc évidemment, pour eux, rien ne se produit.

Il faut donc changer la manière de cibler les inputs qui sont modifiés par l"utilisateur. et a priori, on a besoin de ne réagir qu'au click finalement.

Dans le jquery ci-dessous, j'ai donc ajouté ".form-check-input" et "[type=range]" à ".form-check-label" pour cibler tous les inputs concernés (au lieu de seulement les labels dans ta version), et j'ai retiré les actions pour "input" et "change", car finalement, avec ton formulaire, ce n'est pas nécessaire.

Le problème de jquery, c'est souvent ça : les gens ont du mal à voir à quoi correspond les lignes de codes qu'ils écrivent. Du coup, c'est du pifomètre.

    $(document).ready(function(){
        $(".form-check-label,.form-check-input,[type=range]").on("click",function(){
            $.ajax({
                type: "POST",
                url: "updater.php",
                data: $("#formu").serialize(),
                dataType : 'html',
                success: function (code_html, statut) {
                    $('.affiche').html(code_html);

                },

                error : function(resultat, statut, erreur){
                    $('.affiche').html("Argh !");
                },

                complete : function(resultat, statut){
                }

            });

        });

    });

Amicalement,
Modifié par parsimonhi (19 Oct 2020 - 14:12)
Encore merci Smiley smile Ça réagit maintenant bien au 1er clique mais aléatoirement Smiley sweatdrop .
Cela provient de ma structure label/Input lié au css tu penses?

J'ai caché les inputs comme ceci en CSS :
.sortItem input {
    position: relative;
    display: none;
}


Un screen pour donner une idée :
https://ibb.co/8rBvht8
Modérateur
Bonjour,
louyi a écrit :

Cela provient de ma structure label/Input lié au css tu penses?

J'ai caché les inputs comme ceci en CSS :
.sortItem input {
    position: relative;
    display: none;
}


Dire que quand j'ai écris que si les labels recouvraient les inputs, ça pouvait influer, je me disais intérieurement : "mais de toute façon, il n'a surement pas fait ça !".

Et bien si, tu l'as fait ! Smiley smile

Il est probable que ton label n'est pas l'élément qui a le fond blanc, mais que c'est son parent, et que le label est plus petit que le parent.

On peut améliorer soit en modifiant le css, soit en modifiant le html et le css (en mettant le label autour de l'input).

Si tu ne modifies que le css :

1) tu ne mets pas ton input en display:none
2) tu mets le div autour du label en position:relative
3) tu mets l'input en position absolute (du coup le label s'affichera par dessus l'input)
4) tu mets le fond blanc sur ton label (tu mets le label en display:block;)
5) tu fais en sorte que ton label remplisse tout le div qui l'entoure (là, ça dépend comment est fait ton css, et en particulier comment tu détermines la taille du rectangle blanc : est-ce le label qui donne la taille du div qui l'entoure ou bien est-ce le div qui donne la taille du rectangle blanc actuellement).

Amicalement,
Modifié par parsimonhi (19 Oct 2020 - 16:01)
Merci je vais essayer avec toutes tes infos Smiley smile

Comme tu l'a fait remarque au début de ta dernière réponse, "Et bien si, tu l'as fait ! " ^^, il ne faut pas faire comme j'ai fait, cad recouvrir les inputs avec les label? (c’était pour avoir des radio stylisé comme des bouton à cliquer comme sur mon screen).
Modérateur
Bonjour,

Si, tu peux, mais il faut mettre l'input radio en dessous et non le cacher avec display:none selon moi. Y en a beaucoup qui utilisent les labels pour changer l'aspect des inputs car ceux-ci sont difficiles à styler.

Mon "Et bien si, tu l'as fait !", c'était plutôt le constat d'une nouvelle surprise à propos de ce sujet ! Smiley cligne

Amicalement,