11540 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous!

Après 3 jours de débâcle, je m'en remets à vous.
Comme signifié dans le titre, mon problème concerne le rechargement d'une portion de page contenant du Javascript, grâce à AJAX.

Je m'explique :
J'ai un formulaire d'ajout de chansons (toujours les même projets !!). Lors de la validation de celui-ci, j'utilise XMLHttpRequest qui est censé faire l'insertion en BD et recharger le contenu d'un DIV. Ce DIV contient à l'origine une table, qui comme vous l'aurez compris contient la liste des chansons.
Donc, lorsque je valide le formulaire, je fais appel à une fonction javascript qui s'occupe d'insérer en BD la nouvelle chanson saisie dans le formulaire et de recharger ma table avec les nouvelles valeurs (par un nouveau 'select' en BD).

Fonction JS exécutée lors de la validation :
 
if (window.XMLHttpRequest) { // Mozilla, Safari,...
     httpRequest = new XMLHttpRequest();
     if (httpRequest.overrideMimeType) {
          httpRequest.overrideMimeType('text/xml');
     }
          }
     else if (window.ActiveXObject) { // IE
          try { httpRequest = new ActiveXObject("Msxml2.XMLHTTP"); }
          catch (e) {
               try { httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); }
                    catch (e) {}
          }
     }
     if (!httpRequest) {
          alert("Abandon : blablabla...");
          return false;
     }
