11548 sujets

JavaScript, DOM et API Web HTML5

Pages :
Bonjour,

Le titre du sujet n'est sans doute pas très clair et la question qui va suivre assez maladroitement posée...


Soit ce code :

<div id="conteneur_test">
<p><a href="#">Lien 1</a></p>
<p><a href="#">Lien 2</a></p>
<p><a href="#">Lien 3</a></p>
</div>

<div id="resultat" style="color:red;">Numéro d'ordre du lien cliqué : </div>

<script type="text/javascript">
     var referent = document.getElementById('conteneur_test') ;    
     var liens = referent.getElementsByTagName('a') ;

     for (var i = 0 ; i < liens.length ; ++i) {
     liens[ i ].onclick=function() {
     var no_ordre=?????;
    document.getElementById('resultat').innerHTML="Numéro d'ordre du lien cliqué : "+no_ordre;
     }
     }
     </script>


Je cherche à récupérer dans la variable "no_ordre" la valeur du i correspondant au lien qui vient d'avoir l'évènement onclick.

Si je clique le premier lien alors je dois obtenir no_ordre=0
Si je clique le 2ème alors no_ordre=1
Si le troisième alors no_ordre=2

Comment fait on pour obtenir ce résultat en javascript ?

PS :
. J'ai mis un code plutôt brutal, JS intrusif et utilisation de innerHTML, mais c'est pour alléger la quantité de code dans l'exemple.

. J'emploie l'expression "numéro d'ordre" faute de mieux...

Merci d'avance pour votre aide
Modifié par clb56 (25 Sep 2006 - 22:02)
Bonjour,

