Ajaxový upload skutečně funguje?
- Kcko
- Člen | 468
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?
- Kcko
- Člen | 468
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
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)
- m.brecher
- Generous Backer | 863
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)