FormData

Tato kapitola je o odesílání formulářů HTML:se soubory nebo bez nich, s dalšími poli atd.

S tím mohou pomoci objekty FormData. Jak jste možná uhodli, je to objekt reprezentující data formuláře HTML.

Konstruktor je:

let formData = new FormData([form]);

Pokud HTML form prvek, automaticky zachytí jeho pole.

Zvláštní věc na FormData jsou síťové metody, jako je fetch , může přijmout FormData objekt jako tělo. Je zakódováno a odesláno s Content-Type: multipart/form-data .

Z pohledu serveru to vypadá jako obvyklé odeslání formuláře.

Odeslání jednoduchého formuláře

Nejprve odešleme jednoduchý formulář.

Jak vidíte, je to téměř jednodílné:

<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>

V tomto příkladu není uveden kód serveru, protože je mimo náš rozsah. Server přijme požadavek POST a odpoví „Uživatel uložen“.

Metody FormData

Můžeme upravit pole v FormData s metodami:

  • formData.append(name, value) – přidejte pole formuláře s daným name a value ,
  • formData.append(name, blob, fileName) – přidejte pole, jako by to bylo <input type="file"> , třetí argument fileName nastavuje název souboru (ne název pole formuláře), jako by to bylo jméno souboru v systému souborů uživatele,
  • formData.delete(name) – odeberte pole s daným name ,
  • formData.get(name) – získat hodnotu pole s daným name ,
  • formData.has(name) – pokud existuje pole s daným name , vrátí true , jinak false

Formulář může mít technicky mnoho polí se stejným name , takže více volání na append přidejte další pole stejného jména.

Existuje také metoda set , se stejnou syntaxí jako append . Rozdíl je v tom, že .set odstraní všechna pole s daným name a poté připojí nové pole. Takže zajišťuje, že existuje pouze jedno pole s takovým name , zbytek je jako append :

  • formData.set(name, value) ,
  • formData.set(name, blob, fileName) .

Také můžeme iterovat přes pole formData pomocí for..of smyčka:

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, then key2 = value2
}

Odeslání formuláře se souborem

Formulář je vždy odeslán jako Content-Type: multipart/form-data , toto kódování umožňuje posílat soubory. Takže <input type="file"> pole jsou také odeslána, podobně jako při obvyklém odeslání formuláře.

Zde je příklad s takovým formulářem:

<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>

Odeslání formuláře s daty objektů Blob

Jak jsme viděli v kapitole Načítání, je snadné odesílat dynamicky generovaná binární data, např. obrázek, jako Blob . Můžeme jej dodat přímo jako fetch parametr body .

V praxi je však často vhodné odeslat obrázek nikoli samostatně, ale jako součást formuláře s dalšími poli, jako je „jméno“ a další metadata.

Servery jsou také obvykle vhodnější k přijímání vícedílně zakódovaných formulářů, spíše než nezpracovaných binárních dat.

Tento příklad odešle obrázek z <canvas> , spolu s některými dalšími poli jako formulář pomocí 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>

Všimněte si prosím, jak obrázek Blob je přidáno:

formData.append("image", imageBlob, "image.png");

To je stejné, jako kdyby existovalo <input type="file" name="image"> ve formuláři a návštěvník odeslal soubor s názvem "image.png" (3. argument) s údaji imageBlob (2. argument) z jejich souborového systému.

Server čte data formuláře a soubor, jako by šlo o běžné odeslání formuláře.

Shrnutí

Objekty FormData se používají k zachycení formuláře HTML a jeho odeslání pomocí fetch nebo jinou síťovou metodou.

Můžeme buď vytvořit new FormData(form) z formuláře HTML nebo vytvořte objekt bez formuláře a poté přidejte pole pomocí metod:

  • formData.append(name, value)
  • formData.append(name, blob, fileName)
  • formData.set(name, value)
  • formData.set(name, blob, fileName)

Zde si všimněme dvou zvláštností:

  1. set metoda odstraní pole se stejným názvem, append ne. To je jediný rozdíl mezi nimi.
  2. Pro odeslání souboru je nutná syntaxe se 3 argumenty, posledním argumentem je název souboru, který se normálně přebírá z uživatelského souborového systému pro <input type="file"> .

Další metody jsou:

  • formData.delete(name)
  • formData.get(name)
  • formData.has(name)

To je ono!