11548 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

Le troisième carrousel sur cette page (sous le titre "C'est vous qui le dites !") présente une liste de couvertures de livres.

Le contenu de cette liste est chargé dynamiquement via Ajax à partir d'un script PHP (ce que permet le script jCarousel, comme dans l'exemple montré sur le site de jCarousel).

Comme je travaille actuellement sur la navigation au clavier de ma page, j'aurais besoin de faire un "bind" sur les liens de ce carrousel (c'est-à-dire les images de couverture), comme dans le code suivant :
$("#carousel-comments ul li a")
		.bind('keydown', 'left', function () { carousel.prev(); return false; });

Néanmoins, cela ne fonctionne pas actuellement. Je suppose que c'est précisément à cause du chargement dynamique des images (du coup les liens ne sont pas dans le DOM, c'est ça ???)

Existe-t-il une solution pour ce genre de cas ? Est-il possible d'agir en javaScript sur un élément chargé dynamiquement ?

Merci de votre aide !
Modifié par Fix (14 Mar 2012 - 09:21)
Pourquoi ? Mon "bind" fonctionne très bien sur d'autres éléments de la page. Je ne crois pas que ce soit le problème. Je pense que cela vient plutôt que les liens ne sont pas encore disponibles/créés dynamiquement au moment du traitement.

La solution serait plus, je pense, du côté d'un $("#carousel-comments ul li a").onLoad ou quelque chose comme ça, non ?
Faudrait voir à lire la doc avant de poster. Smiley cligne
a écrit :
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.
HS: Même sans utiliser la forme de .on avec un deuxième sélecteur, une bonne habitude est de quand même utiliser .on à la place de .bind, qui est amené à virer sur le long terme en plus d'avoir nom très très mal choisi.
C'est bien beau tout ça, mais ça ne résout pas mon problème... que j'ai moi-même résolu entre temps : en effet, comme je le pensais, le "bind" était simplement appelé trop tôt, c'est-à-dire avant l'ajout dynamique des liens...

