Replicator – problém s uploadem, který je ve stejném formuláři jako replicator
- chikeet
- Člen | 160
Předem upozorňuju, že upload nemám uvnitř replicatoru, tak mě nekamenujte, že nečtu, co se všude píše. K jádru věci: mám formulář – kartu produktu. Zjednodušeně vypadá takto:
{form productForm}
<div>{control $form errors}</div>
<div>
{label name /}
{input name}
</div>
<table>
<tr>
<td>{label area /}</td>
<td>{input area}</td>
<td rowspan="4">
{if $action == 'edit'}
<img src="{$product->makeImagePath()}" title="Hlavní fotka" alt="Hlavní fotka" /><br />
{else}
{label photo /}
{/if}
{input photo}
</td>
</tr>
...
</table>
{snippet dynamicItems}
<h2>Příprava</h2>
<div>
<div>
{foreach $form['preparations']->containers as $id => $preparation}
<div>
{label preparations-$id-type /} {input preparations-$id-type}
{label preparations-$id-duration /} {input preparations-$id-duration} min:s
{input preparations-$id-id} {input preparations-$id-remove}
</div>
{/foreach}
</div>
{input preparations-add_preparation}
</div>
<h2>Video</h2>
<div>
<div>
{foreach $form['videos']->containers as $id => $video}
<div>
{label videos-$id-code /} {input videos-$id-code}
{input videos-$id-id} {input videos-$id-remove}
</div>
{/foreach}
</div>
{input videos-add_video}
</div>
{/snippet}
{input submit}
{/form}
<script>
$('form.ajax :submit').live('click', function (event) {
event.preventDefault();
$.post(this.action, $(this).serialize());
});
</script>
V presenteru mám:
public function beforeRender() {
parent::beforeRender();
$this->template->form = $this->getComponent('productForm');
$this->template->_form = $this->getComponent('productForm');
}
//...
protected function createComponentProductForm($name){
$form = new Form();
//...
$form->addUpload('photo', 'Hlavní fotka')->addRule(Form::MAX_FILE_SIZE, 'Maximální velikost souboru je 5 MB.', 5242880);
$videos = $form->addDynamic('videos', function (Container $video) use ($presenter) {
$video->addTextArea('code', 'Kód videa:', 30, 5);
$video->addHidden('id', 0);
$video->addSubmit('remove', 'Smazat video')
->addRemoveOnClick(callback($presenter, 'DeleteVideo'));
});
$videos->addSubmit('add_video', 'Přidat video')
->addCreateOnClick(TRUE, function (Kdyby\Replicator\Container $replicator, Container $video) { });
$preparations = $form->addDynamic('preparations', function (Container $preparation) use ($presenter, $preparationTypeDAO) {
$preparation->addSelect('type', 'Typ:', $preparationTypeDAO->fetchPairs());
$preparation->addText('duration', 'Čas přípravy:')->addRule(Form::FILLED, 'Zadejte čas přípravy. ');
$preparation->addHidden('id', 0);
$preparation->addSubmit('remove', 'Smazat typ přípravy')
->setAttribute('class', 'ajax')
->addRemoveOnClick(callback($presenter, 'DeletePreparation'));
});
$form->addSubmit('submit', 'Uložit změny')
->onClick[] = callback($this, 'productFormSubmitted');
$this[$name] = $form;
$form->action .= '#snippet--dynamicItems';
return $form;
}
/**
* @param SubmitButton $button
*/
public function productFormSubmitted(SubmitButton $button){
$values = $button->form->values;
//...
}
No a problém: když kliknu na tlačítko pro přidání dynamické položky, tak se jednak celý formulář validuje a bez vyplnění povinných polí mě nepustí dál (přestože mám jako první argument funkce addCreateOnClick TRUE), a druhak, a to hlavně, se smaže soubor, který jsem předtím vybrala v uploadu. Navíc si nejsem jistá, jestli jde přidávání polí opravdu ajaxem (pardon, ale s ajaxem začínám), protože firebug se netváří jako při ajaxovém požadavku, ale ani se nepřekreslí celá stránka, hodnoty ve formuláři zůstanou stejné a neháže mě to nahoru na začátek stránky… Vím, jsem lama, ale opravdu si nejsem jistá, jestli to jde ajaxem, nebo jak. Budu ráda za každou radu, co může být špatně a jak to řešit.
Editoval chikeet (18. 8. 2013 20:06)
- OK3
- Člen | 91
Zkus na ta odesílací tlačítka (přidat i smazat) u replikátoru nastavit:
<?php
$videos->addSubmit('add_video', 'Přidat video')
->setValidationScope(FALSE)
...
?>
To by mohlo pomoci s validací.
K čemu je u toho tlačítka na přidání prázdná anonymní funkce? https://componette.org/search/?…
Jinak zajaxovat replikátor jde, stačí tu část ve formuláři obalit snippetem a dál postupovat podle návodu na ajax z dokumentace (zajaxovat formulář, invalidace snipetu). To by mohlo být i řešení problému s mazáním vybraného souboru, které nastane vždy po standardním odeslání a opětovném zobrazení formuláře (což replikátor způsobuje).
Edit: no vlastně koukám, že to tak jednoduchý není :) Tady je „hack“, který je potřeba, aby to fungovalo – možná to jde vyřešit líp, nevím.. Využívají se tam doplňky $.ajaxSubmit a Nette.forms
// Ajax replikátor
$replicatorSnippet.on('click', '.submit', function() {
// odchytáváme na odesílacím tlačítku replikátoru
var $button = $(this);
var $form = $button.parents('form');
var f = $form.get(0);
f.setAttribute('formnovalidate', true);
f['nette-submittedBy'] = f;
// odesílá formulář ajaxem
$form.ajaxSubmit.call($button, function(payload) {
$.nette.success(payload);
Nette.initForm(f);
});
return false;
});
Editoval OK3 (19. 8. 2013 11:50)
- chikeet
- Člen | 160
OK3 napsal(a):
Zkus na ta odesílací tlačítka (přidat i smazat) u replikátoru nastavit:
<?php $videos->addSubmit('add_video', 'Přidat video') ->setValidationScope(FALSE) ... ?>
To by mohlo pomoci s validací.
Díky moc, funguje.
Jinak zajaxovat replikátor jde, stačí tu část ve formuláři obalit snippetem a dál postupovat podle návodu na ajax z dokumentace (zajaxovat formulář, invalidace snipetu). To by mohlo být i řešení problému s mazáním vybraného souboru, které nastane vždy po standardním odeslání a opětovném zobrazení formuláře (což replikátor způsobuje).
Edit: no vlastně koukám, že to tak jednoduchý není :) Tady je „hack“, který je potřeba, aby to fungovalo – možná to jde vyřešit líp, nevím.. Využívají se tam doplňky $.ajaxSubmit a Nette.forms
// Ajax replikátor $replicatorSnippet.on('click', '.submit', function() { // odchytáváme na odesílacím tlačítku replikátoru var $button = $(this); var $form = $button.parents('form'); var f = $form.get(0); f.setAttribute('formnovalidate', true); f['nette-submittedBy'] = f; // odesílá formulář ajaxem $form.ajaxSubmit.call($button, function(payload) { $.nette.success(payload); Nette.initForm(f); }); return false; });
Navázání na tlačítko funguje, ale to ajaxové odesílání už ne. Mám nalinkované oba zmíněné js, takže tam by problém být neměl. Ale není mi úplně jasné, co přesně dělá to odesílání ajaxem. Doteď jsem používala pro ajaxové odesílání formuláře $button.ajaxSubmit(); a vím, že volá metodu pro submit toho formuláře, která pak dělá, coje potřeba. Ale není mi jasné, jak, když se mi ajaxově zavolá http://localhost/…dit-product/?…, probíhá přidání dynamické položky formuláře (kde se přidává, čím přesně se to přidání vyvolá). InvalidateControl tam mám, ale před invalidováním by se mělo provést to přidání položky…
Pro odesílání mi funguje $form.ajaxSubmit();, ale $form.ajaxSubmit.call(…) už ne, nic to neodesílá. A $form.ajaxSubmit(); sice něco odešle, ale nepřekreslí se mi snippet. Evidentně mi tam něco chybí, ale nemám tušení, co, zkouším všechno možné, ale nic nezabírá. Téma ajax a snippety jsem četla snad stokrát, ale ve spojení s Replicatorem a přidáváním polí, které probíhá – pro mě zatím záhadně – někde v kódu, mi to nějak nedocvakává.
- OK3
- Člen | 91
No v zásadě je potřeba nechat proběhnout to odeslání formuláře
tlačítkem replikátoru a pak překreslit snippet (invalidovat). Přidání je
vázáno na signál a detekuje se, jestli jej odeslalo to správné tlačítko,
jinak se nic nepřidá. Proto tam je ta
část $form.ajaxSubmit.call($button, function(payload) ...
Ten můj kód taky počítá s tím, že to tlačítko bude mít třídu
submit
.
Nevím, jak bych víc poradil. Pořádně prozkoumej ajaxové požadavky a jejich odpovědi v konzoli, snad tam něco najdeš. Nebo sem ještě dej kód: část šablony s tím snippetem, obslužný skript a část presenteru, která to obsluhuje na serveru.