Jak jsem si chtel vytvorit komponenticku

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

Zdravim, s Nette se zatim moc nekamaradim, ale v ramci zlepsovani, jsem se udelal takovej malej formularik alias komponentu..

<?php
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of AddStatus
 *
 * @author simekadam
 *
 */
namespace Components;

use Nette\Application\AppForm;
use Nette\Forms\Form;

class AddStatus extends \Nette\Application\Control{
    //put your code here
    public $form;
    public function __construct($parent, $name) {
        parent::__construct($parent, $name);
        $form = new AppForm($this, 'form');
        $form->addText('status', "Whats on your mind man?")
                ->addRule(Form::MAX_LENGTH, "Maximum length is %d characters",150)
                ->addRule(Form::FILLED, "You have to post something,but remember can not send empty post!!");
        $form->addSubmit('post', "Post your thoughts");
    }


    public function render()
        {
                $template = $this->template;
                $template->form=$this->form;
                $template->setFile(dirname(__FILE__) . '/statusForm.latte');
                $template->render();
        }

//    public function createComponentAddStatusForm($name) {
//
//    }
}
?>

tady je jeho layout

{control form begin}
{control form errors}
{!$form['post']->label}
{!$form['post']->control}
{!$form['post']->control}
{dump $form}
{control form end}

Takto ji pak vytvarim v presenteru

public function  createComponentAddStatusForm($name) {
        $addStatusForm = new AddStatus($this,'addStatusForm');
    }

a nakonec v sablone mam {control addStatusForm}
Trvalo mi celkem dlouho nez jsem to nejak nabastlil..Potiz je, ze to nefunguje. Respektive v kodu mam formular, ale nejsou tam ty prvky vevnitr..Kdyz dumpuju promenou form ze sablony komponenty, tak je NULL..Ale pritom v metode render() v komponente ji nastavuju..Aspon doufam:)Neviote nekdo,kde je v tom chyba?A jestlli to treba taky neni uplne totalne spatne?Diky

Mozna by se hodilo dodat, ze komponenta je v app/components/AddStatus.php, jeji sablona v ty stejny slozce..Ale v tom asi chyba nebude..N

Editoval simekadam (23. 12. 2010 11:42)

Quinix
Člen | 108
+
0
-

V konstruktoru nahraď $form za $this->form :-)

Filip Procházka
Moderator | 4668
+
0
-

Takhle to vypadá líp ne?

namespace Components;

use Nette;
use Nette\Application\AppForm;

class AddStatus extends Nette\Application\Control
{

	public function render()
        {
		$this->template->form = $this['form'];
		$this->template->setFile(dirname(__FILE__) . '/statusForm.latte');
		echo $this->template;
        }

	protected function createComponentForm($name)
	{
		$form = new AppForm($this, $name);

		$form->addText('status', "Whats on your mind man?")
                	->addRule(AppForm::MAX_LENGTH, "Maximum length is %d characters",150)
                	->addRule(AppForm::FILLED, "You have to post something,but remember can not send empty post!!");
        	$form->addSubmit('post', "Post your thoughts");

		return $form;
	}
}

jinak, doporučoval bych kouknout se na tohle: https://gist.github.com/627987 je to velice šikovné přesně na tohle :)

Editoval HosipLan (23. 12. 2010 12:46)

simekadam
Člen | 36
+
0
-

Tak kod od HosipLan slape jak po masle…Ale mam teda nekolik otazek:)co je to $this['form']??Kam presne v tomhle pripade ukazuje $this..Na instanci AddStatus, ne?Proste nejak mi chybi v hlave to spojeni od new AddStatus v presenteru az po echo $this->template..to jako $this['form'] automaticky zavola createComponent?nebo to je tak, ze to jede postupne od sablon a zacne si to vytvaret komponenty a vzdycky kdyz najede do nejaky tridy, tak tam zavola potrebny createComponent?Tak nejak me to zmatlo tohle..Plus teda i to echo na konci:) ----Tak metoda render() dela to samy..:D uff

Ale jeste jsem se chtel zeptat. Je nekde nejakej peknej popis jak odchytavat Nette chybovy hlasky (formularovy) a vypisovat si je jak chci ja?Zvlast, kdyz to pojede pres ajax. No a kdyz jsem u toho javascriptu..Nejede mi tam standarnde validace na klientovi?Pro to je potreba nejakej plugin?Mam teda Nette 2, kde by mely byt v tomhle zmeny, ale nejak jsem nikde nenasel moc jaky:D Ja teda jsem skoro radsi.Stejne bych se tam asi pokusil nejak nacpat neco typu jQuery form validator apod..Ale divim se, ze to nic nedela..Jinak diky moc, mam tedka na nauceni Nette asi dva dny, tak jedu takovej rychlokurz:)

Editoval simekadam (23. 12. 2010 15:23)

Filip Procházka
Moderator | 4668
+
0
-

