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 lenameetvaluedonnés,formData.append(name, blob, fileName)â ajoute un champ comme sâil était<input type="file">, le troisième argumentfileNamedé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 lenamedonné,formData.get(name)â obtient la valeur du champ avec lenamedonné,formData.has(name)â sâil existe un champ avec lenamedonné, 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
setsupprime 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â¦)