Tato kapitola pojednává o odesÃlánà HTML formuláÅů: se soubory nebo bez nich, s dodateÄnými poli a podobnÄ.
Mohou nám s tÃm pomoci objekty tÅÃdy FormData. Jak jste možná uhádli, tento objekt reprezentuje data HTML formuláÅe.
Jeho konstruktor je následujÃcÃ:
let formData = new FormData([form]);
Pokud je uveden HTML element form, objekt automaticky naÄte jeho pole.
Zvláštnostà na FormData je, že sÃÅ¥ové metody, napÅ. fetch, mohou pÅijÃmat objekt FormData jako tÄlo požadavku. Bude zakódován a odeslán s Content-Type: multipart/form-data.
Z pohledu serveru to vypadá jako obvyklé odeslánà formuláÅe.
Poslánà jednoduchého formuláÅe
Nejprve poÅ¡leme jednoduchý formuláÅ.
Jak vidÃte, je to skoro na jeden Åádek:
<form id="formElem">
<input type="text" name="jméno" value="Jan">
<input type="text" name="pÅÃjmenÃ" value="Novák">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let odpovÄÄ = await fetch('/article/formdata/post/user', {
method: 'POST',
body: new FormData(formElem)
});
let výsledek = await odpovÄÄ.json();
alert(výsledek.message);
};
</script>
Serverový kód nenà v tomto pÅÃkladu uveden, protože je mimo náš rámec. Server pÅijme požadavek POST a odpovà âUser savedâ (âUživatel uloženâ).
Metody tÅÃdy FormData
Pole ve FormData můžeme mÄnit pomocà tÄchto metod:
formData.append(název, hodnota)â pÅidá do formuláÅe pole s názvemnázeva hodnotouhodnota,formData.append(název, blob, názevSouboru)â pÅidá pole, jako by to bylo<input type="file">, tÅetà argumentnázevSouborunastavà název souboru (ne název formuláÅového pole), jako by to byl název souboru z uživatelova souborového systému,formData.delete(název)â odstranà pole s názvemnázev,formData.get(název)â vrátà hodnotu pole s názvemnázev,formData.has(název)â pokud existuje pole s názvemnázev, vrátÃtrue, jinak vrátÃfalse.
Technicky formuláŠsmà obsahovat vÃce polà se stejným názvem, takže nÄkolik volánà append pÅidá nÄkolik polà se stejným názvem.
Existuje i metoda set, která má stejnou syntaxi jako append, ale rozdÃl spoÄÃvá v tom, že .set odstranà vÅ¡echna pole s názvem název a pak pÅidá nové pole. TÃm zajistÃ, že ve formuláÅi bude jen jedno pole s názvem název. VÅ¡echno ostatnà je jako u append:
formData.set(název, hodnota),formData.set(název, blob, názevSouboru).
Můžeme také iterovat nad poli ve formData pomocà cyklu for..of:
let formData = new FormData();
formData.append('klÃÄ1', 'hodnota1');
formData.append('klÃÄ2', 'hodnota2');
// Seznam dvojic klÃÄ/hodnota
for(let [název, hodnota] of formData) {
alert(`${název} = ${hodnota}`); // klÃÄ1 = hodnota1, pak klÃÄ2 = hodnota2
}
Poslánà formuláÅe se souborem
FormuláŠse vždy posÃlá jako Content-Type: multipart/form-data. Toto kódovánà umožÅuje posÃlat soubory. PosÃlajà se tedy i pole <input type="file">, podobnÄ jako pÅi obvyklém odeslánà formuláÅe.
NásledujÃcà pÅÃklad obsahuje takový formuláÅ:
<form id="formElem">
<input type="text" name="kÅestnÃJméno" value="Jan">
Obrázek: <input type="file" name="obrázek" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let odpovÄÄ = await fetch('/article/formdata/post/user-avatar', {
method: 'POST',
body: new FormData(formElem)
});
let výsledek = await odpovÄÄ.json();
alert(výsledek.message);
};
</script>
PosÃlánà formuláÅe s daty blobu
Jak jsme vidÄli v kapitole Fetch, je snadné poslat dynamicky generovaná binárnà data, napÅ. obrázek, jako Blob. Můžeme jej pÅedat pÅÃmo jako parametr body metody fetch.
V praxi je vÅ¡ak Äasto vhodnÄjšà neposÃlat obrázek oddÄlenÄ, ale jako souÄást formuláÅe s dalÅ¡Ãmi poli, napÅÃklad s názvem nebo jinými metadaty.
NavÃc servery jsou obvykle lépe navrženy pro pÅÃjem formuláÅů zakódovaných v multipart než planých binárnÃch dat.
Tento pÅÃklad posÃlá pomocà FormData obrázek z <canvas> spolu s nÄkterými dalÅ¡Ãmi poli jako formuláÅ:
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Odeslat" onclick="odešli()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function odešli() {
let blobObrázku = await new Promise(splÅ => canvasElem.toBlob(splÅ, 'image/png'));
let formData = new FormData();
formData.append("firstName", "Jan");
formData.append("image", blobObrázku, "image.png");
let odpovÄÄ = await fetch('/article/formdata/post/image-form', {
method: 'POST',
body: formData
});
let výsledek = await odpovÄÄ.json();
alert(výsledek.message);
}
</script>
</body>
ProsÃme vÅ¡imnÄte si, jak se pÅidává obrázek Blob:
formData.append("image", blobObrázku, "image.png");
Je to totéž, jako by ve formuláÅi byl <input type="file" name="image"> a návÅ¡tÄvnÃk poslal ze svého souborového systému soubor s názvem "image.png" (3. argument) a daty blobObrázku (2. argument).
Server naÄte data formuláÅe a soubor stejnÄ, jako pÅi obvyklém odeslánà formuláÅe.
ShrnutÃ
Objekty FormData se použÃvajà k naÄtenà HTML formuláÅe a jeho odeslánà metodou fetch nebo jinou sÃÅ¥ovou metodou.
Můžeme buÄ vytvoÅit new FormData(form) z HTML formuláÅe, nebo vytvoÅit objekt úplnÄ bez formuláÅe a pak do nÄj pÅidávat pole následujÃcÃmi metodami:
formData.append(název, hodnota)formData.append(název, blob, názevSouboru)formData.set(název, hodnota)formData.set(název, blob, názevSouboru)
VÅ¡imnÄme si zde dvou zvláštnostÃ:
- Metoda
setodstranà pole se stejným názvem, metodaappendne. To je jediný rozdÃl mezi nimi. - K odeslánà souboru potÅebujeme tÅÃargumentovou syntaxi. Poslednà argument je název souboru, který se v
<input type="file">zpravidla bere z uživatelova souborového systému.
Dalšà metody jsou:
formData.delete(název)formData.get(název)formData.has(název)
A je to!
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)