Démultiplication des petits pains..

Par Franck RELLO, il y a 8 ans


Bonjour,

Je suis en train de travailler sur un gestionnaire d'habilitation qui va permettre aux utilisateurs enregistrés d'accéder à une ou plusieurs applications en ligne.
J’ai créé un formulaire qui permet de sélectionner un utilisateur d'autoriser son accès à une application web.
Le formulaire est on ne peut plus simple et tous les échanges avec la base de données s’effectuent avec AJAX.

Mon formulaire

Dans mon formulaire j'ai :
Un évènement attaché à un menu déroulant (bootstrap-select) qui permet de sélectionner un utilisateur et de récupérer de la table sql des utilisateurs les informations dont j'ai besoin.

<div class="container"> <h1>Ajouter un utilisateur</h1> <div id="addform" class="col-lg-6"> <form action="#" class="form-horizontal" enctype="application/x-www-form-urlencoded"> <div class="form-group"> <label class="control-label col-lg-4" for="identite">Identifiant : </label> <div class="col-lg-8"> <select id="idselection" class="selectpicker" data-live-search="true" title="Matricule/Nom" data-width="auto"> <option selected disabled ></option> <?php foreach ($userslist as $item): ?> <option value="<?= $item->matricule; ?>" ><?= $item->nom; ?> <?= $item->prenom; ?> <?= $item->matricule; ?></option> <?php endforeach; ?> </select> </div> </div> </form> <div id="user" data-app="<?= is_numeric($this->request->params[0]) ? $this->request->params[0] : null; ?>"></div> </div> </div>

Le résultat de la requête est affiché dans le div#user par chargement d'un fichier php userprofile.php dans lequel j'insère les informations :

<div class="userprofilebox"> <div class="input-group"> <span class="input-group-addon">NOM : </span> <p id="nom" class="form-control"></p> </div> <div class="input-group"> <span class="input-group-addon">PRENOM : </span> <p id="prenom" class="form-control"></p> </div> <div class="input-group"> <span class="input-group-addon">MATRICULE : </span> <p id="matricule" class="form-control"></p> </div> <div class="input-group"> <span class="input-group-addon">SERVICE : </span> <p id="service" class="form-control"></p> </div> <div class="row"> <button id="validate" class="btn btn-success" type="button" value="" ><span class="glyphicon glyphicon-ok"></span> Habiliter</button> <a class="btn btn-danger" href="<?= WEBROOT; ?>/app/liste" target="_parent" title="Retour à la liste des applications" ><span class="glyphicon glyphicon-remove"></span> Abandon</a> </div> </div>

..et je clique sur le bouton Habiliter pour enregistrer cette nouvelle habilitation.

Mon Jquery

