Ce chapitre concerne l’envoi de formulaires HTML: avec ou sans fichiers, avec des champs supplémentaires, etc…
Les objets FormData peuvent nous aider pour cela. Comme vous l’avez peut-être deviné, c’est l’objet pour représenter les données du formulaire HTML.
Le constructeur est :
let formData = new FormData([form]);
Si un élément HTML form
est fourni, il capture automatiquement ses champs.
La particularité de FormData
est que les méthodes réseau, telles que fetch
, peuvent accepter un objet FormData
en tant que corps. Il est encodé et envoyé avec Content-Type: multipart/form-data
.
Du point de vue du serveur, cela ressemble à une soumission de formulaire habituelle.
Envoi d’un formulaire simple
Envoyons d’abord un formulaire simple.
Comme vous pouvez le voir, c’est presque une ligne :
<form id="formElem">
<input type="text" name="name" value="John">
<input type="text" name="surname" value="Smith">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
Dans cet exemple, le code du serveur n’est pas présenté, car il dépasse notre portée. Le serveur accepte la requête POST et répond “User saved”.
Méthodes FormData
Nous pouvons modifier les champs dans FormData
avec des méthodes :
formData.append(name, value)
– ajoute un champ de formulaire avec lename
etvalue
donnés,formData.append(name, blob, fileName)
– ajoute un champ comme s’il était<input type="file">
, le troisième argumentfileName
définit le nom du fichier (pas le nom du champ de formulaire), comme s’il s’agissait d’un nom du fichier dans le système de fichiers de l’utilisateur,formData.delete(name)
– supprimer le champ avec lename
donné,formData.get(name)
– obtient la valeur du champ avec lename
donné,formData.has(name)
– s’il existe un champ avec lename
donné, retournetrue
, sinonfalse
Un formulaire est techniquement autorisé à avoir plusieurs champs avec le même name
, donc plusieurs appels à append
ajoute d’autres champs portant le même nom.
Il existe également la méthode set
, avec la même syntaxe que append
. La différence est que .set
supprime tous les champs avec le name
donné, puis ajoute un nouveau champ. Il s’assure donc qu’il n’y a qu’un seul champ avec ce genre de name
, le reste est comme append
:
formData.set(name, value)
,formData.set(name, blob, fileName)
.
Nous pouvons également parcourir les champs formData en utilisant la boucle for..of
:
let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
// List key/value pairs
for(let [name, value] of formData) {
alert(`${name} = ${value}`); // key1 = value1, ensuite key2 = value2
}
Envoi d’un formulaire avec un fichier
Le formulaire est toujours envoyé en tant que Content-Type: multipart/form-data
, cet encodage permet d’envoyer des fichiers. Ainsi, les champs <input type="file">
sont également envoyés, comme pour une soumission de formulaire habituelle.
Voici un exemple avec ce genre de formulaire :
<form id="formElem">
<input type="text" name="firstName" value="John">
Picture: <input type="file" name="picture" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user-avatar', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
Envoi d’un formulaire avec des données Blob
Comme nous l’avons vu dans le chapitre Fetch, il est facile d’envoyer des données binaires générées dynamiquement, par exemple une image en tant que Blob
. Nous pouvons le fournir directement en tant que paramètre body
de fetch
.
En pratique cependant, il est souvent plus commode d’envoyer une image non pas séparément, mais en tant que partie du formulaire, avec des champs supplémentaires, tels que “name” et autres métadonnées.
En outre, les serveurs sont généralement plus adaptés pour accepter des formulaires encodés en plusieurs parties, plutôt que des données binaires brutes.
Cet exemple soumet une image à partir de <canvas>
, ainsi que d’autres champs, sous forme de formulaire, en utilisant FormData
:
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Submit" onclick="submit()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function submit() {
let imageBlob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let formData = new FormData();
formData.append("firstName", "John");
formData.append("image", imageBlob, "image.png");
let response = await fetch('/article/formdata/post/image-form', {
method: 'POST',
body: formData
});
let result = await response.json();
alert(result.message);
}
</script>
</body>
Veuillez noter comment l’image Blob
est ajoutée :
formData.append("image", imageBlob, "image.png");
C’est comme s’il y avait <input type="file" name="image">
dans le formulaire, et le visiteur a soumis un fichier nommé "image.png"
(3ème argument) avec les données imageBlob
(2ème argument) de son système de fichiers.
Le serveur lit les données du formulaire et le fichier, comme s’il s’agissait d’une soumission régulière de formulaire.
Résumé
Les objets FormData sont utilisés pour capturer le formulaire HTML et le soumettre en utilisant fetch
ou une autre méthode réseau.
Nous pouvons soit créer un new FormData(form)
à partir d’un formulaire HTML, soit créer un objet sans aucun formulaire, puis ajouter des champs avec des méthodes :
formData.append(name, value)
formData.append(name, blob, fileName)
formData.set(name, value)
formData.set(name, blob, fileName)
Notons ici deux particularités :
- La méthode
set
supprime les champs du même nom, contrairement àappend
. C’est la seule différence entre eux. - Pour envoyer un fichier, une syntaxe à 3 arguments est nécessaire, le dernier argument est un nom de fichier, qui est normalement extrait du système de fichiers utilisateur pour
<input type="file">
.
Les autres méthodes sont :
formData.delete(name)
formData.get(name)
formData.has(name)
C’est tout !
Commentaires
<code>
, pour plusieurs lignes – enveloppez-les avec la balise<pre>
, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen…)