11548 sujets

JavaScript, DOM et API Web HTML5

Bonjour ! Smiley smile

Je travaille actuellement à un projet d'interface web Full AJAX.
Lors du chargement initial du site, je "construit" le DOM de la page grâce à des successive via xmlHttpRequest.

Je charge par exemple le header via une première requête, puis la structure de la page, puis le menu, puis le bloc "contenu" centre, etc.

J'utilise pour cela une fonction unique nommé loadModule qui prend en paramètre l'adresse du module à charger, les paramètre avec les quels le charger, et la cible (l'id) où le charger dans la structure de la page XHTML.

Le premier chargement se fait sans problème, mais le problème que je rencontrer c'est que lorsque j'appelle une seconde fois la même fonction le script plante, car la première requête n'est pas terminée.

Voila ci dessous pour les sources qui peuvent être utiles pour comprend mon problème...

loadModule.js
var httpReqObjetRep = createHttpReq();
var showErrors = true;

	function handleRequestStateChangeRep(cible) {
		if (httpReqObjetRep.readyState == 4)   {
			if (httpReqObjetRep.status == 200)  {
				try{
					includeReponse(cible);
				}
				catch(e){
					displayError(e.toString());
				}
			}
			else{
				displayError(httpReqObjetRep.statusText);
			}
		}
	}
	function includeReponse(cible){
		var reponseScript = httpReqObjetRep.responseText;
		document.getElementById(cible).innerHTML=reponseScript;
	}
	function loadModule(module,param,cible){
		if (httpReqObjetRep){
			try
			{
				if (httpReqObjetRep.readyState == 4 || httpReqObjetRep.readyState == 0) {
					var cacheContent = cache.shift();
					httpReqObjetRep.open("POST", 'modules/'+module+'/'+module+'.ajax.php?'+param, true);
					httpReqObjetRep.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
					httpReqObjetRep.onreadystatechange = function() {handleRequestStateChangeRep(cible); }
					httpReqObjetRep.send(cacheContent);
				}
				else {
					alert('Erreur');
				}
			}
			catch (e){
				displayError(e.toString());
			}
		}
	}


et dans la page, le chargement successif :

<script>
	loadModule('window','keychild=logon','page');
	loadModule('window','1','window');
</script>


Le premier chargement fonctionne donc sans problème, mais le deuxième venant directement après génère l'erreur alert('Erreur!'); , je pense (mais peut être que je me trompe ?) parce que le readystate de la première readystate de la première n'est pas encore arrivé à l'état 4.

J'ai fais beaucoup de recherche mais je n'ai pas trouvé grand chose...

Je voudrais trouver une solution pour faire patienter le second script dans que l'objet readystate de la précédente requête n'est pas arrivé à 4.

Malheureusement JS n'est pas un langage qui aime patienter de ce que j'ai pu voir des résultat des essais que j'ai fait jusqu'ici ...

(Par ailleurs je sais que cette idée de site full ajax va en faire crier plus d'un sur ce cher site Strasbourgeois, mais je ne suis pas ici pour parler d'accessibilité Smiley langue )
(Et, non, je ne tiens absolument pas à utiliser un framework comme jQuery Smiley biggol )

Merci de votre aide Smiley confused
Modifié par nakwa (16 Jun 2009 - 15:12)
Salut,

Le problème que je vois est que tu utilises le même objet XHR pour toutes tes requêtes. Vu que tu n'as qu'un seul objet, tu n'as aussi qu'un readyState et il ne peut pas en même temps être à 3 (par exemple) et à 0 pour que tu puisses commencer une nouvelle requête. Bref, soit tu fais tes requêtes en mode synchrone (plus lent), soit il te faut créer un objet XHR pour chaque requête.
Modifié par marcv (16 Jun 2009 - 16:44)
Merci pour ta réponse marcv ;
Générer un objet différent parait effectivement une solution à mon problème.

Mais exécutant un même script plusieurs fois, j'ai du trouver une solution pour générer un objet xmlHttpRequest portant un nom différent à chaque fois.

Je ne sais pas si c'est vraiment correcte :

Une variable au début du code qui initialise un numéro d'objet XHR ..
var nobjxhrini = 0;


L'ajout du code en gras à la fonction
function loadModule(module,param,cible){
	[b]var nobjxhrini = nobjxhrini + 1;
	var xhr = 'var httpReqObjetRep'+nobjxhrini+'=createHttpReq();';
		if(window.execScript){
			window.execScript(xhr);
		} 
		else if(navigator.userAgent.indexOf("KHTML") != -1){ 
			var s = document.createElement("script");
			s.type = "text/javascript";
			s.innerHTML = xhr;
			document.getElementsByTagName("head")[0].appendChild(s);
		} 
		else { 
			window.eval(xhr);	
		}[/b]
		if (httpReqObjetRep){
			try
			{
				if (httpReqObjetRep.readyState == 4 || httpReqObjetRep.readyState == 0) {
					var cacheEntry = cache.shift();
					httpReqObjetRep.open("POST", 'modules/'+module+'/'+module+'.ajax.php?'+param, true);
					httpReqObjetRep.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
					httpReqObjetRep.onreadystatechange = function() {handleRequestStateChangeRep(cible); }
					httpReqObjetRep.send(cacheEntry);
				}
				else {
					alert('erreur');
				}
			}
			catch (e){
				displayError(e.toString());
			}
		}
	}


Smiley sweatdrop

Je ne suis pas sûr pour l'itération de nobjxhrini;
Mais comment faire pour appeler a chaque fois l'autre objet ?

Je veux dire dans :
([b]httpReqObjetRep[/b].readyState == 4 || httpReqObjetRep.readyState == 0)

par exemple ?
Modifié par nakwa (16 Jun 2009 - 21:06)
La seule solution que j'ai trouvée c'est de faire un eval() sur l'ensemble des fonctions si dessus dans une fonction mère qui fait varier à chaque fois qu'elle est appelée le nom des variables, des fonctions, et des objets XHR .... et bien que ce soit lourd, ça fonctionne bien Smiley smile

Bonne soirée
Dans ce cas, il faut que créer un classe, comme ça tu pourras faire autant d'appel ajax que tu veux sans qu'il y est de confusion.

Un fois que ta classe est faite tu fais seulement :
var loadHeader = new loadModule('header');
loadHeader.post('id_user=1');
loadHeader.includeReponse('header');

var loadContent = new loadModule('content');
loadContent.post('id_user=1&id_page=1');
loadContent.includeReponse('content');


A mon avis c'est que mieux qu'eval...
Modifié par matmat (17 Jun 2009 - 07:06)
matmat a écrit :
il faut créer un classe
+1

Dans 99,999999 % des cas, si tu en arrives à utiliser eval, c'est quelque chose cloche dans la logique de ton code.
Modifié par marcv (17 Jun 2009 - 11:13)
Merci beaucoup de votre aide ! Smiley ravi

Maintenant que vous le dite c'est vrai que ça parait bien plus cohérent x)
JS et moi ça ne fais pas encore 1 Smiley lol

Puis solliciter votre aide une fois de plus ?
Je ne connais pas grand chose aux classes en javascript, j'ai fais quelques recherche, mais ça ne veux pas fonctionner (rien ne se produit quand l'appelle la fonction...)


