Vlastni FormRenderer a stale sa pouziva DefaultFormRenderer

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

Co je zle na tomto? Nastavim setRenderer, ale napriek tomu sa stale pouziva DefaultRenderer.

$renderer = (new \Nextras\Forms\Rendering\Bs3FormRenderer);
$form->setRenderer($renderer);
Šaman
Člen | 2666
+
+2
-

Na tomto nic špatného není, jen ty závorky jsou zbytečné. Chyba bude jinde.

steelbull
Člen | 241
+
0
-

jj, tak musim hladat problem inde :-(

steelbull
Člen | 241
+
0
-

Šaman napsal(a):

Na tomto nic špatného není, jen ty závorky jsou zbytečné. Chyba bude jinde.

Novy objekt sa vytvori, ale ani funkcia init() sa nezavola :-(

<?php
/**
 * This file is part of the Nextras community extensions of Nette Framework
 *
 * @license    New BSD License
 * @link       https://github.com/nextras/forms
 * @author     Jan Skrasek
 */
namespace TestUI\Helpers;

use Nette\Forms\Rendering\DefaultFormRenderer;
use Nette\Forms\Controls;
use Nette\Forms\Form;
use Nette;
use Nette\Utils\Html;
/**
 * FormRenderer for Bootstrap 3 framework.
 * @author   Jan Skrasek
 * @author   David Grudl
 */
class Bs3FormRenderer extends DefaultFormRenderer
{
    /** @var Controls\Button */
    public $primaryButton = NULL;
    /** @var bool */
    private $controlsInit = FALSE;
    public function __construct()
    {
        $this->wrappers['controls']['container'] = NULL;
        $this->wrappers['pair']['container'] = 'div class=form-group';
        $this->wrappers['pair']['.error'] = 'has-error';
        $this->wrappers['control']['container'] = 'div class=col-sm-9';
        $this->wrappers['label']['container'] = 'div class="col-sm-3 control-label"';
        $this->wrappers['control']['description'] = 'span class=help-block';
        $this->wrappers['control']['errorcontainer'] = 'span class=help-block';
    }

    public function init() {
        die();
    }



    public function renderBegin()
    {die();
        $this->controlsInit();
        return parent::renderBegin();
    }
    public function renderEnd()
    {die();
        $this->controlsInit();
        return parent::renderEnd();
    }
    public function renderBody()
    {die();
        $this->controlsInit();
        return parent::renderBody();
    }
    public function renderControls($parent)
    {die();
        $this->controlsInit();
        return parent::renderControls($parent);
    }
    public function renderPair(Nette\Forms\IControl $control)
    {die();
        $this->controlsInit();
        return parent::renderPair($control);
    }
    public function renderPairMulti(array $controls)
    {die();
        $this->controlsInit();
        return parent::renderPairMulti($controls);
    }
    public function renderLabel(Nette\Forms\IControl $control)
    {die();
        $this->controlsInit();
        return parent::renderLabel($control);
    }
    public function renderControl(Nette\Forms\IControl $control)
    {die();
        $this->controlsInit();
        return parent::renderControl($control);
    }
    private function controlsInit()
    {die();
        if ($this->controlsInit) {
            return;
        }
        $this->controlsInit = TRUE;
        $this->form->getElementPrototype()->addClass('form-horizontal');
        foreach ($this->form->getControls() as $control) {
            if ($control instanceof Controls\Button) {
                $markAsPrimary = $control === $this->primaryButton || (!isset($this->primary) && empty($usedPrimary) && $control->parent instanceof Form);
                if ($markAsPrimary) {
                    $class = 'btn btn-primary';
                    $usedPrimary = TRUE;
                } else {
                    $class = 'btn btn-default';
                }
                $control->getControlPrototype()->addClass($class);
            } elseif ($control instanceof Controls\TextBase || $control instanceof Controls\SelectBox || $control instanceof Controls\MultiSelectBox) {
                $control->getControlPrototype()->addClass('form-control');
            } elseif ($control instanceof Controls\Checkbox || $control instanceof Controls\CheckboxList || $control instanceof Controls\RadioList) {
                if ($control->getSeparatorPrototype()->getName() !== NULL) {
                    $control->getSeparatorPrototype()->setName('div')->addClass($control->getControlPrototype()->type);
                } else {
                    $control->getItemLabelPrototype()->addClass($control->getControlPrototype()->type . '-inline');
                }
            }
        }
    }
}
steelbull
Člen | 241
+
0
-

…a este – formular je potomkom UI\Control…

Unlink
Člen | 298
+
+1
-

A prečo by sa mala volať?

Volá sa metoda render()

steelbull
Člen | 241
+
0
-

@Unlink mas pravdu, zabudol som pridat:

public function render(\Nette\Forms\Form $form, $mode = NULL) {
    die();
}

…ale ani ta sa nezavola :-(

Unlink
Člen | 298
+
+1
-

A ako to používaš, ono tá časť kódu čo si dal je OK, skús poslať viac, možno celú create component metódu, lebo ako písal @Šaman chyba bude niekde inde.

David Matějka
Moderator | 6445
+
+1
-

Jak ten formular renderujes?

Martk
Člen | 661
+
+1
-

Nevím, jestli ty tvoje kódy jsou jenom ukázkové, ale název třídy render se neshoduje s tvojí.

Nextras\Forms\Rendering\Bs3FormRenderer a TestUI\Helpers\Bs3FormRenderer

steelbull
Člen | 241
+
0
-

Jj, ukazkove, toto mam spravne. Poslem cely control… Vybral som nejaky z kratsich formularov.

<?php

use Nette\Application\UI,
    Nette\Forms\Form,
    App\Model;



class BrandFormFactory extends UI\Control {

    private $instance;
    private $context;
    private $translator;



    /**
     * Constructor
     * @param instance $instance
     * @param string $callback
     * @param \Kdyby\Translation\Translator $translator
     * @param \Nette\Database\Context $context
     */
    function __construct($instance, \Kdyby\Translation\Translator $translator, \Nette\Database\Context $context) {
        $this->instance = $instance;
        $this->context = $context;
        $this->translator = $translator;
    }



    /**
     * Create form
     */
    function createComponentForm() {

        // Create new instance
        $form = new UI\Form;

		// Tu som nastavil Renderer a nic :-(
        $form->setRenderer(new \AgileUI\Helpers\Bs3FormRenderer);

        $form->method = 'post';
        $form->getElementPrototype()->addAttributes(array('id' => 'BrandForm', 'class' => 'ajax'));

        $form->addText('title', $this->translator->translate('brands.form.title'))
                ->setAttribute('class', 'form-control')
                ->setRequired($this->translator->translate('brands.form.please_insert_the_title'));

        $form->addText('description', $this->translator->translate('brands.form.description'))
                ->setAttribute('class', 'form-control');

        $form->addHidden('id');

        $form->addProtection();


/*

Mimochodom, ako riesite Callbacky? Ked to mam takto, mam plny presenter callbackov, co nie je velmi cool

*/
        $form->onSuccess[] = array($this->instance, 'BrandFormSuccess');

        $form->onError[] = callback($this->instance, 'BrandFormError');

        return $form;
    }



    /**
     * Render
     */
    function render() {
        $template = $this->template;
        $template->setFile(__DIR__ . '/templates/BrandFormFactory.latte');
        $template->render();
    }

}



/**
 * Form interface
 */
interface IBrandFormFactory {



    /**
     * @return BrandFormFactory
     */
    function create($instance);
}
Azathoth
Člen | 495
+
+1
-

já píšu callback jsko např. $this->BrandFormSuccess a nette/object z toho přes ObjectMixin udělá callback na stejnojmennou metodu.

jiri.pudil
Nette Blogger | 1032
+
+1
-

Komponenta by neměla záviset na tom, že presenter implementuje nějaké konkrétní metody. Já mám zpracování formuláře přímo v té komponentě a stejně tak v ní mám vlastní událost, kterou právě při tom zpracování vyvolám, a obsluhu si na ni navěsím až v presenteru. Viz můj článek

Jan Mikeš
Člen | 771
+
0
-

Presun radek

$form->setRenderer(new \AgileUI\Helpers\Bs3FormRenderer);

Az nakonec toho jak mas nadefinovany formular, tesne nad

	return $form;

nebo callbacky, pisni jestli ti to pomohmo.

David Matějka
Moderator | 6445
+
+2
-

zeptam se znovu, jak ten formular vykreslujes v latte?

steelbull
Člen | 241
+
0
-

jiri.pudil napsal(a):

Komponenta by neměla záviset na tom, že presenter implementuje nějaké konkrétní metody. Já mám zpracování formuláře přímo v té komponentě a stejně tak v ní mám vlastní událost, kterou právě při tom zpracování vyvolám, a obsluhu si na ni navěsím až v presenteru. Viz můj článek

Jj, velmi pekne dakujem za tento pohlad. Sam som nad nim rozmyslal a tiez sa mi nepaci, ze mam v presenteri mnozsto metod na osetrenie formulara. Ale uvazoval som nad tym, ze budem chciet formular pouzit niekolko krat ako standardny formular a niekolko krat ako jaxovy modal window. A v tychto pripadoch budem vzdy redirectovat niekam inam.

Aj ked na druhej strane, target, kam presmerovat by bolo efektnejsie osetrit asi setterom, ci? Napada Ta ine riesenie?

steelbull
Člen | 241
+
0
-

Lexi napsal(a):

Presun radek

$form->setRenderer(new \AgileUI\Helpers\Bs3FormRenderer);

Az nakonec toho jak mas nadefinovany formular, tesne nad

	return $form;

nebo callbacky, pisni jestli ti to pomohmo.

Nepomohlo:

$form->onSuccess[] = array($this->instance, 'BrandFormSuccess');

$form->onError[] = callback($this->instance, 'BrandFormError');

// Set renderer
$form->setRenderer(new \AgileUI\Helpers\Bs3FormRenderer());

//Return rendered Form
return $form;
steelbull
Člen | 241
+
0
-

Lexi napsal(a):

Presun radek

$form->setRenderer(new \AgileUI\Helpers\Bs3FormRenderer);

Az nakonec toho jak mas nadefinovany formular, tesne nad

	return $form;

nebo callbacky, pisni jestli ti to pomohmo.

A skusal som aj pred callbacky aj za a nejde. Potom som skusal callbacky dat prec, ale tiez nepomohlo.

Editoval steelbull (27. 6. 2015 19:24)

steelbull
Člen | 241
+
0
-

David Matějka napsal(a):

zeptam se znovu, jak ten formular vykreslujes v latte?

Vykreslujem ho takto:

{form form}
<div class="form-group col-md-6">
	{label 'title' /}
	{input 'title'}
	<span class="form-error-message">{inputError 'title'}</span>
</div>
/*
.
.
.
.
*/
{/form}

Editoval steelbull (27. 6. 2015 19:05)

Šaman
Člen | 2666
+
+2
-

steelbull napsal(a):

David Matějka napsal(a):

zeptam se znovu, jak ten formular vykreslujes v latte?

Vykreslujem ho takto:

{form form}
{/form}

No, když ho vykresluješ ručně, tak se samozřejmě renderer neprojeví. Můžeš ho nechat buď vykreslit rendererem {control fooForm}, nebo ručně pomocí latte makra {form}{/form}. :D

steelbull
Člen | 241
+
0
-

:-( ano, ale DefaultRenderer sa stale pouziva. Preto ma ani nenapadlo, ze custom renderer nemozem pouzit. V tomto pripade potrebujem hromadne nastavit class pre vsetky napr. selectboxy a pouzit vlastny renderer vidim ako useful future. Bolo by to urcite lepsie, ako pri kazdej polozke formulara vzdy nastavovat setAttribute.

Šaman napsal(a):

steelbull napsal(a):

David Matějka napsal(a):

zeptam se znovu, jak ten formular vykreslujes v latte?

Vykreslujem ho takto:

{form form}
{/form}

No, když ho vykresluješ ručně, tak se samozřejmě renderer neprojeví. Můžeš ho nechat buď vykreslit rendererem {control fooForm}, nebo ručně pomocí latte makra {form}{/form}. :D

Šaman
Člen | 2666
+
+1
-

Zkus to rozchodit na ukázkovém formuláři na čistém sandboxu (nebo spiš web-projectu) a pošli odkaz na zdrojáky. Někde máš zakopanou chybu. A bude se špatně hledat, když nám ukazuješ zdrojáky po kouskách. Chyb tam teda máš víc, třeba komponenta není továrna, ale to jsou věci související s čitelností, ne s funkčností.

A jinak nehledáš teda spíš tohle?

steelbull
Člen | 241
+
0
-

Prave ze mam ako tovarnicku, Interface som neposielal. Obsahuje jednu metodu Create a Commenty v spravnom tvare. Komponentu mam zaregistrovanu v config neon a injectnutu do presentera. Vsetko funguje, len set Renderer nie. Zavesim zdrojak na GIThub.

Este budem mat asi viac otazok na formulare, ale zavesim do samostatnych vlakien.

Šaman
Člen | 2666
+
+1
-

Já mluvil o tomhle class BrandFormFactory extends UI\Control. Tohle není továrna, je to komponenta – potomek Control (která obsahuje továrničku na formulář, ale to už je interní věc té komponenty).

Jinak na tu otázku kam psát obsluhu událostí formuláře, tak do té komponenty.
Ale není problém si udělat opravdu jen továrnu na formulář (bez komponenty) a obsluhu mít také v ní.

Ale těm navěšeným callbackům v presenteru se úplně nevyhneš, protože většinou až presenter umí zpracovat flashmessage a hlavně rozhodnout, kam přesměrovat. Nemluvím teď o triviálním přesměrování na ten samý formulář, ale třeba po registraci chci nejspíš zobrazit jinou stránku – detail nového uživatele, nebo třeba výzvu k potvrzení registrace odkazem v emailu apod. Já mám nejčastěji zpracování dat u formuláře, ale přesměrování a flashmessage navěšuji až v presenteru (nebo komponentě).

Editoval Šaman (28. 6. 2015 9:05)

steelbull
Člen | 241
+
0
-

…a vytvorit vlastne setteri a v presenteri v createComponent setSuccessFlasMessage() a setSuccessRedirectTarget() je bad practise?

Šaman napsal(a):

Já mluvil o tomhle class BrandFormFactory extends UI\Control. Tohle není továrna, je to komponenta – potomek Control (která obsahuje továrničku na formulář, ale to už je interní věc té komponenty).

Jinak na tu otázku kam psát obsluhu událostí formuláře, tak do té komponenty.
Ale není problém si udělat opravdu jen továrnu na formulář (bez komponenty) a obsluhu mít také v ní.

Ale těm navěšeným callbackům v presenteru se úplně nevyhneš, protože většinou až presenter umí zpracovat flashmessage a hlavně rozhodnout, kam přesměrovat. Nemluvím teď o triviálním přesměrování na ten samý formulář, ale třeba po registraci chci nejspíš zobrazit jinou stránku – detail nového uživatele, nebo třeba výzvu k potvrzení registrace odkazem v emailu apod. Já mám nejčastěji zpracování dat u formuláře, ale přesměrování a flashmessage navěšuji až v presenteru (nebo komponentě).