Skip to content

Commit f5fffd3

Browse files
committed
Merge remote-tracking branch 'feugy/master'
2 parents 8973b54 + 850e96c commit f5fffd3

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
layout: post
3+
title: Les subtilité des formulaire de login en JS
4+
author: feugy
5+
tags: [javascript, login, formulaire, chrome, firefox, jQuery]
6+
published: false
7+
---
8+
9+
Quoi de plus simple qu'un formulaire de login ?
10+
En HTML, certes, mais lorsque qu'on parle d'application riche en javascript, c'est une autre histoire.
11+
12+
Si vous ne comprenez pas pourquoi le navigateur ne retient pas vos logins, ne propose pas le mot de passe associé, ou ne réagit pas à la touche entrée, lisez la suite !
13+
14+
Cet article est le résultat de **l'étude empirique du comportement des navigateurs**.
15+
Il est donc sujet à caution: tout dépends de votre navigateur, et de sa version.
16+
J'espère simplement vous aider à comprendre et éviter les principaux chausse-trappes, sans avoir recours à l'installation d'un plugin :)
17+
18+
19+
## Mais ce n'est qu'un formulaire !
20+
21+
Hélas non... Les formulaire de login (un champs <tt>text</tt> + un champ <tt>password</tt>) sont détecté par le navigateur, qui va traiter différemment des autres champs textuels.
22+
23+
C'est là le premier problème :
24+
>**Le formulaire doit être présent dans le DOM au chargement de la page.**
25+
26+
Oui, vous avez compris : si vous construisez votre formulaire directement en JS, ou si vous utilisez un template que vous accrochez une fois la page chargée, votre formulaire ne sera ignorés par certains navigateurs.
27+
28+
L'astuce que j'utilise consiste a :
29+
30+
* inclure le formulaire de login dans ma page index.html
31+
* le masquer avec un style CSS <tt>display:none</tt>.
32+
* le déplacer par la suite en javascript là où il doit apparaitre dans le rendu
33+
34+
**index.html**
35+
36+
<div id="loginStock" style="display:none">
37+
<form id="formLogin">
38+
<input type="text" name="username"/>
39+
<input type="password" name="password"/>
40+
</form>
41+
</div>
42+
43+
**login.js**
44+
45+
$('.loginContainer', this.element).append($('#loginStock > *'));
46+
47+
48+
## Dois-je mettre un champ de type <tt>submit</tt> ?
49+
50+
S'il n'y a que les champs de type <tt>text</tt> et <tt>password</tt>, le navigateur ne retiendra pas le mot de passe.
51+
52+
>**Le champ de type <tt>submit</tt> est indispensable.**
53+
54+
Même s'il est masqué (le bouton n'est pas encore bien skinnable, même en CSS 3), il doit être présent.
55+
56+
**index.html**
57+
58+
<div id="loginStock" style="display:none">
59+
<form id="formLogin">
60+
<input type="text" name="username"/>
61+
<input type="password" name="password"/>
62+
<input type="submit" style="display:none"/>
63+
</form>
64+
<a href="#" class="submit"></a>
65+
</div>
66+
67+
**login.js**
68+
69+
$('.loginContainer .submit').click(function(event){
70+
// Déclenche la soumission du formulaire.
71+
$('#formLogin').submit();
72+
// Annule la propagation du Click sur le lien, pas de la soumission du formulaire !
73+
return false;
74+
}).button({label:'log in !'});
75+
76+
77+
## Doit-on stopper la propagation de l'évènement <tt>submit</tt> ?
78+
79+
Le problème se pose si vous ne réalisez pas de "vrai" POST lorsque l'utilisateur déclenche la soumission du formulaire.
80+
Dans la majorité des applications riches, l'authentification se fait via une Api, et donc un appel Ajax.
81+
82+
On se branche alors sur l'évènement submit, et on annule sa propagation. Par exemple :
83+
84+
Seulement, en stoppant l'évènement de soumission, le navigateur ne retient pas le login et le mot de passe.
85+
86+
>**Pour que le navigateur mémorise le couple login/mot de passe, l'évènement <tt>submit</tt> doit se propager.**
87+
88+
Cela implique:
89+
90+
* Que le formulaire pointe sur une véritable url, sinon, une vilaine 404 apparaitra dans votre console
91+
* Que le résultat de la soumission est routée dans une iframe (désolé pour les puristes :)), sans quoi, toute la page se rechargera
92+
93+
Donc généralement, mon service web propose une Api POST qui ne fait rien et renvoi une page vide, et j'utilise une iframe masquée.
94+
95+
**index.html**
96+
97+
<div id="loginStock" style="display:none" method="post" action="/api/login/noop" target="postFrame">
98+
<form id="formLogin">
99+
<input autofocus="autofocus" type="text" name="username"/>
100+
<input autocomplete="on" type="password" name="password"/>
101+
<input type="submit" style="display:none"/>
102+
</form>
103+
<a href="#" class="submit"></a>
104+
</div>
105+
<iframe name="postFrame" class="hidden"></iframe>
106+
107+
**login.js**
108+
109+
$('#formLogin').submit(function(event){
110+
// Ici mon appel ajax, et surtout, ne pas renvoyer false ni n'invoquer event.stopPropagation().
111+
});
112+
113+
114+
### Une petite astuce : lorsque l'authentification échoue.
115+
116+
A partir du moment où l'évènement <tt>submit</tt> est propagé, et qu'une réponse HTTP est reçue, le navigateur conservera bien le mot de passe et le login.
117+
118+
Mais nous pouvons tirer parti de se comportement, lorsque l'authentification échoue, par exemple si l'utilisateur est inconnu, ou le mot de passe erroné.
119+
120+
Ainsi, mon appel Ajax est toujours **synchrone** (parfois ça sert !), et s'il échoue, alors dans ce cas, j'annule la propagation de l'évènement <tt>submit</tt> pour ne pas conserver les mauvais identifiants.
121+
122+
123+
124+
## La touche entrée ne soumet pas toujours mon formulaire...
125+
126+
Hélas oui, c'est un comportement étrange de certains navigateurs : un formulaire sera automatiquement soumit si on appuie sur entrée dans un de ses champs, sauf s'il à plus d'un champ <tt>text</tt>/<tt>password</tt>!
127+
128+
Nous n'avons donc pas d'autres choix que de gérer nous même en javascript la touche entrée :
129+
130+
**login.js**
131+
132+
$('#formLogin input').keyup(function(event){
133+
if (event.which == '13' && !event.metaKey) {
134+
$('#formLogin').submit();
135+
// Annule la propagation de l'évènement clavier, pour ne pas soumettre 2 fois le formulaire sur les navigateurs qui supportent correctement la feature.
136+
return false;
137+
}
138+
});
139+
140+
141+
## Conclusion
142+
143+
Vous voyez ? quand je vous disais que ce n'était pas trivial...
144+
145+
Mais maintenant, vous avez toutes les clefs pour faire des formulaires qui exploitent le cache de login/mot de passe des navigateurs.
146+
147+
Espérons que dans un futur proche, les navigateurs harmonisent un peu plus leur fonctionnement, de manière à éviter tout ces tricks...
148+
149+
Damien.

0 commit comments

Comments
 (0)