Jak na vlastní komponentu

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

Ahoj, snažím se vytvořit vlastní komponentu na krokový formulář. Inspiroval jsem se zde https://forum.nette.org/…est-practice

Nicméně potřebuji trochu jiné použití a jelikož dělám v nette krátce, řekl jsem si že si ji zkusim napsat sám.

Zatím vše vypadá funkčně jen mi nejde do hlavy jak vytvářet odkazy a jak volat signály.. v komponentě podle které to zkouším, je funkce attached(), která jak jsem se dočetl monitoruje změny nad presenterem. Nicméně odkaz poté v šabloně vypadá takto

{plink this, var=>'neco'}

v dokumentaci je ale příklad na fifteen: https://github.com/…ster/Fifteen a zde David používá signály. Přijde mi to hezčí, ikdyž mi to generuje zvláštní url: ?stepForm-step=3&do=stepForm-Step. Proč v krokovém formuláři je použito attached() ale jinak se používají signály v čem e to lepší nebo rozdílné ?

a dále bych potřeboval zjistit jak se dá formulář odeslat do komponenty, kde bych si například jeho data uložil do session. Díky

Editoval kleinpetr (27. 3. 2015 15:39)

Jan Suchánek
Člen | 404
+
0
-

@kleinpetr Udělej si model kterej pracuje se session a ten model používej v komponentě a výsledky formu předávej normálně tomu modelu.

kleinpetr
Člen | 480
+
0
-

To sice jo, ale jak mám udělat to předání těch hodnot z toho formu.. ?

kleinpetr
Člen | 480
+
0
-

Asi jsem měl zmínit, že rozděluju na kroky pouze jeden fomrulář který je rozdělen na groupy a každá group je jeden krok.. tudíž jeden krok je pouze sada několika inputů a potřenuji vždy tu sadu za pomoci nějakého buttonu odeslat do nějakého signálu nebo tak někam, kde to potom zpracuji.

kleinpetr
Člen | 480
+
0
-

Opravdu by mi někdo nevysvětlil jaký je rozdíl mezi použitím attached() nebo signálu ?

Vojtěch Dobeš
Gold Partner | 1316
+
+1
-

kleinpetr: Opravdu by mi někdo nevysvětlil jaký je rozdíl mezi použitím attached() nebo signálu ?

Neřekl bych, že metoda attached monitoruje změny nad presenterem. Kde jsi se to dočetl?

Každopádně jak je to přesně: metoda attached je zavolána, jakmile je komponenta připojena k monitorovanému rodiči. Potomci UI\Control by default monitorují presenter, proto je metoda attached ve všech potomcích UI\Control (což jsou klasické vykreslované komponenty) zavolána, jakmile je tato komponenta připojena k presenteru. Metoda se hodí, pokud potřebuješ mít jistotu, že se některý kód vykoná teprve, jakmile je komponenta připojena k presenteru (například vytvoření odkazu může záviset na presenteru apod.).

Signály jsou docela jiná věc. handle metody jsou rozhraním komponenty, vyjadřují, co může uživatel webu s komponentou dělat (kliknout na odkaz, odeslat formulář… to vše budou signály).

Klidně se ptej dále, pokud je to stále nejasné.

kleinpetr
Člen | 480
+
0
-

Moc díky, snažím se totiž vytvoři krokový formulář na úrovni groups. Mám napsanou komponentu StepForm() do které pošlu nějaký již vytvořený form. Tenhle form je rozdělen třeba na 4 groups a já nyní vezmu ten form, proiteruju ty groupy a každou tu group si uložím jako step pod klíčem currentStep. Poté mám signál handleStep() jejímž parametrem je nový currentStep, tenhle signál prozatím jen změní pozici currentStep.. a podle aktuální pozice se pak vykreslí daná group. Po odeslání prvního kroku, kde má submit nastavenou scope pro první kontejner, se uloží hodnoty do sessionSteps, v metodě saveForm() kontroluji zda už nejsem na posledním korku a pokud ano tak si vezme všechny ty sessionSteps a vrátí je do presenteru. Pro ukázku zasílám kód. Budu rád když mě někdo opraví, navede, prostě cokoliv, abych se poučil. Zdá se mi to celé takové nepřehledné, kdyby měl někdo tip co by se alo zkrátit nebo vylepšit, určitě to přivítám :).

  • Nepodařilo se mi udělat vícerozměrné pole v session, neco jako $this->session['steps']['step1']; končí errorem, proto jsem vytvořil i sessionSection pro steps zvlášť.
  • Ještě bych se chtěl zeptat jak mohu manuálně spustit validaci nad celým formulářem ? Například něco jako $form->isValid(); ? díky.