$(function () { // Selection de l’utilisateur $("#idselection").on('changed.bs.select', function (e) { var identifiant = $(this).val(); function reponse(callback) { $.ajax({ url: "applications/activedirectory/PHPScripts/ajax-get-user", // requete sur table des utilisateurs method: "post", data: {ref: identifiant}, dataType: 'JSON' }) .done(function (data, textStatus, jqxhr) { callback(data); }) .fail(function (jqxhr) { callback(jqxhr.responseText); }); } // Resultat de la requet est affiché dans la page userprofile.php chargée dans un div (J'avais la flême de générer du DOM) reponse(function (data) { var app = $("#user").data('app'); $("#user") .load('userprofile', function (e) { $(this).find('#nom').text(data.nom); $(this).find('#prenom').text(data.prenom); $(this).find('#matricule').text(data.matricule); $(this).find('#service').text(data.service); $(this).find('#validate').attr('value', data.matricule); // Bouton de validation }) // Click sur le bouton de validation .on('click', 'button#validate', function (e) { function calling(callback) { // Requete INSERT dans la table des habilitations $.ajax({ url: "applications/activedirectory/PHPScripts/ajax-add-user", method: "post", data: {app: app, ref: identifiant}, dataType: 'JSON' }) .done(function (data, textStatus, jqxhr) { callback(data); }) .fail(function (jqxhr) { callback(jqxhr.responseText); }); } // Affichage d’un message (erreur ou succès) calling(function (data) { var msg = "<div class='col-lg-12 alert alert-info'>"; msg += "<button type='button' class='close' aria-label='Close' data-dismiss='alert'><span aria-hidden='true'>&times;</span></button>"; msg += "<h4>Message</h4>"; msg += "<p>" + data +"</p>"; msg += "</div>"; $("#user").before(msg); }); }); }); }) });

Ce que j'obtiens

Tous fonctionne à merveille (hormis les messages mais ça c'est un détail)  ! Sauf… que dans la console du navigateur (network onglet XHR) je vois apparaître l’impensable ! l’inimaginable !

Dans mon formulaire je sélection un utilisateur, les informations s'affichent, je clique sur le bouton button#validate, il est enregistré dans la table des utilisateurs habilités.

Je continue, je sélectionne un autre utilisateur, les informations de ce nouvel utilisateur remplacent les précédentes, je clique sur le bouton button#validate, il est enregistré.

etc.. donc je suis content !

MAIS !
Voilà ce qu'il se passe lorsque je surveille l'activité dans la console du navigateur -> network onglet XHR
Premier utilisateur : une requête vers ajax-add-user.php
Deuxième utilisateur : je vois 2 requêtes vers ajax-add-user.php ( le premier utilisateur suivi du second)
Troisième : je vois 3 requêtes vers ajax-add-user.php… (le premier suivi du second lui-même suivi du troisième).

etc..

Bon, j’ai cherché avant de poster sur le forum mais là… je donne ma langue au chat.
Jquery bubble ? Heu non j’pense pô.

Ma seule piste c’est la délégation du click sur le bouton #validate.
Pour l'heure j'ai réecrit le code jquery différement en séparant les contenus de l'évenement change et click

$(function(){ $("#idselection").on('changed.bs.select', function (e) {...} $(#user).on('click', 'button#validate', function (e) {..} });

C'est moche mais ça fonctionne aussi.
Si quelqu'un pouvait m'expliquer d'ou vient cette démultiplication du contenu de l'évènement CLICK, ça serait simpa :)

6 réponses

Maenhyr, il y a 8 ans

C'est parce que dans tu ajoutes un listener sur click a chaque fois dans ton callback de reponse().

Franck RELLO, il y a 8 ans

Bonjour et merci de ta réponse !
Cela je m'en doutais un peu ("Ma seule piste c’est la délégation du click sur le bouton #validate.") mais ce que j'ignore c'est le comment du pourquoi. A chaque selection d'un nouvel utilisateur les variables destinées à transmettre les données en POST par AJAX sont réinitialisées non ? Comment se peut il que les réponses AJAX précédentes soient toujours rappelées lors d'une nouvelle excution du code ? C'est ça que je ne comprend pas...

Psylozoff, il y a 8 ans

Définit ton évènement click une seule fois et utilise des variables...
Si tu ne connais rien à javascript arrête d'utiliser jquery -_-
Apprends js et ensuite tu pourras légitimement, facilement et de façon transparente te "faciliter" la vie avec jquery ou n'importe quel autre framework..!

Franck RELLO, il y a 8 ans

Merci prbaron, voilà une réponse tout à fait productive et qui va me permettre d'avancer dans mon apprentissage !
Psylozoff, je me passerais volontier de ce genre de commentaires d'autant que la solution ne m'intéresse pas, mais plutôt une piste de reflexion , un lien vers un article, afin comprendre mon erreur.

Psylozoff, il y a 8 ans

Tu dis que tu ne comprends pas la notion de "gestionnaire d'évènement" qui est pourtant une des bases fondamentales de javascript ^^
Or, tu nous présentes du jQuery : un framework qui occulte la majeure partie de la logique applicative de JS :-s
Je te dis juste que tu essaies de comprendre le fonctionnement d'un moteur en regardant la carrosserie...