Ajaxový upload skutečně funguje?

Kcko
Člen | 468
+
0
-

V nedávném topicu (https://forum.nette.org/…i-tovarnicky#…) tazatel řešil ajaxový upload a nepřekreslování. Chyba byla v nesprávném pořadí volání nette.init a čehosi.
Já jsem si to zkoušel taky a nerozumím tomu, jak mu nettí ajax může poslat pole $_FILE.

Mě to tedy nefunguje, Nette 2.3

Když odesílám formulář ajaxem, tak mám vždycky prvek typu FILE UPLOAD prázdný s chybou 4.

<?php
Nette\Utils\ArrayHash Object
(
    [xxxxx] => aaa
    [upload] => Nette\Http\FileUpload Object
        (
            [name:Nette\Http\FileUpload:private] =>
            [type:Nette\Http\FileUpload:private] =>
            [size:Nette\Http\FileUpload:private] =>
            [tmpName:Nette\Http\FileUpload:private] =>
            [error:Nette\Http\FileUpload:private] => 4
        )

)
?>

Kde je chyba? Tohle má tedy fungovat?

Ondřej Kubíček
Člen | 494
+
0
-

jak ten formulář vypadá?

Kcko
Člen | 468
+
0
-

Ondřej Kubíček napsal(a):

jak ten formulář vypadá?

Nic nestandardního.

<?php
	protected function createComponentUploadForm()
	{
		$form = new Nette\Application\UI\Form;
		$form->getElementPrototype()->setClass('ajax');
		$form->addText('xxxxx', 'Test')->setRequired();
		$form->addUpload('upload', 'Upload file');
		$form->addSubmit('btn', 'Odeslat');

		$that = $this;
		$form->onSuccess[] = function($form, $values) use($that) {

			$file = $values['upload'];
			$file->move(__ROOT__ . '/upload/' . $file->getSanitizedName());

			$that->redrawControl('upload');

		};

		return $form;
	}

?>
Kcko
Člen | 468
+
0
-

Ondřej Kubíček napsal(a):

jak ten formulář vypadá?

Nic nestandardního. Když to odešlu mimo ajax, tak se soubor uloží.

<?php
	protected function createComponentUploadForm()
	{
		$form = new Nette\Application\UI\Form;
		$form->getElementPrototype()->setClass('ajax');
		$form->addText('xxxxx', 'Test')->setRequired();
		$form->addUpload('upload', 'Upload file');
		$form->addSubmit('btn', 'Odeslat');

		$that = $this;
		$form->onSuccess[] = function($form, $values) use($that) {

			$file = $values['upload'];
			$file->move(__ROOT__ . '/upload/' . $file->getSanitizedName());

			$that->redrawControl('upload');

		};

		return $form;
	}

?>

Editoval Kcko (23. 6. 2018 10:46)

Ondřej Kubíček
Člen | 494
+
0
-

nevím jestli to teda není 2.3, ve 2.4 mi ten příklad funguje

Kcko
Člen | 468
+
0
-

Ondřej Kubíček napsal(a):

nevím jestli to teda není 2.3, ve 2.4 mi ten příklad funguje

Aha tak to bude asi tím.

Mohl by to někdo potvrdit, co kde změnilo? @DavidMatějka?

Kcko
Člen | 468
+
+4
-

Záhada objasněna, verzí Nette to není, bylo to starší verzí nette.ajaxu. Už to šlape jak má.

Felix
Nette Core | 1196
+
+1
-

Nadesel cas to pridat do ukazky s Webpackem.

contributte/webpack-skeleton

At to slouzi jako reference.

m.brecher
Generous Backer | 863
+
+1
-

Ahoj,

také jsem narazil na to, že ajaxový nette formulář neposílá data v případě, že obsahuje input pro nahrání souborů UploadControl. Používám vlastní javascriptový ovladač pro nette formuláře a příčina byla záludná:

Nette formuláře automaticky nastaví formuláři, který obsahuje prvek UploadControl enctype = multipart/form-data. Javascript tento enctype podporuje a kód pro odeslání ajaxového requestu submitu formuláře není složitý – zjednodušeně nějak takto:

#sendFormRequest(url, form, event)
{
    let submitter = event.submitter
    let body = form.enctype === 'application/x-www-form-urlencoded'
        ? new URLSearchParams(new FormData(form))
        : new FormData(form);
    body.append(submitter.name, submitter.value)
    fetch(url, {
        method: form.method,
        headers: {
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type':  form.enctype,  // nefunguje pokud je enctype = 'multipart/form-data'
            'Accept': 'application/json'
        },
        body: body
    })
        .then(response => {
            //.......
        })
}

Výše uvedený javascript bezproblémově odesílá ajaxově submit Nette formuláře BEZ prvků UploadControl. Jakmile UploadControl přidáme, ajaxový request odejde, ale neobsahuje žádná data, která by server mohl přečíst.

Nejedná se o chybu ve formulářích nebo v uvedeném javascriptu, ale je to správné, leč neočekávané chování browseru. Příčinou je dělení dat – multipart do sekcí boundary, které prohlížeč neprovede správně, pokud se nastaví hodnota ‚Content-Type‘: ‚multipart/form-data‘.

Detailně je problematika popsána zde: https://muffinman.io/…t-form-data/, Článek lze shrnout do jednoduchého pravidla: „To upload files using fetch and FormData you must NOT set Content-Type header“.

Když jsem pro formulář multipart/form-data vyřadil položku ‚Content-Type‘ z http hlavičky, ajaxový request odeslal správná data. Toto důležité pravidlo pro práci s fetchAPI a FormData není na internetu dostatečně propagováno.

Editoval m.brecher (8. 2. 19:39)