Florian_R > je retiens néanmoins ton conseil, et j'aimerais l'appliquer... mais c'est un peu compliqué pour moi que ne suis qu'un novice : je peux simplement remplacer "bind" par "on" ? (Je précise que pour la gestion des événements au clavier, j'utilise le script jQuery hotkeys.)
Fix a écrit :
C'est bien beau tout ça, mais ça ne résout pas mon problème... que j'ai moi-même résolu entre temps : en effet, comme je le pensais, le "bind" était simplement appelé trop tôt, c'est-à-dire avant l'ajout dynamique des liens...
Parce que tu ne dois pas appliquer ton .on sur tes liens, mais sur un élément parent présent dans le DOM au moment ou tu l'appliques. Avec du code ce sera plus clair.

Supposons que tu as une div .container dans laquelle tu insères dynamiquement un lien .truc.
$(document).ready(function () {
	//Ne fonctionne pas, .truc n'existe pas
	$(".truc").on('click', function () {
		console.log('Je ne serais jamais appellé');
	});
	
	//Fonctionne, car .container est présent dans le DOM au moment du DOM ready
	$(".container").on('click', '.truc', function () {
		console.log('Crazy shit, ça marche!!');
	});
});
Et sinon, oui en théorie, si tu utilises jQuery > 1.7, tu peux remplacer tous tes .bind.
Modifié par Florian_R (06 Mar 2012 - 17:46)
Je comprends mieux Smiley cligne Néanmoins je ne vois pas comment je pourrais appliquer cela, car je dois agir sur certains liens en particulier pour régler la navigation au clavier.

Un exemple vaut mieux qu'un long discours :
	$("#carousel-comments li.jcarousel-item-" + carousel.last + " a")
		.bind('keydown', 'tab', function () { $("#rang3 a").first().focus(); return false; });

Autrement dit : si le focus est sur le dernier lien visible du carrousel, alors un appui sur la touche tab donnera le focus au premier lien rencontré après le carrousel.

À moins qu'il y ait une autre manière de procéder ?

D'autre part, j'utilise jQuery version 1.4.4, donc je reste avec mes "bind" ? Ou bien il y aurait un intérêt à faire évoluer tout ça ?
Tu dois pouvoir t'en sortir avec
$("#carousel-comments").on('keydown', 'li:last-child a', function () {
	//Ton code, sachant que $(this) -> l'objet jQuery faisant référence à ton lien
})
J'ai testé avec cette version du plugin hotkeys, ça semble fonctionner.

Si tu veux rester sur jQuery 1.4, tu peux utiliser .delegate à la place de .on (attention, l'ordre des arguments est différent), mais si tu n'as pas de raison particulière de rester sur cette version (code ou plugin utilisant des fonctions dépréciées), autant upgrader vu les améliorations en terme de perf des versions récentes.
Modifié par Florian_R (08 Mar 2012 - 11:24)
D'accord. Merci pour ces précieux conseils ! Je suis en train de tester tout cela.

Merci beaucoup pour tout le temps que tu m'as consacré !
Bon, je rouvre ce billet, car je n'y parviens pas : avec le code donné par Florian_R, je me trouve plus ou moins obligé de détecter deux fois l'événement "keydown", je ne parviens pas à faire autrement. Du coup, ça ne donne plus tout à fait le résultat escompté (ça marche mal : au lancement du carrousel, on est par exemple obligé d'appuyer deux fois sur la touche "droite" pour que le carrousel affiche les images suivantes, par exemple).

Voici mon code actuel :
$("#carousel-comments").delegate("li a", "keydown", function () {
	$(this)
		.bind('keydown', 'left', function () { carousel.prev(); return false; })
})


N'y a-t-il pas moyen de détecter la touche qui a été pressée, plutôt que de refaire un $(this).bind("keydown" etc. ?

C'est toujours visible ici (3ème carrousel, contenant les images de couvertures de livres).

Je précise que je souhaiterais continuer à utiliser le plugin hotkeys pour gérer les événements clavier...
Modifié par Fix (14 Mar 2012 - 09:23)
À bien y réfléchir, mon problème pourrait se résumer à ceci : je dispose du code suivant, qui fonctionne sur d'autres carrousels grâce aux plugins jCarousel et hotkeys, pour permettre la navigation au clavier :
$("#carousel-comments li a")
	.bind('keydown', 'left', function () { carousel.prev(); return false; })
	.bind('keydown', 'right', function () { carousel.next(); return false; })
	.bind('keydown', 'home', function () { carousel.scroll(1); return false; })
	.bind('keydown', 'end', function () { carousel.scroll(carousel.size()); return false; });
$("#carousel-comments li a")
	.bind('keydown', 'tab', function () { $(this).parent("li").nextAll("li").first().children("a").focus(); return false; });
$("#carousel-comments li.jcarousel-item-" + carousel.last + " a")
	.bind('keydown', 'tab', function () { $("#rang3 a").first().focus(); return false; });
$("#carousel-comments li a")
	.bind('keydown', 'tab', function () { if (focused != carousel.first) { $("#carousel-comments li.jcarousel-item-" + carousel.first + " a").focus(); focused = carousel.first; return false; } });
$("#carousel-comments li a")
	.focusin(function () { $("#carousel-comments li.jcarousel-item-" + carousel.first + " a").focus(); focused = carousel.first; return false; });


Néanmoins, comme ici mon carrousel charge dynamiquement les éléments à afficher, je dois utliser la fonction .delegate().

Ce que je ne parviens pas à faire, c'est convertir mon code en l'incluant dans la fonction suivante :
$("#carousel-comments").delegate("li a", "keydown", function () {
})


J'ai grand besoin d'aide... Un grand merci d'avance !
Modifié par Fix (15 Mar 2012 - 18:35)
Oups ! Je m'étais trompé dans le code indiqué. C'est corrigé. Cf. mon billet ci-dessus... si quelqu'un toutefois parvient à m'aider ? Un grand merci d'avance !
Il faut savoir que "live" est déprécié.
Il est plutôt conseillé d'utiliser "delegate" ou "on".
Pour ma part j'ai quelques problèmes parfois avec "on" sur des éléments chargé dynamiquement en revanche "delegate" fonctionne parfaitement et n'as pas tendance à être déprécié .Même si je le trouve un peu plus contraignant au niveau de la syntaxe.
nibbler a écrit :
Sauvé..
Merci super baloo !


un peu pressé, j'avais pas lu Ledzelkin..
Va pour delegate !
Merci