<?php
namespace App\Components;

use Nette\Application\UI\Control;
use Nette\Application\UI\Presenter;
use App\Model\FormModelParser;
use Nette\Http\Session;

class StepForm extends Control
{

    private $steps;

    private $menu;

    private $form;

    public $onFinish;

    private $session;

    private $sessionSteps;


    public function __construct($uniqueName = null, FormModelParser $form, Session $session)
    {
        parent::__construct();
        $this->session = $session->getSection($uniqueName);
        $this->sessionSteps = $session->getSection($uniqueName . '_steps');

        if (!isset($this->session->currentStep)) {
            $this->session->currentStep = 1;
        }

        $this->form = $form;
        $this->setSteps();
    }

    private function setSteps()
    {
        $form = $this->form;
        foreach ($form->groups as $group) {
            $counter = count($this->menu) + 1;
            $this->menu[$counter] = $group->getOption('label');
            $this->steps[$counter] = $group;
        }
    }

    public function handleStep($position)
    {
        if (!$this->isRange($position)) {
            $position = 1;
            $this->flashMessage('Neplatný krok', 'danger');
        }

        $this->session->currentStep = $position;
        $this->redrawControl();
    }


    protected function createComponentForm()
    {
        $form = $this->form;
        $form->onSuccess[] = [$this, 'saveForm'];
        return $form;
    }


    public function saveForm($form)
    {
        $session = $this->session;
        $sessionSteps = $this->sessionSteps;
        $vals = $form->values;
        $stepValues = [];


        $sessionSteps[$session->currentStep] = $vals['step_' . $session->currentStep];
        $this->flashMessage('Step ' . $session->currentStep . ' save');

        if ($session->currentStep == count($this->steps)) {
            foreach ($sessionSteps as $step) {
                foreach ($step as $key => $val) {
                    $stepValues[$key] = $val;
                }
            }

			//zde jeste zvaliduji cely formular najednou.
            $this->onFinish($stepValues);
            $this->flashMessage('Form send to Presenter', 'success');
        }

        if ($this->isRange(($session->currentStep+1))) {
            $this->session->currentStep = $session->currentStep+1;
            $this->redrawControl();
        }

    }


    public function render()
    {
        $template = $this->template;
        $template->setFile(__DIR__ . '/StepForm.latte');

        $template->steps = $this->steps;
        $template->menu = $this->menu;
        $template->currentStep = $this->session->currentStep;

        $template->render();
    }

    protected function isRange($position)
    {
        if ($position <= count($this->menu)) {
            if ($position > 0) {
                return true;
            }
        }

        return false;
    }

}

?>

v templatě pak mám:

<div class="row">
    {snippet flashes}
		//flashes..
    {/snippet}
</div>

{snippet menu}
    <div class="row steps_box">
        {foreach $menu as $key=>$step}
            <a class="ajax" n:href="Step! $key">
                <div class="step_box {if $key<=$currentStep}active{/if}">{$step}</div>
            </a>
        {/foreach}
    </div>
{/snippet}

<div class="row">

    {snippet step}
    {form form class=>'ajax'}

    {var $group = $steps[$currentStep]}
        <fieldset>
            <legend>{$group->getOption('label')}</legend>

            {foreach $group->controls as $item}
                <div class="form-group>
                    {$item->label}
                    {$item->control}
                </div>
            {/foreach}

        </fieldset>
    {/form}
    {/snippet}

</div>

a v presenteru tohle:

protected function createComponentStepForm()
{
    $form = new Model\FormModelParser();

    $stepForm = new StepForm('userRegistration',$form,$this->session);
    $stepForm->onFinish[] = [$this,'saveStepForm'];
    return $stepForm;
}


public function saveStepForm($values){
    dump($values);
		//zde už mám všechny data z formuláře ...
}

Je to má první komponenta, takže budu opravdu rád za každou krtiku, nápad či pomoc :) díky všem.

Editoval kleinpetr (29. 3. 2015 18:58)

kleinpetr
Člen | 480
+
0
-
  • A poslední otázka je, jak validovat form při posílání ajaxem, protože v tu chvíly je netteForms.js k ničemu.
iNviNho
Člen | 352
+
0
-

Dovoľ mi ti zložiť kompliment, vyzerá to super :)

kleinpetr
Člen | 480
+
0
-

To jako fakt ? :D mě to spíš přijde takový nepřehledný, jakoby to potřebovalo trochu zoptimalizovat…