Formulář v komponentě, action na anchor

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Zax
Člen | 370
+
0
-

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

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

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

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

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

@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
+
0
-

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)

Zax
Člen | 370
+
0
-

Michal Vyšinský: viz můj ninja edit vespod ;-)

Dovolím si trapně ještě jeden edit: Ten nápad s onAttached se mi líbí, mám dokonce pocit, že po tomto eventu se tu už pár lidí shánělo, upřímně se skoro divím, že to v Nette není.

Editoval Zax (3. 5. 2014 23:51)