Formulář v komponentě, action na anchor
- Zax
- Člen | 370
Ahoj,
mám komponentu na komentáře a u každého komentáře se zobrazuje formulář s tlačítky Upravit/Odstranit (pomocí Multiplieru). Po kliknutí na Upravit se příslušný komentář změní na editační formulář. Komponenta je záměrně nastavená tak, že se editační formulář zobrazí pouze po kliknutí na Upravit (=nejde se na něj redirectnout).
Můj problém je následující: nejde mi nastavit action formuláře s těmi tlačítky aby obsahoval hash parametr (anchor) – abych po kliknutí na Upravit měl ihned daný komentář přímo před sebou.
Když action nenastavím, formulář směřuje na
?do=tripDetail-tripComments-toolsForm-4-submit
Když ale action nastavím pomocí
$form->action .= '#comment-' . $comment->id;
tak formulář směřuje na
#comment-4
a pochopitelně se bez toho ?do=… neodešle.
Když akci nenastavím a jenom si ji dumpnu, dostanu prázdný string. Hádám, že Nette automaticky doplňuje action jen když je prázdná a neignoruje přitom hash parametr – je k tomu nějaký pádný důvod?
Existuje (jednoduché) řešení mého problému?
Díky
Editoval Zax (3. 5. 2014 15:02)
- Zax
- Člen | 370
Trochu jsem zkoumal, kde je zakopaný pes, a zjistil jsem, že formulář musí být připojen k presenteru. Obvykle by to nebyl problém, jenže formulář definuji v Multiplieru a tam nemám možnost jej připojit (nebo nevím jak na to).
Myslím, že tato část by chtěla lehce upravit nějak zhruba v tomto duchu:
if (!$this->getAction() || $actionIsAnchor = strpos($this->getAction(), '#') === 0) {
$this->setAction(new Link($presenter, 'this' . ($actionIsAnchor ? $this->getAction() : ''), array()));
}
Nenapadá mě totiž situace, kdy bych si přál, aby se mi pouhým nastavením anchoru zrušila celá výchozí action. A určitě by se mi jen kvůli anchoru nechtělo psát celý $this->setAction(new Link(…));
Ale to je jen můj názor.
Editoval Zax (3. 5. 2014 15:28)
- PavelJurasek
- Člen | 39
Ty přece stejně nepotřebuješ přidávat fragment do url při odesílání formuláře, ale až při redirectu z jeho zpracování.
- Zax
- Člen | 370
No jo no, dělat formuláře (byť jen složené ze submitů) bez redirectu není úplně košér. Můj původní záměr byl, že se editační okno otevře jen po kliknutí na ten submit „Upravit“, chtěl jsem se vyhnout tomu, aby existovala specifická url adresa přímo pro ten editační formulář..
S redirectem a signály vše funguje, ale formulář jde zobrazit vložením správné adresy, což nechci. Napadá mě použít session, ale to je trošku overkill když mi fakt jde jenom o ověření (které tam už je a bez redirectu funguje), že se na formulář přistoupilo ze správného tlačítka…
Sice možná nejedu úplně podle best practice a uznávám, že v 99%
případů po formuláři má následovat redirect, ale není to důvod, aby mi
Nette házelo v 1% klacky pod nohy když to není bezpodmínečně nutné.
Prostě nevidím důvod, proč by se ta akce nemohla vygenerovat s fragmentem
na konci (fragment je přece nezávislý na zbytku url, nemá na chod aplikace
absolutně žádný vliv)… kdybych to psal v čistém HTML/PHP, tak si tam
ten fragment prostě přidám a jsem v pohodě, ale Nette v tomhle případě
působí trochu jako zbytečná „brzda“ :-(
EDIT: nebo spíš Multiplier působí jako brzda, nejde mi v něm formulář
správně připojit k presenteru. Po připojení je samozřejmě možné si ten
fragment do action přidat bez problémů…
No tak, přece musí být nějaká rozumná cesta, nevěřím, že jsem narazil na něco, o čem se dá říct „sorry, tohle v Nette prostě nejde“ a přitom řešení by bylo celkem jednoduché a myslím si že i naprosto intuitivní.
Editoval Zax (3. 5. 2014 23:27)
- Michal Vyšinský
- Člen | 608
Ahoj, kde nastavuješ tu action? Ten append by měl fungovat, nicméně action se nastavuje až v attached, takže přepiš attached a za parent::attached dej ten append.
Edit: teď jsem to schválně zkusil a funguje to:
class BlaForm extends Nette\Application\UI\Form
{
protected function attached($presenter)
{
parent::attached($presenter);
$this->action .= '#test';
}
}
A ještě druhý způsob, kdybys nechtěl třídu pro formulář navíc:
public function createComponentForm($name)
{
$form = new BlaForm($this, $name);
// zde se attached již zavolalo a action je nastavena
$form->action .= '#test';
}
Edit: omlouvám se, přeskočil jsem druhý příspěvek o použití Multiplieru, nicméně první způsob by fungovat mohl.
Editoval Michal Vyšinský (3. 5. 2014 23:39)
- Zax
- Člen | 370
@Michal Vyšinský: Věřím, že to funguje a možná to tak i nakonec udělám, ale je mi proti srsti představa, že jen kvůli nastavení action musím tvořit nový unikátní „BaseForm“…
Formulář tvořím zde (problém je v multiplieru, bez něj nemám problém formulář s presenterem spojit)
protected function createComponentToolsForm() {
$control = $this;
return new UI\Multiplier(function($id) use ($control) {
// Zax\Forms\Form rozšiřuje UI\Form
$form = new Zax\Forms\Form; // kdybych zde mohl formulář připojit k multiplieru, měl bych vyhráno
if(!$control->canEditOrDelete()) {
return $form;
}
$form->getElementPrototype()->addClass('tools');
$form->addProtection();
$form->addHidden('commentId')->setDefaultValue($id);
if($control->canEdit()) {
$form->addSubmit('edit', 'Upravit');
}
if($control->canDelete()) {
$form->addSubmit('delete', 'Odstranit');
}
$form->enableBootstrap();
$form->groupButtons();
//$form->action .= '#comment-' . $id;
$form->onSuccess[] = array($control, 'toolsFormSubmitted');
return $form;
});
}
A vykresluji zhruba takto:
{foreach $comments as $comment}
{if $control->canEditOrDelete()}
{control toolsForm-$comment->id}
{/if}
# ...
{/foreach}
EDIT: Hm až teď mě to trklo.. do Zax\Forms\Form si prostě přidám metodu setActionFragment, přetížím attached a můžu to používat kdykoliv budu potřebovat (aniž bych výrazně narušil běžné chování Nette). Děkuji za nakopnutí :-)
Editoval Zax (3. 5. 2014 23:48)
- Michal Vyšinský
- Člen | 608
No a co si udělat vlastní event onAttached? V Zax\Forms\Form přepsat metodu attached a za parent::attached dát $this->onAttached($this); V callbacku bys mohl nastavit action podle potřeby.
Možná by nebylo od věci, aby tento event byl přímo v Nette.
Editoval Michal Vyšinský (3. 5. 2014 23:45)