httpRequest.open('POST', 'insert.php', false);
     httpRequest.onreadystatechange = function() {
          if (httpRequest.readyState == 4) {
               if (httpRequest.status == 200) {
setInnerHTML(document.getElementById('reload_div'), httpRequest.responseText);
               } else { alert('Un problème est ...'); }
          }


Contenu du fichier 'insert.php' :

<?php header('Content-type: text/html; charset=iso-8859-1');
mysql_connect($host,$user,$password) or die ("Erreur de conn..");
mysql_select_db ($database) or die ("Erreur de co");

$req = "insert into ...";
	if ( !mysql_query ($req)) {
		echo "Erreur lors de l'insertion de ...;
	} else {
		require_once "affich_table.php"; }
?>

Le fichier 'affich_table.php' établit la structure d'un tableau avec les données récupérés en BD.

Le souci, c'est que j'ai deux fonctions JS (dans 'affich_table.php') qui permettent le tri en temps réel de la table et l'affichage d'infobulles. Ces deux fonctions utilisent jQuery.
Quant j'arrive sur la page initialement, le tri et les infobulles marchent correctement. Lorsque je réalise une première insertion et que ma table est rechargée, ces deux fonctions ne fonctionnent plus.

Mon problème revient donc à l'exécution de code JS au travers de la fonction
 httpRequest.responseText

J'ai lu énormément de discussion qui traitent de ce sujet. Malheureusement, j'ai n'ai toujours pas de solutions et je suis à présent complètement perdus.


setInnerHTML devait être la fonction miracle, qui permettait de 'mettre à jour' un div en prenant en compte le code javascript. Mais cela ne fonctionne pas.
J'ai essayé également de recharger uniquement le contenu de la table, placer dans les DIV grâce à 'innerHTML' et ensuite de rapellé directement mes fonctions JS. sans succès...
Quelqu'un peut m'expliquer la fonction append() propre à jQuery, qui semblerait être une solution ?


J'ai besoin d'aide là ...
Help Me Please...
Modifié par AdJiBouDi (18 Jun 2008 - 14:56)
Modérateur
Salut,

Tes fonctions de tri et d'affichage d'infobulle interprètent le DOM au chargement de la page.
Lorsque tu fais une requête Ajax, tu mets à jour ton tableau et du coup, le DOM change ce qui fait que ces scripts ne fonctionnent plus vu qu'ils ont en mémoire l'ancienne structure.
Donc, il faut relancer tes fonctions en réévaluant le DOM une fois la mise à jour effectuée. Smiley cligne
Modifié par koala64 (18 Jun 2008 - 14:55)
Bonjour!

Merci pour ta réponse koala64.

Mais je comprends pas ce que tu veux dire par 'réévaluer le DOM'.
Je suis désolé, je suis pas un pro du javascript, et c'est la première fois que j'utilise AJAX...

Ce que j'ai fais, c'est re-éxécuter la fonction JS d'origine, je suppose que ce n'est pas la même chose que réévaluer le DOM...
Modifié par AdJiBouDi (18 Jun 2008 - 15:09)
Up!

J'ai vraiment vraiment besoin d'aide SVP, cette 'broutille' me bloque depuis maintenant 4 jours et je peux pas avancer...
Et
Smiley fache Smiley sweatdrop
Modifié par AdJiBouDi (18 Jun 2008 - 17:21)
Modérateur
eh oh ?! tout doux... C'est qu'on a du boulot aussi... Smiley rolleyes Inutile de faire un up en si peu de temps. Smiley cligne

Quand je parle de réévaluer le DOM, ça veut dire que si le tableau que tu places via un innerHTML se trouve dans un conteneur avec un identifiant "cont" (par exemple), il faut que tu reparses ta page en resélectionnant ce conteneur et les éléments contenus qui déclenchent les actions afin que les gestionnaires d'événements (les fonctions que tu lances sur les onclick, onmouseover, etc...) puissent être réaffectées.

Concernant JQuery, il y a effectivement des fonctions dédiées à l'Ajax mais bon, si tu ne connais pas grand chose au JS, ça te permettra, tout au plus, d'aller plus vite mais certainement pas de mieux comprendre le cheminement à suivre pour mettre un tel système en place.

Ce qu'il faut comprendre, c'est que quelquesoit la bibliothèque dont tu te sers, elle va te permettre de faire des raccourcis au point que tu ne verras plus ce qu'il faut mettre en place... Une fois les notions de base acquises, ok mais avant, ce n'est pas forcément la meilleure chose à faire.
Arf !!

Désolé koala64. Veux pas me battre moi Smiley biggol
Non mais c'est que cette histoire me stress parck ça fé 4 jours que j'y suis dessus et j'ai pris énormément de retard... Sorry
Je potasse ce que tu as marqué.

Merci encore!
Modifié par AdJiBouDi (18 Jun 2008 - 18:20)
Merci pour ta réponse Koala64.

J'ai donc bien compris le principe, et surtout pourquoi ça ne fonctionne pas actuellement.
Je place en effet mon tableau dans un conteneur (SPAN) qui contient également les fonctions Javascript (je récapitule ici) :

J'ai donc déplacer les fonctions JS hors de ce conteneur, comme ceci :

<span id='reload'> <!-- CONTENEUR
<!-- Chargement du contenu de la 'page' (tableau + infobulles) -->
        <?php require_once "ma_tab.php"; ?> 
<!-- Javascript pour le Tri de Table et le ToolTip -->
        <?php require_once "imon_script.js.php"; ?>
<!-- Exécution du JS précédement chargé -->
        <script type="text/javascript">load_reload();</script>
</span>


Lors du rechargement de la page avec AJAX, 'httpRequest.responseText' renvoi uniquement le contenu de la page sans les fonctions JS, que j'inscris dans la page avec innerHTML, puis je fais appel au fonction :
if (httpRequest.status == 200) {
     document.getElementById('reload'), = httpRequest.responseText;
     load_reload(); //Relancement des fonctions JS



Il faut donc que je reparse ma page pour que les gestionnaires d'événements puissent être réaffectées.
Je comprends le 'principe' de parser un élément, comme pour PHP qui renvoie au serveur web une page dépourvue de php, mais là je ne sais pas trop par où commencer; j'ai essayé de tout relancer en même temps (code PHP + Javascript) et utiliser la fonction 'eval' mais cela ne fonctionne pas. Est-ce à cause du type de fonction JS (voir ci-dessous) :

window.addEvent('domready',function(){
     jQueryVarNoConflict(function() {
     jQueryVarNoConflict("table")
          .tablesorter({cssHeader: "sortHeader", cssAsc: "sortedASC", cssDesc: "sortedDESC"})
          .tablesorterPager({container: jQueryVarNoConflict("#pager"), size: 12});
     });
});
	
jQueryVarNoConflict(function(){
     jQueryVarNoConflict("a.clic").simpletooltip({click: true, effect: "slideDown", hideDelay: 0.4});
});


Merci pour ton aide Koala64, et promis je refais pas de 'up' (pas avant une heure en tout cas .. Smiley cligne ) !
Modifié par AdJiBouDi (19 Jun 2008 - 10:12)
Salut.
Je sais pas si j'ai exactement le même soucis, mais dans tous les cas j'aimerais bien savoir koala64 ce que tu entends par "reparser", "réévaluer" la page ?

En effet dans un de mes code JS (cf mon autre topic mais je réexplique vite fait la), je récupère le contenu d'un div avec document.getElementById('divId').innerHTML pour l'envoyer au serveur qui me renverra une autre version, que j'appliquerai à mon div. Le contenu de mon div a donc changé. Mais lorsque je réappelle ce code, que je récupère à nouveau le contenu du div, il me renvoie le contenu d'_avant_ mon changement. Sans prendre en compte mon changement donc.

Ca semble être plus ou moins le même problème non ?
Modérateur
Salut,

Ca rejoint le problème oué. Smiley cligne

mmh... bon, je laisse un exemple... Ce qu'il faut regarder, c'est surtout le principe de fonctionnement de la "classe" Test (à la fin du script), ce qui se trouve avant étant des fonctions d'aide.

index.php
<?php

header('Content-Type: text/html; charset=utf-8');
session_start();

?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<title>Exemple</title>
		<script type="text/javascript"><!--

(function() {

// SELECTION
var $ = function() {
	var aArgs = arguments;
	if(aArgs.length > 1 && typeof aArgs[1] == 'string') {
		return typeof aArgs[0] == 'string' ?
			document.getElementById(aArgs[0]).getElementsByTagName(aArgs[1]):
			aArgs[0].getElementsByTagName(aArgs[1]);
	}
	else switch(typeof aArgs[0]) {
		case 'string':
			return document.getElementById(aArgs[0]);
		case 'object':
			return aArgs[0];
	}
	return false;
};


// GESTION D'EVENEMENTS
var $e = {
	add: function() {
		var a = arguments;
		if(a[0] == 'domready')
			return $e.domready(a[1]);
		return document.addEventListener ?
			a[0].addEventListener(a[1], a[2], a[3] || false):
			a[0].attachEvent ?
				a[0].attachEvent('on' + a[1], a[2]):
				false;
	},
	stop: function(e) {
		if(e && e.stopPropagation && e.preventDefault) {
			e.stopPropagation();
			e.preventDefault();
		}
		else if(e && window.event) {
			window.event.cancelBubble = true;
			window.event.returnValue = false;
		}
		return false;
	}
};

// AJAX
var $a = {
	tempoXHR: 2500,
	bXHRSupport: (typeof XMLHttpRequest != "undefined"),
	bActiveXSupport: (window.ActiveXObject),
	aMSXML: ["Microsoft.XMLHTTP",
		"MSXML2.XMLHTTP", "MSXML2.XMLHTTP.3.0",
		"MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.5.0",
		"MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.7.0"],
	createXHR: function() {
		if($a.bXHRSupport)
			return new XMLHttpRequest;
		else if($a.bActiveXSupport) {
			var iI;
			iI = $a.aMSXML.length;
			do {
				try {
					return new ActiveXObject($a.aMSXML[--iI]);
				}
				catch(oError) { };
			}
			while(iI > 0);
			throw new Error("L'objet oXHR n'a pas été créé");
		}
	},
	getXHR: function(oReq) {
		var oXHR = $a.createXHR();
		$a.oReq = oReq;
		oXHR.open($a.oReq['method'], $a.oReq['url'], $a.oReq['sync'] && $a.oReq['sync'] == 'true' ? false : true);
		var oTimer = setTimeout(
			function() {
				if(oXHR)
					return oXHR.abort();
			},
			$a['tempoXHR']
		);
		oXHR.onreadystatechange = function() {
			if(oXHR.readyState == 4)
				if(oXHR.status && /200|304/.test(oXHR.status)) {
					clearTimeout(oTimer);
					if($a.oReq['callback']) ($a.oReq['callback'])(oXHR.responseText);
				}
		};
		oXHR.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
		if($a.oReq['method'] == 'post')
			oXHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		return $a.oReq['method'] == 'get' ? oXHR.send(null) : oXHR.send($a.oReq['param']);
	}
};

// CLASSE TEST
var Test = function() {}, Tp = Test.prototype = {
	initialize: function() {
		var oCont = $('cont');
		var oCtrlAlert = $(oCont, 'a')[0];
		var oCtrlMaj = $(oCont, 'a')[1];
		var oStatut = $(oCont, 'p')[1];
		$e.add(oCtrlAlert, 'click', Tp.alert(oStatut));
		$e.add(oCtrlMaj, 'click', Tp.chgContent(oCont));
	},
	alert: function(oEl) {
		return function(e) {
			alert(oEl.lastChild.nodeValue);
			return $e.stop(e);
		};
	},
	chgContent: function(oCont) {
		return function(e) {
			$a.getXHR({
				method: 'get',
				url: 'content.php',
				callback: function(oResponse) {
					oCont.innerHTML = oResponse;
					[#blue]return Tp.initialize();[/#]
				}
			});
			return $e.stop(e);
		};
	}
};

return $e.add(window, 'load', function() {
	return (new Test).initialize();
});

})();

		//--></script>
	</head>
	<body>

<div id="cont">
	<p><a href="#">texte du conteneur</a> | <a href="#">mise à jour du conteneur</a></p>
	<p>conteneur à mettre à jour</p>
</div>

	</body>
</html>

content.php
<?php

header('Content-Type: text/html; charset=utf-8');
session_start();

if(!isset($_SESSION['maj'])) $_SESSION['maj'] = 0;
$_SESSION['maj']++;
echo $_SESSION['maj'] % 2 == 0 ?
	'<p><a href="#">texte du conteneur</a> | <a href="#">mise à jour du conteneur</a></p><p>conteneur à mettre à jour</p>':
	'<p><a href="#">texte du conteneur</a> | <a href="#">réinitialisation du conteneur</a></p><p>conteneur mis à jour</p>';

?>
En somme, pour réévaluer le conteneur, je relance le script dans la fonction de callback une fois la mise à jour effectuée (ce qui est en bleu). Smiley smile
Merci beaucoup koala64.

Je n'ai pas encore eu le temps de regarder ça mais je m'y mets tout de suite...
J'ai mis en œuvre cette solution!

Je ne suis pas arrivé à la faire fonctionner mais je pense savoir d'où vient le problème, il me faudrait une confirmation.
Les scripts qui gèrent le tri de table et les infobulles sont ainsi :

window.addEvent('domready',function(){
     jQueryVarNoConflict(function() {
     jQueryVarNoConflict("table")
          .tablesorter({cssHeader: "sortHeader", cssAsc: "sortedASC", cssDesc: "sortedDESC"})
          .tablesorterPager({container: jQueryVarNoConflict("#pager"), size: 12});
     });
});
	
jQueryVarNoConflict(function(){
     jQueryVarNoConflict("a.clic").simpletooltip({click: true, effect: "slideDown", hideDelay: 0.4});
});


Lors du callback, le gestionnaire d'évenements doit être 'mis à jour', mais vu que ce type d'événement est géré par le Framework jQuery, cela ne pose t-il pas problème ??


EDIT : Je pense avoir compris le fonctionnement de la fonction Tp.initialize() : pour cet exemple, elle 'recharge' les événements pour le clic. Si j'ai bien compris, c'est donc à cet endroit qu'il faut mettre la définition des événements du tri de table (pour mon cas). Mais, et j'en reviens à ce que j'ai dis en début de message, ces événements étant gérés par le framework jQuery, comment est-il possible de les 'recharger' ?? En rappelant juste les fonctions (ci-dessus), ça ne marche évidement pas... arf!
Modifié par AdJiBouDi (20 Jun 2008 - 11:06)
Modérateur
Difficile de te répondre avec ce petit bout de code. Smiley murf

A priori, il faut relancer l'ensemble de la fonction que tu affectes au domready une fois la mise à jour effectuée.

Ainsi, tu resélectionnes ta table et les événements sont ajoutés aux nouveaux éléments réactifs de cette table via les méthodes tablesorter et tablesorterPager.
Je change d'orientation...

Exit le principe de reloader la page (comme lorsque l'on appuie sur F5). Je passe dans le code du plugin jQuery qui me permet de faire le tri de la table.
Vous l'aurez compris, c'est pas moi qui est développé ce plugin, et déjà un premier problème viens m'embêter... quel joie !

La classe de ce plugin se nomme 'tablesorter' et possède un constructeur.
FireFox exécute le constructeur lors de la construction de l'objet de cet classe (qd je l'appel donc, voir le code précédement), normal c'est le principe de la POO.
IE lui n'en fais rien ! Smiley eek Il ne passe jamais par le constructeur. Pourquoi ??? La machine ayant toujours raison, ou est mon erreur, je comprends plus là ?? Smiley bawling Est-ce le principe de fonctionnement de IE ??

Pour info, à partir du constructeur je crée un nouvel évènement de type click sur un lien (merci koala64). Lorsque je clique sur ce lien donc, j'exécute le code que je veux. Le souci c'est que IE ne passe pas par le constructeur (pourtant le plugin fonctionne), et donc ma définition de l'événement n'est pas prise en compte.

Voila mon code :
Constructeur
$reloadHand = $("a", "#reload_a");

$reloadHand.click(function(e) {
     //Récupération des données du formulaire & traitement
     //Création de l'élément XMLHttpRequest
     //Insertion en base de données
     //Ajout de la nouvelle ligne (au passage plus besoin de recharger la table complète)
     //Mise à jour des données de la classe
});

Modifié par AdJiBouDi (20 Jun 2008 - 16:24)
Bonjour tout le monde.

Finalement, j'ai réussi ce que je voulais faire (total temps passé : 43heures !!! Smiley fache , très fâché).. Je précise que je n'ai pas pu mettre en œuvre la solution recherchée en début de post.
J'explique ma "solution" : j'ai utilisé les diverses fonctions du plugin pour refaire tout le cheminement exécuté lors de l'initialisation de l'objet. Ce plugin est basé sur un cache (initialisé lors de la phase de construction de l'objet).

J'ai définis un évenement clic sur un bouton. Lors du clic sur ce bouton, une ligne est ajoutée au tableau HTML présent sur le premier slide, puis une fonction récupère la ligne html ajoutée et l'ajoute au cache du plugin (cache total puisque celui-ci est divisé car le tableau possède un affichage par page). Je réutilise ensuite les fonctions pour mettre en forme le cache sur le slide1.
Voilà, je pense pas que ça serve à grand chose (d'ôu les guillemts à solution), mais bon, sait-on jamais....

Sinon, personne n'a d'idées pour le problème lors de la phase d'initialisation (constructeur) entre IE et Firefox??
Merci à tous (enfin surtout koala64) !

EDIT : dois-je passer le sujet en résolu ??
Modifié par AdJiBouDi (23 Jun 2008 - 16:13)
Pour le problème du constructeur, il semblerait que ce soit une seule partie de mon code qui ne fonctionne pas, et plus précisément cette ligne :

var nb_occ = document.forms['formAjout'].elements['libelle_form'].value.length;


'document.all' ne fonctionne pas non plus, ni 'document.getElementById'...
Auriez-vous une idée pourquoi ??
Modifié par AdJiBouDi (23 Jun 2008 - 17:21)