Une solution est d'affecter une propriété spéciale à chaque liens :
for (var i = 0 ; i < liens.length ; ++i) {
  liens[ i ].no_ordre = i;
  liens[ i ].onclick=function() {
  document.getElementById('resultat').innerHTML="Numéro d'ordre du lien cliqué : "+this.no_ordre;
  ...


On peut alors récupérer la propriété avec le mot clé "this"
Modifié par golog (21 Sep 2006 - 17:35)
Administrateur
clb56 a écrit :
Merci, merci encore
Bah dites-moi pas qu'un habitué comme toi n'as pas eu le réflexe du [Résolu] ?! Smiley biggol
Modérateur
youplaaaa... aussi ! Smiley clapclap

Merci golog parce que tu viens de me débloquer sur un truc que je végète depuis un moment aussi... Je n'avais pas compris l'utilité de ces propriétés qui apparaissaient de nul part... Smiley lol

Allez, hop... je file mon test... La même ! ou presque... Cherchez le this... Smiley ravi


<ul id="conteneur_test">
   <li><a href="#">Lien 1</a></li>
   <li><a href="#">Lien 2</a></li>
   <li><a href="#">Lien 3</a></li>
</ul>


var oO =
{
   'page': 'body',
   'ref': 'conteneur_test',
   'lien': 'a',
   'paragraphe': 'p',
   'text': "Numéro d'ordre du lien cliqué : ",

   _Connect: function(elm, evType, fn, useCapture)
   {
      if(elm.addEventListener) elm.addEventListener(evType, fn, useCapture);
      else if(elm.attachEvent) elm.attachEvent('on' + evType, fn);
      else elm['on' + evType] = fn;
   },

   _NumTab: function()
   {
      if(!document.getElementById || !document.getElementsByTagName) return false;

      var oRef = document.getElementById(oO['ref']);
      var aLiens = oRef.getElementsByTagName(oO['lien']);
		
      var iI, tTab = aLiens.length;
      for(iI = 0; iI < tTab; iI++)
      {
         aLiens[iI].num = iI;
         oO._Connect(aLiens[iI], 'click', function(e) { oO._ScribeNum(oO['paragraphe'], oO._GetTarget(e).num) }, false);
      }
      return true;
   },

   _ScribeNum: function(cont, num)
   {
      if(!document.getElementsByTagName ||
         !document.createElement ||
         !document.createTextNode) return false;

         var oBody = document.getElementsByTagName(oO['page'])[0];
         var oElem = document.createElement(cont);
         var oNum = document.createTextNode(oO['text'] + num);

         oElem.appendChild(oNum);
         return oBody.appendChild(oElem);
   },

   _GetTarget: function(e)
   {
      var target = window.event ? window.event.srcElement : e ? e.target : null;
      if(!target) return false;
      while(target.nodeType != 1 && target.nodeName.toLowerCase() != oO['page']) target = target.parentNode;
      return target;
   }
};
oO._Connect(window, 'load', oO._NumTab, false);
Ah oui, j'aurais dû préciser que "this" n'est réellement utilisable qu'avec le modèle d'événements "traditionnel", c'est-à-dire :
object.event

Avec les modèles plus avancés, c'est normalement utilisable aussi, mais avec le "bubble", on est des fois pas très sûrs de ce que l'on récupère (et puis Safari a parfois des problèmes sur les liens et renvoie l'enfant du lien : le noeud texte ou autre). Et dans le modèle avancé d'IE, this fait référence à l'objet "window"... bref partiquement inutilisable.

Pour plus d'infos sur ce sujet, voir les très bons articles (anglais) sur Quirksmode :
http://www.quirksmode.org/js/events_tradmod.html
http://www.quirksmode.org/js/events_advanced.html
http://www.quirksmode.org/js/this.html

Un bouquin est pas mal aussi là-dessus ainsi que sur l'utilisation des propriétés pour les "passer" aux événements :
http://www.beginningjavascript.com/
Modérateur
oui, d'ailleurs dans ce bouquin est justement expliqué comment régler le problème de Safari...

Il suffit d'ajouter, pour le code que je viens de donner :

aLiens[iI].onclick = function() { return false; };
dans la boucle for.

a écrit :
Et dans le modèle avancé d'IE, this fait référence à l'objet "window"... bref partiquement inutilisable.
d'où l'utilité de la méthode _GetTarget qui vient, elle aussi, de ce bouquin d'ailleurs...

Bien que ça soit plus difficile à mettre en place, je n'ai pas encore trouvé de cas qui posait réellement problème pour cette manière de faire. A voir... je teste...

Tiens, sinon, faudra qu'on m'explique aussi pourquoi, dans ce bouquin ou dans des bibliothèques telles que Prototype, ils laissent des fonctions qui provoquent des avertissements... D'un côté, ils font un code super propre et de l'autre, ils laissent passer ce genre de chose... Ce n'est pas rédhibitoire mais bon, j'ai parfois du mal à comprendre... Smiley sweatdrop Du coup, ben je me permets d'y retoucher en croisant les doigts pour ne pas faire de bêtises... Smiley murf (ex. : méthode _Connect qui s'appelle d'origine _addEvent)

Et pour la gestion des événements, c'est d'excellents articles sur le sujet que tu as donné là... Smiley cligne
koala64 a écrit :
Tiens, sinon, faudra qu'on m'explique aussi pourquoi, dans ce bouquin ou dans des bibliothèques telles que Prototype, ils laissent des fonctions qui provoquent des avertissements... D'un côté, ils font un code super propre et de l'autre, ils laissent passer ce genre de chose... Ce n'est pas rédhibitoire mais bon, j'ai parfois du mal à comprendre... Smiley sweatdrop Du coup, ben je me permets d'y retoucher en croisant les doigts pour ne pas faire de bêtises... Smiley murf (ex. : méthode _Connect qui s'appelle d'origine _addEvent)

Je ne sais pas... Je n'ai jamais trop regardé du côté de Prototype... trop lourd, trop de fonctionnalités pour moi ! Dans le bouquin par contre, je me rappelle qu'il y a tout de même pas mal de boulettes (un peu dommage, ça vient ternir quelque chose de très bonne facture Smiley ohwell )... m'enfin !
Modérateur
golog a écrit :
Je n'ai jamais trop regardé du côté de Prototype... trop lourd, trop de fonctionnalités pour moi !
On est d'accord. Smiley cligne Ce que je reproche essentiellement à cette bibliothèque, c'est le manque de recul qu'a eu l'auteur au moment de la créer. C'est bien trop lourd, difficilement modulable et il y a quelques erreurs... C'est aussi pour çà que je ne m'en sers pas. En revanche, j'en regarde la syntaxe histoire de parfaire mes connaissances. Je pense que c'est une bonne chose. En fait, je suis plutôt partisan que chacun fasse sa propre bibliothèque, qu'il améliore au fur et à mesure de son apprentissage.

Celà dit, à titre de contre-exemple, il y en a une qui retient mon attention, c'est celle de JQuery parce qu'elle ne fait que 15ko (pour la version compressée), qu'elle ne contient que 4 avertissements facilement corrigeables et surtout parce qu'elle permet de faire des méthodes plus courtes et plus puissantes. Pour un gros site, je pense que c'est un bon investissement (moins pour un petit) mais il est vrai que rien ne vaut une bibliothèque personnelle bien pensée, ne serait-ce que pour la maintenance.

a écrit :
Dans le bouquin par contre, je me rappelle qu'il y a tout de même pas mal de boulettes (un peu dommage, ça vient ternir quelque chose de très bonne facture Smiley ohwell )... m'enfin !
Personne n'est parfait ! Smiley ravi Malgré ces quelques bourdes, il est clair que ça n'en reste pas moins un très bon bouquin mais pas vraiment dédié au débutant... Il faut un oeil objectif pour en tirer le meilleur parti et puis comme d'hab', ne pas hésiter à multiplier les sources de renseignements. Smiley smile
koala64 a écrit :
En fait, je suis plutôt partisan que chacun fasse sa propre bibliothèque, qu'il améliore au fur et à mesure de son apprentissage.

On est du même avis ! J'ai débuté 2 bibliothèques que j'essaye d'améliorer petit à petit. C'est très formateur... effectivement aisé pour la maintenance, et quand il y a un bug, on sait généralement très vite d'où ça vient, contrairement aux grosses biblios.

a écrit :
Malgré ces quelques bourdes, il est clair que ça n'en reste pas moins un très bon bouquin mais pas vraiment dédié au débutant...

Effectivement ! Pour débuter, je crois que DOM Scripting de Jeremy Keith est parfait. Après cette saine lecture et quelques dizaines d'heures passées dans le code, le livre de Christian Heilmann est une bonne suite, ainsi que celui de James Edwards et Cameron Adams, The Javascript Anthlogy... Reste plus qu'à attendre le livre de Peter-Paul Koch PPK on JavaScript Smiley murf
Raphael a écrit :
Bah dites-moi pas qu'un habitué comme toi n'as pas eu le réflexe du [Résolu] ?! Smiley biggol


Hi hi hi...

J'ai pris connaissance du message de goglog à 18h31

Fait le test entre 18h31 et 18h33

Envoyer mes remerciements émerveillés, que je renouvellent, à 18:33:46

Fermer l'ordi à 18h34

Pris ma voiture à 18:34:05 go Lorient from Concarneau, à la bourre mais sans excès de vitesse.

J'en reviens à l'instant.
Smiley cligne
Modifié par clb56 (22 Sep 2006 - 21:15)
Bonjour,

Concernant les galeries photos en javascript partant de listes de vignette j'avais dans ce post :
http://forum.alsacreations.com/topic-23-17556-1-modif-de-tuto-Galerie-photos-javascript.html#p132726

émis l'idée que :
a écrit :

En fait pour tout dire je pense que le commentaire de la photo devrait être présent en dur hors js. Etre récupéré et utilisé dans le dt si js actif sans passer par le title du lien, parce que le title ne devrait pas servir à ça.


tout en en restant à la conclusion :
a écrit :

Mais je ne sais pas comment faire...


C'est dire que je suis content de la réponse qu'a fourni golog car c'est l'élément qui me manquait pour finaliser ce que j'avais en tête.

Partant du script d'Olivier celà donne ceci :

Soit une liste de liens vignettes pour lesquelles on associe chaque fois un commentaire en dur dans un <p>

<li>
<a href=""><img /></a>
<p>Commentaire de l'image</p>
</li>


On créé un tableau_commentaire=newArray()

Ayant par ailleurs récupérer dans un tableau tous les liens de la listes par

var photos = document.getElementById('galerie_mini') ;
var liens = photos.getElementsByTagName('a') ;

on remplit le tableau_commentaire avec chaque <p> associé à chaque itération des liens puis on supprime chacun de ces <p>

for (var i = 0 ; i < liens.length ; ++i)
                 {
tableau_commentaire[ i ]=liens[ i ].parentNode.lastChild.lastChild.nodeValue;
var para=liens[ i ].parentNode.lastChild;
liens[ i ].parentNode.removeChild(para);
}


Au clique sur chaque vignette on remplit le <dt> de la liste de défintion avec l'itération de tableau_commentaire de même niveau d'ordre que le lien cliqué.

liens[ i ].no_ordre = i;/* golog Président !!!!!!!!!!!!!!!!!!!! */
                 
liens[ i] .onclick = function()
                       {
var commentaire_big_photo=tableau_commentaire[this.no_ordre];
titre_photo.firstChild.nodeValue = commentaire_big_photo;

                       }


Ainsi les commentaires des photos sont complètement accessibles et ce sans passer par le title des liens où, outre le fait que cela limitait justement l'accessibilité (navigation clavier), ils n'avaient je pense pas grand chose à faire.

Le résultat de tout ça est ici :
http://clb56.freezee.org/test_upload/galerie_resultat_quat.php

Script JS complet :
http://clb56.freezee.org/test_upload/galerie_ter.js
Bonsoir,

Content d'avoir pu t'aider Smiley smile
Bon j'ai quelques commentaires maintenant !

D'une façon générale, quand on récupère un élément par ID (qui n'a pas été créé en JS), il vaut toujours mieux tester son existence avant de l'utiliser. Si le script fait partie d'une collection plus grande ou, par commodité, est un include serveur sur toutes les pages du site (même les pages où il ne devrait pas s'exécuter), il n'y aura par conséquent pas de souci. Ceci est donc plus prudent :
var referent = document.getElementById('global_galerie');
if(!referent) {return;}


De même, lorque l'on récupère une collection d'éléments, il peut être bon de tester qu'elle contient effectivement des éléments, par exemple :
var liens = photos.getElementsByTagName('a');
if(liens.length < 1) {return;}


Par ailleurs, tu réalises dans la boucle plusieurs choses qui pourraient être faites en dehors, et en une seule déclaration. Il serait en effet plus simple pour le "stylage dynamique" de la galerie d'appliquer une classe sur le <ul>, et de se servir ainsi de la cascade pour styler en même temps tout ce qui en dépend. Il est généralement préférable de ne jamais toucher au style dans le javascript, sauf lorsque l'on est vraiment obligé (anim ou drag n drop). Tu ajoutes donc cela avant la boucle :
// stylage dynamique de la galerie (galerie_mini)
photos.className = 'dynGalerie';

et tu peux virer ces lignes :
liens[ i ].parentNode.setAttribute("style","float:left; margin-right:3px;");
liens[ i ].parentNode.parentNode.setAttribute("style","list-style-type:none; margin-left:0; padding-left:0;");
if (document.all) {
  liens[ i ].parentNode.style.setAttribute("cssText","float:left; margin-right:3px; margin-top:3px;");
  liens[ i ].parentNode.parentNode.style.setAttribute("cssText","list-style-type:none; margin-left:0; padding-left:0;");
}

et dans la CSS (+ CSS spécifique IE si besoin) :
#galerie_mini.dynGalerie {
  list-style-type:none;
  margin-left:0;
  padding-left:0;
}

#galerie_mini.dynGalerie li {
  float:left;
  margin-right:3px;
}

Tu économises ainsi des ressources, évites les redondances, et tu gagnes finalement en temps d'exécution...
En passant, attention au test "document.all" qui est supporté par Opera !

Voilà, je pense avoir fait le tour...
Modifié par golog (23 Sep 2006 - 21:21)
Resalut,

En fait, d'autres choses peuvent être simplifiées :
- encore quelques déclarations qui ne devraient pas être dans la boucle
- quelques recups d'éléments inutiles (sur les éléments créés, dont tu as déjà une référence)

Voici un script simplifié ci-dessous (désolé pour la longueur, impossible de le mettre chez mon hébergeur... qui a des ratés, comme souvent chez OVH ces derniers temps Smiley bawling ) :
function displayPics() {
	if( !document.getElementById || !document.getElementsByTagName || !document.createElement || !document.createTextNode ) {return;}

	// recup elements + tests existence
	var referent = document.getElementById('global_galerie');
	var photos = document.getElementById('galerie_mini');
	if(!referent || !photos) {return;}
	var liens = photos.getElementsByTagName('a');
	if(liens.length < 1) {return;}
	
	// stylage galerie dynamique
	photos.className = 'dynGalerie';

	// creation galerie
	var new_dl = document.createElement('dl');
	new_dl.setAttribute('id','photo');
	var new_dt = document.createElement('dt');
	var content_dt = document.createTextNode(' ');
	new_dt.appendChild(content_dt);
	new_dl.appendChild(new_dt);
	var new_dd = document.createElement('dd');
	new_dl.appendChild(new_dd);
	var new_img = document.createElement('img');
	new_img.setAttribute('id','big_pict');
	new_dd.appendChild(new_img);
	referent.appendChild(new_dl);	

	var tableau_commentaire = new Array();
	
	// assigne evenements + recup titres + suppr para
	for (var i = 0 ; i < liens.length; ++i) {
		liens[ i ].title = liens[ i ].title+' et son commentaire';
		tableau_commentaire[ i ] = liens[ i ].parentNode.lastChild.lastChild.nodeValue;
		var para = liens[ i ].parentNode.lastChild;
		liens[ i ].parentNode.removeChild(para);

		liens[ i ].no_ordre = i;

		liens[ i ].onclick = function() {
			new_img.src = this.href;
			new_img.alt = this.title;
			content_dt.nodeValue = tableau_commentaire[this.no_ordre];
			return false;
		}
	}
	
	// contenu de depart
	content_dt.nodeValue = tableau_commentaire[0];
	new_img.src = liens[0].href;
	
	return true;
}

Voilà...

Edit : en fait, voilà un exemple : http://austral.chez-alice.fr/clb56/galerie.htm
Désolé, les images sont un peu lourdes (pas terrible pour ce genre de script, mais je n'avais que ça sous la main). D'ailleurs, en parlant de poids d'images, il peut être intéressant d'effectuer un preload des images dans la boucle :
var preload_img = new Image();
preload_img.src = liens[ i ].href;

Ceci dit, il vaut mieux faire cela pour des images ayant un poids modéré, sinon cela peut rapidement bloquer la page...
Modifié par golog (23 Sep 2006 - 22:20)
Salut,

merci beaucoup pour tes commentaires et ta proposition d'optimisation du script.

Effectivement l'idée de sortir le stylage du script lui même est une très bonne chose que les fainéants dans mon genre ont tendance à remettre au lendemain...

... "Sine die" ... Smiley rolleyes

Heu...
golog a écrit :

En passant, attention au test "document.all" qui est supporté par Opera !


Smiley confused Smiley confused Smiley confused
Ah ! ... CT pour ça ! Smiley biggol Smiley lol

Pour les tests d'existences, koala64 m'avait déjà alerté (en fait surtout sur le support des méthodes). De fait il y en a bien un, mais que j'ai oublié de mettre dans mon exemple. Comme tu le présupposes bien il est effectivement indispensable car il y a de l'include php dans l'air pour mon affaire.

Le test que j'utilise est

if (!document.getElementById('global_galerie') {return false;}


Dans mon contexte si #global_galerie existe alors tout le reste existe.

Sinon une petite question : return; et return false; c'est la même chose ?

Vala, vala il y a surement plein de chose à améliorer mais ce qu'il y a de pratique dans ce forum c'est que quand tu arrives à trouver la bonne formulation de la question alors tu es sur d'avoir la bonne réponse.

Donc pour le redire ...
Merci ! Smiley smile

PS :

Gnagnagna !!! ...
...
... J'ai voulu faire la nique à Raphaël en mettant :
a écrit :

[Résolu et amélioré] Récupérer le numero d'ordre d'un lien[ i ].onclick


Et du coup j'ai perdu le "k" de mon onclick dans le titre du sujet.

Résultat je passe pour une bille en javascript...

Si j'étais un ptit génie en javascript ça ne me ferait rien, mais il se trouve que je suis réellement une bille en javascript Smiley bawling

Ce monde est trop cruel...
Modifié par clb56 (25 Sep 2006 - 22:12)
clb56 a écrit :
Sinon une petite question : return; et return false; c'est la même chose ?

Non : en mettant un simple "return;", la fonction en quittant ne retournera... rien ! Ou plutôt "undefined". C'est plus rapide à écrire, mais comme tous les raccourcis, il faut s'en méfier. Evidemment à ne pas utiliser lorsqu'une action dépend du résultat de l'exécution de la fonction, bref si la valeur retournée au code appelant est importante. Dans le cas de fonctions se suffisant à elles-mêmes (opérant en solo), ce n'est généralement pas un problème...
Modérateur
a écrit :
Si j'étais un ptit génie en javascript ça ne me ferait rien, mais il se trouve que je suis réellement une bille en javascript Smiley bawling

arf... mais non mais non... y'a pire ! Smiley capello

Afin de compléter la réponse de golog : pour t'améliorer, ( pub Smiley langue ), j'ai justement fait ça :
http://koalnet.com/tutoriels/bonnes-pratiques-js/

alors bon, plus d'excuses hein ! Smiley cligne

Sinon, pour les tests d'IE et Opera, tu peux faire ceci :

var sUserAgent = navigator.userAgent,
     isOpera = sUserAgent.indexOf('Opera') > - 1,
     isIE = sUserAgent.indexOf('compatible') > -1 && sUserAgent.indexOf('MSIE') > -1 && !isOpera;

if(isIE) { ... }
if(isOpera) { ... }


Voilà, voilà... Smiley biggrin
koala64 a écrit :
pour t'améliorer, ( pub Smiley langue ), j'ai justement fait ça :
http://koalnet.com/tutoriels/bonnes-pratiques-js/


Je n'avais pas vu que tu proposais quelque chose d'abouti en ligne.

1. je vais lire

2. la bêbête elle me fait peur Smiley bawling

3. ça va beaucoup m'intéresser de confronter ma propre conception de "bonnes pratiques" du javascript, qui est très extérieure à la maitrise du langage lui même, et la tienne qui sollicite justement cette maitrise.
Modifié par clb56 (25 Sep 2006 - 22:41)
Pages :