moc otázek vedle sebe nevím na co mám odpovídat dřív :)

ad továrničky

V nette se používají magické funkce createComponent na vytvoření komponenty v komponentě (i Presenter je komponenta, protože je potomkem Control). Zjednodušeně to funguje tak, že PresenterComponent implementuje \ArrayAccess, ten dovoluje k objektům přistupovat jako k poli

$control['nejakaKomponenta']; // z venku
$this['nejakaKomponenta']; // ze vnitřku

\ArrayAcces ti při tomto přístupu volá tyhle čtyři metody, podle typu přístupu (čtení, zápis, kontrola existence, smazání), které implementuje PresenterComponent, má v nich vytváření volání a vracení komponent, které obsahují potomci této třídy. Komponenty se vytváří z metody ComponentContainer::createComponent(), které předá jméno z toho klíče (nejakaKomponenta), v této metodě je trochu magie a ona se koukne jestli existuje metoda, které se jmenuje createComponentNejakaKomponenta (ano to první písmenko automaticky zvětšuje, je proto konvence ho psát malým když komponentu volám a velkým ve jménu funkce). Této metodě se říká továrnička, volá se jen jednou a až v ní vytvoříš svoji komponentu, ta se uloží v ComponentContainer a vždy se vrací jedna a ta samá instance.

Čili tohle by byly ve zkratce továrničky a komponenty :)

ad (string) $this->template;

Třída může implementovat magickou metodu __toString(), nebo její další sourozence a každá má speciání význam. __toString() se volá pokud zavoláš nad objektem přetypování na string (string)$objekt;, nebo ho vypíšeš echo $objekt;, nebo ho dáš do řetězce $var = "neco".$objekt;

validace formulářů

Tohle je téma věčných diskuzí, David nám sliboval nové formuláře, kde by to už snad mělo být vyřešené hezčeji, ale protože jsme se všichni, kromě pár vyjímek, vysrali na dokumentaci, David se do ní pustil sám a formuláře se odkládají.

Ale prozatím můžeš použít

// vlastní validátory
$form->onValidate[] = 'MujCoolValidator::validate';

// validovat až po odeslání
$form->onSubmit[] = array('FormSubmitted'); // tohle je pro zjednodušení, nechce se mi kvůli ukázce psát třída
function FormSubmitted($form)
{
	$values = $form->getValues();
	if (strlen($values['password']) < 6) {
		$form->addError('Heslo musí být dlouhé alespoň 6 znaků!');
	}
}

// nebo použít nějaké 3rdParty řešení, třeba Symfony, ale to nevím jestli bych ti doporučoval

Co se týče předávání ajaxu, nevidím v tom problém, najdi si tady na fóru, nebo v dokumentaci jak to funguje, nebo jak to vyřešit. Řešilo se to milionkrat. Já někam spěchám jinak bych ti to možná i napsal :P

Filip Procházka
Moderator | 4668
+
0
-

jo a

{control $form begin}
{control $form errors}
{$form['post']->label}
{$form['post']->control}
{$form['post']->control}
{control $form end}

když už si to předáváš do templaty, tak ty proměnné využij :)

simekadam
Člen | 36
+
0
-

Huste huste diky moc!To bude poctenicko:)Zkouskovy se hrouti:D

mlha
Člen | 58
+
0
-

Ohledně formulářů mám taky několik otázek. Vytvořil jsem si komponentu obalující AppForm.
Pochopil jsem (případně mě opravte), že život komponenty formuláře je asi následující:

  1. vytvoření
  2. zpracování signálů
  3. validace a zpracování onSubmit

V kroku 1) často řeším složitější logiku obsahu formuláře (zobrazení a naplnění polí).

Problém č. 1) identifikace odesílacího tlačítka:
neexistuje nějaká varianta $btn->isSubmittedBy(), která by ale strikně informovala o tom, zda byl formulář odeslán konkrétním tlačítkem?

Problém č. 2)
Pokud nechci v kroku 1), aby došlo ke kroku 3) (protože byl formulář odeslán nějakým pomocným tlačítkem modifikujícím formulář), musím zavolat $form->setSubmittedBy().
Tím se ale formulář chová jako neodeslaný, což má vliv například na následné volání $form[‚item‘]->setDefaultValue(‚xx‘);
Neexistuje nějaká alternativa $form->setSubmittedBy(), která by „jen“ zamezila validaci a onSubmit formuláře, ale formulář by ponechala v „původním (odeslaném) stavu“?

Problém č. 3) setDefaultValue
Fungování této metody je závislé na stavu odeslání formuláře. Pokud do formuláře vložím nějaký prvek dodatečně (po 1. odeslání), nebude nad tímto prvkem metoda nic platná. Leda, že bych před tím zavolal $form->setSubmittedBy(), ale pak to zase ovlivní hodnoty ostatních již odeslaných prvků.

