Jak jsem si chtel vytvorit komponenticku
- simekadam
- Člen | 36
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)
- Filip Procházka
- Moderator | 4668
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
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
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
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 :)
- mlha
- Člen | 58
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í:
- vytvoření
- zpracování signálů
- 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
- 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
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
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
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
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)
- Filip Procházka
- Moderator | 4668
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
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.