function loadModule(module,param,cible) {
	this.httpReqObjetRep=createHttpReq();
	this.handleRequestStateChangeRep = function (){
		if (this.httpReqObjetRep.readyState == 4){
			if (this.httpReqObjetRep.status == 200){
				try{
					this.includeReponse();
				}
				catch(e){
					displayError(e.toString());
				}
			}
			else{
				displayError(httpReqObjetRep.statusText);
			}
		}
	}
	this.includeReponse = function(){
		this.reponseScript = this.httpReqObjetRep.responseText;
		document.getElementById(cible).innerHTML=this.reponseScript;
	}
	this.load = function(){
		if (this.httpReqObjetRep){
			try{
				if(this.httpReqObjetRep.readyState == 4 || this.httpReqObjetRep.readyState == 0){
					this.cacheEntry = cache.shift();
					this.httpReqObjetRep.open("POST", 'modules/'+module+'/'+module+'.ajax.php?'+param, true);
					this.httpReqObjetRep.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
					this.httpReqObjetRep.onreadystatechange = this.handleRequestStateChangeRep;
					this.httpReqObjetRep.send(this.cacheEntry);
				}
				else{
					alert("Erreur avec readyState!");
				}
			}
			catch (e){
				displayError(e.toString());
			}
		}
	}
}


et j'appelle la fonction de cette manière:


		var page = new loadModule('window','x','page');
		page.load();



Je ne suis pas convaincu de l'emploi que je fais du "this"..
Effectivement, tu n'as plus accès au this après le "onreadystatechange", par contre tu as toujours accès aux variables donc tu peux faire :

function loadModule(module,param,cible) {  
   var httpReqObjetRep = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : false);
   this.load = function(){
      if (httpReqObjetRep){
         if(httpReqObjetRep.readyState == 4 || httpReqObjetRep.readyState == 0){
            //this.cacheEntry = cache.shift();
            httpReqObjetRep.open("POST", 'modules/'+module+'/'+module+'.ajax.php?'+param, true);
            httpReqObjetRep.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            httpReqObjetRep.onreadystatechange = function(){
               if (httpReqObjetRep.readyState == 4){
                  if (httpReqObjetRep.status == 200){
                     try{					                 
                        document.getElementById(cible).innerHTML=httpReqObjetRep.responseText;
                     }
                     catch(e){
                        displayError('readyState'+e.toString());
                     }
                  }
               }
            };
            httpReqObjetRep.send(param);
         }
      }
   }
}

Modifié par matmat (18 Jun 2009 - 02:02)
Merci beaucoup, ça fonctionne parfaitement! Smiley jap

A la limite tu aurais pu me laisser galérer encore un peu en ne me donnant qu'une piste ..
.. Smiley biggrin J'ironise qu'à moitié, mais quand je vois la tournure que prend l'ambiance d'autres forums informatiques actuellement ... ça fait plaisir!

Je reviendrai plus souvent sur Alsacréations Smiley loveu
Merci
Modifié par nakwa (18 Jun 2009 - 02:25)