Problém č. 4) příjem signálu
Už když vytvářím komponentu bych potřeboval vědět v jakém je stavu, ale zpracování změny stavu (signal) je až poté. Tady dělám zřejmě chybu už v návrhu.

Předem díky za pomoc.

Editoval mlha (17. 1. 2011 11:12)

bojovyletoun
Člen | 667
+
0
-
  • Form::submittedBy
  • SubmitButton::setvalidationscope(bool- false)
  • nevim
  • jaké stavy? issubmitted()
  • PS: podívej se na Form::fireevents, tam je to pěkně vysvětlené
Filip Procházka
Moderator | 4668
+
0
-

fireEvents bych moc nekuchal…

protected function createComponentFormular($name)
{
	$form = new Nette\Application\AppForm($this, $name);

	$form->addText(...
	// definice

	if (!$form->isSubmitted()) {
		$this->setDefaults($this->model->find($this->idZaznamuKteryEdituji));

		// tuto operaci je obecně lepší a doporučované přesunout do action presenteru
		// $this['formular']->setDefaults(...
	}

	if ($form['tlacitko']->isSubmittedBy()) {
	 	// udelej neco
		dump($form->getValues());
	}

	// lépe - vykoná se pouze,
	// pokud je formulář odeslán a pouze pokud je validní
	$form->onSubmit[] = callback($this, 'FormularSubmitted');

	// kliknutí na specifické tlačítko, opět se vykoná pouze,
	// pokud je formulář odeslán a pouze pokud je validní
	$form['tlacitko']->onClick[] = callback($this, 'TlacitkoClicked');

	// pokud je formulář nevalidní tak se stránka obnoví
	// a nebude se prováděť žádná událost onNěco

	return $form;
}

public function FormularSubmitted(Nette\Application\AppForm $form)
{
	// zpracování
	dump($form->getValues());
}

public function TlacitkoClicked(Nette\Form\IFormControl $control)
{
	// zpracování
	dump($control->getForm()->getValues());
}

Editoval HosipLan (17. 1. 2011 18:33)

dakota
Člen | 148
+
0
-

HosipLan napsal(a):

Len malá otázka. Je správne volať tieto metódy

if (!$form->isSubmitted())
if ($form['tlacitko']->isSubmittedBy())

v createComponentForm()? Nikdy som ich v nej zatiaľ nepoužil. Je tam síce:

$form = new Nette\Application\AppForm($this, $name);

Teoreticky, teraz to nie je možné, bolo by to k niečomu dobré?

$form->onNotSubmit[] = callback($this, 'FormularNotSubmitted');

Editoval dakota (19. 1. 2011 17:36)

Filip Procházka
Moderator | 4668
+
0
-

To je dobrá otázka, je to továrna a jako taková by ti měla poskládat komponentu. Osobně bych použil handlery onSubmit, onClick a popřípadě onInvalidSubmit a tyto metody vůbec nevolal.

tvoje onNotSubmit by jsi využil k čemu? Pokud chceš formulář plnit daty, je nejlepší použít metodu $form->isSubmitted() v action

public function actionDefault($id)
{
	if (!$this['formular']->isSubmitted()) {
		$data = $this->model->find($id);
		$this['formular']->setDefaults($data);
	}
}

Editoval HosipLan (19. 1. 2011 17:39)

dakota
Člen | 148
+
0
-

K onSubmit ja by som bol za premenovanie v Nette na onValidSubmit pretože to je správnejšie – ak bol formulár odoslaný a validný.

Editoval dakota (19. 1. 2011 18:19)

dakota
Člen | 148
+
0
-

HosipLan napsal(a):
tvoje onNotSubmit by jsi využil k čemu? Pokud chceš formulář plnit daty, je nejlepší použít metodu $form->isSubmitted() v action

Ak sa majú formuláre lazy vytvárať tak k plneniu dát – bez použitia v action. Ale je to len teoretická úvaha.

Editoval dakota (19. 1. 2011 17:41)

dakota
Člen | 148
+
0
-

onNotSubmit – mal som namysli niečo také:

public function onFormNotSubmitted(Nette\Application\AppForm $form)
{
	if ($this->action == 'edit') {
		$form->setDefaults($this->article);
	}
}
Filip Procházka
Moderator | 4668
+
0
-

To je ale z deště pod okap, řešilo se to na chatu, řešilo se to nejspíš i někde na fóru a shodli jsme se, že nejlepší je plnit komponenty v akci, samozřejmě si to dělej jak chceš, ale tohle je doporučovaný postup.

dakota
Člen | 148
+
0
-

HosipLan napsal(a):

To je ale z deště pod okap, řešilo se to na chatu, řešilo se to nejspíš i někde na fóru a shodli jsme se, že nejlepší je plnit komponenty v akci, samozřejmě si to dělej jak chceš, ale tohle je doporučovaný postup.

Ok. Data plním v action. To že sa to už na fóre riešilo som nevedel.