et en passant par le onsubmit du formulaire ?
et en passant par le onsubmit du formulaire ?
Ma page Developpez - Mon Blog Developpez
Président du CCMPTP (Comité Contre le Mot "Problème" dans les Titres de Posts)
Deux règles du succès: 1) Ne communiquez jamais à quelqu'un tout votre savoir...
Votre post est résolu ? Alors n'oubliez pas le Tag![]()
Venez sur le Chat de Développez !
Je viens de voir votre réponse. J'essaie de faire du javascript non-intrusif, donc aucun évènement en tant qu'attribut de balise.
Tu n'es pas obligé de mettre le onsubmit sur un attribut, tu peux le mettre directement dans ton script js :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 document.getElementById('mon_form').onsubmit = function(){ // Ta fonction }
Pas de question technique par MP !
Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
Mes formations video2brain : La formation complète sur JavaScript • JavaScript et le DOM par la pratique • PHP 5 et MySQL : les fondamentaux
Mon livre sur jQuery
Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum
Salut, je vais essayer de te consoler :-)
Ton script d'ajout d'évènement gère la possibilité de passer un élément DOM ou
un tableau d'éléments DOM pour y attacher des évènements.
C'est très louable comme fonctionnalité, mais dans ce code il y a un bug vicieux
je m'explique.
La détection du cas Element DOM simple, ou tableau d'éléments DOM est faite
par ce test: elm.length === undefined
Ceci ne permet pas de détecter fiablement si c'est un tableau qui est passé dans elm
ou si l'élément passé a par hasard une propriété length.
Il faudrait un test du genre: elm.constructor == Array
Ce qui s'est produit à mon avis durant tes tests c'est que tu as du essayer ceci:
Utils.Evenement.ajouter(document.getElementById("f1"), "submit", ...
dans ce cas, elm est de type HTMLFormElement, et si tu regarde l'interface
de l'élément HTML Form du moteur Gecko ici tu vera que form.length
représente le nombre d'élément du formulaire (tout comme form.elements.length
et aussi que form[i] est équivalent à form.elements[i]. Un raccourci d'écriture qui
m'a surpris je l'avoue :-)
Donc ton script va attacher l'évenement onsubmit à tous les éléments du formulaire
et non au formulaire lui-même.
Et bien je pense que tu m'as donné la réponse! Je teste donc l'existence de elm.length et de elm.elements. Ca à l'air de fonctionner, je me suis peut-être emporté sur la condition, alors si vous vous sentez de vous amuser avec...Je mettrai éventuellement résolu dans quelques temps.
Code xhtml : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="fr"> <head> <title>empêcher le rechargement de la page à la soumission d'un formulaire</title> <meta http-equiv="Content-type" content="text/html; charset=UTF-8" /> <style type="text/css"> </style> </head> <body> <form id="f1" action="" method="post"> <input id="i1" type="text" /> <button id="v" type="submit" value="v">valider</button> </form> <script type="text/javascript"> var Utils = { Evenement: { ajouter: function(elm, evt, fn) { if (document.addEventListener) { if (!elm.length || elm.elements) { elm.addEventListener(evt, function(e) { if (!fn(e)) {e.preventDefault();} }, false); } else { for (var i = 0, imax = elm.length; i < imax; i++) { elm[i].addEventListener(evt, function(e) { if (!fn(e)) e.preventDefault(); }, false); } } } else if (document.attachEvent) { if (!elm.length || elm.elements) { var r = elm.attachEvent("on" + evt, fn); return r; } else { for (var i = 0, imax = elm.length; i < imax; i++) { var r = elm[i].attachEvent("on" + evt, fn); return r; } } } } } } Utils.Evenement.ajouter(document.getElementById("f1"), "submit", function(e) { return false; }); </script> </body> </html>
Je reviens sur ton test pour déterminer si elm est
un élément unique ou une liste d'éléments.
J'avais écrit plus haut:
Il faudrait un test du genre: elm.constructor == Array
Mais document.getElementsByTagName par exemple ne retourne
pas un vrai Array, mais un des ces ArrayLike qu'on trouve partout
en javascript.
Voici donc une fonction pour ton test qui me semble adéquate:
Je reviens avec ça parce que je pense qu'il subsiste un risque dans ton
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 function isArrayLike(o) { return o.length && o[o.length - 1] !== undefined && !o.nodeType; }
test, je m'explique:
Les navigateurs (presque tous maintenant) permettent
d'étendre le DOM et d'ajouter des méthodes et propriétés
aux éléments.
Il existe donc le risque qu'un objet n'aie pas de length
mais aie une propriétés elements (je ne sais pas si il
en existe un comme ça dans le DOM actuel, mais on
peut en étendre un, ou une librairie pourrait le faire)
Je trouve l'idée du nodeType plutôt bonne. Par contre, je ne comprends pas ce test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part o[o.length - 1]
Si il s'agit d'un ArrayLike alors il est supposé contenir des éléments (pas
forcemment DOM, juste des éléments de tableau)
o.length - 1 représente le dernier élément (on aurait pu en prendre un
autre arbitrairement)
o[o.length - 1] est donc censé représenter le dernier élément du tableau
ce test sert a s'assurer qu'il s'agit d'un ArrayLike en essayant de consulter
un élément du tableau
C'est pour éviter de confondre avec un élément DOM qui aie été étendu
d'une propriété length qui représenterai autre chose.
le test est plutôt :
on vérifit que le dernier élément du tableau n'est pas a undefined ( donc que l'élément existe
Code : Sélectionner tout - Visualiser dans une fenêtre à part o[o.length - 1] !== undefined)
Au final, ne serait-il pas plus simple et plus propre de faire un simple?qui teste si c'est un document ou un élément HTML.
Code : Sélectionner tout - Visualiser dans une fenêtre à part if (elm.nodeType===1 || elm.nodeType===9) {
Cela me semble en effet une approche intéressante, mais je vois
pas quel évènement tu pourrais mettre sur un document node ?
Sinon je viens de tester window.nodeType est ça donne undefined :-(
Ce qui va poser problème pour mapper window.onload par exemple
Je pense plus logique tout de même de tester si tu passe un ArrayLike
puisque dans ce cas on fait une itération.
Mais bon, le plus important c'est d'éviter le bug à l'origine de cette discussion :-)
Ca permet la délégation d'évènement. Plutôt que d'attacher un évènement "click" sur 30 éléments, on attache l'évènement au document et c'est ensuite qu'on détecte quel élément a été cliqué :En ce qui concerne les évènements je pense qu'on peut se contenter de coller le code en fin de page.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Utils.Evenement.ajouter(document.getElementsByTagName("input"), "click", function(e) { var elm = e.target || event.srcElement; //si c'est un élément précis on fait bla... });
J'y ai pensé juste après avoir posté...
Exact, je ne développe pas un framework. De plus, pour éviter le genre de problème que tu as soulevé j'utilise du bon français pour étendre les objets. Je suis rarement en conflit. D'un autre coté, ça fait plaisir de savoir que quelque chose peut fonctionner de façon universelle.
Une discussion qui revient de loin! Je profite de la lecture de certains messages pour donner une dernière version du code et classer cette discussion comme résolue. Un bug tout bête existait encore sous IE (un return dans une boucle!).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 <!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" lang="fr"> <head> <title>attacher/détacher un évènement</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style type="text/css"> * {margin:0;padding:0;color:#333;} body {padding:80px; background:#000;} form {margin:0 0 20px 0;padding:10px;width:260px;background:#333;} </style> </head> <body> <form id="f" method="post" action="perdu.html"> <p><input id="c1" type="checkbox" name="c" value="1" /></p> <p><input id="c2" type="checkbox" name="c" value="2" /></p> <p><input id="c3" type="checkbox" name="c" value="3" /></p> <p><input id="s" type="submit" name="s" value="essayons" /></p> </form> <button id="a" name="a" value="a">attacher l'évènement</button> <button id="d" name="d" value="d">détacher l'évènement</button> <script type="text/javascript"> <!-- /***** version courte *****/ var FC = { Evenement: { evenements: [], ajouter: function(elm, evt, fn) { var fni = function(e) { // prévient le comportement par défaut if (fn(e)===false) { // false explicitement car peut être undefined en cas de délégation d'évènement if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } } }; if (document.addEventListener) { elm.addEventListener(evt, fni, false); } else if (document.attachEvent) { elm.attachEvent("on" + evt, fni); } FC.Evenement.evenements.push([elm, evt, fni]); }, supprimer: function(elm, evt, fn) { var evts = FC.Evenement.evenements; for (var i=evts.length-1; i>=0; i--) { if (evts[i][0]===elm && evts[i][1]===evt) { if (document.removeEventListener) { elm.removeEventListener(evts[i][1], evts[i][2], false); } else if (document.detachEvent) { elm.detachEvent("on" + evts[i][1], evts[i][2]); } FC.Evenement.evenements.splice(i,1); } } } } } var elms = document.getElementById("f").elements; var fn = function(e) { var elm = e.target || event.srcElement; alert("action suite à un évènement en cours."); return false; }; for (var i=0,imax=elms.length; i<imax; i++) { FC.Evenement.ajouter(elms[i], "click", function(e) { var elm = e.target || event.srcElement; if (elm.id==="a") { FC.Evenement.ajouter(document, "click", fn); } if (elm.id==="d") { FC.Evenement.supprimer(document, "click", fn); } }); } FC.Evenement.ajouter(document.getElementById("a"), "click", function(e) { for (var i=0,imax=elms.length; i<imax; i++) { FC.Evenement.ajouter(elms[i], "click", fn); } }); FC.Evenement.ajouter(document.getElementById("d"), "click", function(e) { for (var i=0,imax=elms.length; i<imax; i++) { FC.Evenement.supprimer(elms[i], "click", fn); } }); /***** version courte *****/ /***** version longue ***** var FC = { Evenement: { evenements: [], ajouter: function(elm, evt, fn) { var fni = function(e) { // prévient le comportement par défaut if (fn(e)===false) { // false explicitement car peut être undefined en cas de délégation d'évènement if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } } }; if (document.addEventListener) { if (elm.nodeType===1 || elm.nodeType===9) { elm.addEventListener(evt, fni, false); } else { for (var i=0,imax=elm.length; i<imax; i++) { elm[i].addEventListener(evt, fni, false); } } } else if (document.attachEvent) { if (elm.nodeType===1 || elm.nodeType===9) { elm.attachEvent("on" + evt, fni); } else { for (var i=0,imax=elm.length; i<imax; i++) { elm[i].attachEvent("on" + evt, fni); } } } FC.Evenement.evenements.push([elm, evt, fni]); }, supprimer: function(elm, evt, fn) { var evts = FC.Evenement.evenements; var estElm = true; for (var i=evts.length-1; i>=0; i--) { if (elm.nodeType===1 || elm.nodeType===9) { estElm = evts[i][0]===elm; } else { for (var j=0,jmax=elm.length;j<jmax;j++) { if (evts[i][0][j]!==elm[j]) { estElm = false; break; } } } if (estElm && evts[i][1]===evt) { if (document.removeEventListener) { if (elm.nodeType===1 || elm.nodeType===9) { elm.removeEventListener(evts[i][1], evts[i][2], false); } else { for (var j=0, jmax=elm.length; j<jmax; j++) { elm[j].removeEventListener(evts[i][1], evts[i][2], false); } } } else if (document.detachEvent) { if (elm.nodeType===1 || elm.nodeType===9) { elm.detachEvent("on" + evts[i][1], evts[i][2]); } else { for (var j=0, jmax=elm.length; j<jmax; j++) { elm[j].detachEvent("on" + evts[i][1], evts[i][2]); } } } FC.Evenement.evenements.splice(i,1); } } } } }; FC.Evenement.ajouter(document.getElementsByTagName("button"), "click", function(e) { var elm = e.target || event.srcElement; var inputs = document.getElementsByTagName("input"); var input = document.getElementById("c3"); var fn = function(e) { var elm = e.target || event.srcElement; alert("action suite à un évènement en cours."); return false; }; if (elm.id==="a") { FC.Evenement.ajouter(inputs, "click", fn); } if (elm.id==="d") { FC.Evenement.supprimer(inputs, "click", fn); } }); ***** version longue *****/ //--> </script> </body> </html>
Partager