data z dynamickeho formulara sa stracaju
- xr
- Člen | 94
zdravim
mam formular, do ktoreho dynamicky pridavam prvky. pridavaju sa rozne inputy podla kontextu. tieto nacitam ajaxovo a vkladam do formularu.
problem je v tom, ze do obsluznej funkcie sa mi tieto data nedostanu.
public function processEdit( AppForm $form ) {
if ( $form['save']->isSubmittedBy() ) {
$values = $form->getValues();
debug::dump($values);
debug::dump($_POST);exit;
...
POST obsahuje potrebne prvky, ale $values nie – ako je to mozne? kde sa data stracaju a ako sa tomu vyhnem?
okrem teda moznosti rucne si ich sosat z POSTu … resp. este su data
dostupne vo
$form->httpData
ale tahat ich odtial mi prijde rovnako suplikantske ako z POSTu.
dik za reakcie vopred
- xr
- Člen | 94
@22:
moja metoda spociva v tom, ze mam AsyncPresenter, ktory zostavi formular na
zaklade toho, co si uzivatel zada (moze pridavat rozne objekty, ktore
maju rozne inputy – text / radiobutton / chebbox atd), z neho si zoberiem
len vnutro (t.j. len samotne inputy) a tieto ajaxom nacitam a pridam priamo
pomocou jQuery do hlavneho formulara.
jednotlive inputy patriace jednemu objektu pomenuvam takto:
[nazov_objektu]_[nazov_inputu]
, cize podla prefixu
[nazov_objektu]
som schopny inputy rozdelit do skupin a potom
vytvarat model podla hidden inputu nesucim typ a takto ich spracovat.
napriklad ak teda pridavam dynamicky objekt s textovymi inputmi
title
a description
, tak do formulara pridavam input
tagy typu text s name atributom nastavenym na i123_title
a
i123_description
, kde i123
je unikatny
identofikator.
inak s tym obchadzanim bezpecnosti nette – je mozne na pole hodnot
inputov $dynamic
(viz moj predchadzajuci post) aplikovat validaciu
ineho formularu, ako toho hlavneho, ktory prave obsluhujem? t.j. toho, ktory
tieto inputy vytvara (v async prezenteri).
a tiez, ak mi niekto poradi lepsiu metodu, tak ju rad prijmem.
- Filip Procházka
- Moderator | 4668
Obcházíš bezpečnostní mechanizmus Nette. Správně je to:
- Uživatel otevře stránku s presenterem
- actionDefault()
- zavolá továrničku, která sestaví formulář
$this['myForm']
→createComponentMyForm()
- naplnění výchozích hodnot formuláře
->setDefaults($this->myModel->find($id))
- tento krok není nutný, pokud neplníš formulář výchozími daty
- zavolá továrničku, která sestaví formulář
- v šabloně vykreslíš formulář
{control myForm}
- uživatel vyplní data a odešle formulář
- actionDefault()
- zavolá se úplně to stejné co předtím, sestaví se stejný formulář a můžeš mít v akci i podmínku, abys zbytečně nevolal databázi kvůli výchozím datům
- signál na formulář
$presenter->getComponent('myForm')->handleSubmit()
- provede se automaticky
- naprosto stejně sestavený formulář ti příjme data co uživatel odeslal
- BEZPEČNOSTNÍ MECHANIZMUS !!!!
- provedou se tvoje události, kde máš k dispozici správné a všechny hodnoty
…
Takže ty vůbec nepotřebuješ šahat na nějaké httpData
, ty
MUSÍŠ sestavit formulář stejně jako byl při
vykreslování. To tvoje ajaxové cosi je celé špatně a radši to smaž a
nikdy nikomu neukazuj. Až ti někdo rozjebe aplikaci, protože jsi dělal
takové kotrmelce s ajaxem, tak nechoď brečet k nám.
Nic z toho co jsem popsal ti nebrání sestavovat dynamicky formuláře. Jenom to nebudeš dělat jako prasátko, ale sestavíš formulář, připojíš ho do presenteru a vykreslíš. Potom ho sestavíš znovu, úplně stejně a přijmeš data. Ale to už se opakuju :)
- Filip Procházka
- Moderator | 4668
Já nic neobcházím. To je několik různých věcí. Ty potřebuješ nadefinovat formulář a potřebuješ ho pak někde vypisovat. Jenom jsi zvolil jeden z nejhorších přístupů :)
- bazo
- Člen | 620
xr napsal(a):
no a ty zase obchadzas to, co sa snazim dosiahnut – ako zrekonstruujem formular, ktory si uzivatel sam naklika na front-ende ? mam X skupin inputov, ktore si moze lubovolne umiestnit a moze ich byt neobmedzeny pocet v lubovolnom poradi.
strukturu toho formulara si asi niekde ptom ukladas, nie? tak podla toho si to aj zrekonstruujes
- xr
- Člen | 94
nie, nic si neukladam. zakladny formular ma napevno zopar prvkov a ostatne sa do neho sukaju ajaxom. potom sa to posle cele a ja potrebujem dostat tie hodnoty.
ok, tak teraz otazka na expertov → ked mam pole s hodnotami, ktore som dostal nekalym sposobom, kazdu sadu hodnot vytvoril jeden formular, akurat sa z neho vykuchali vnutornosti a strcili do toho zakladneho. mozem teda nejakym sposobom spustit validaciu toho tovarnickoveho formularu ?
aby som tu len nekecal o nekonkretnych veciach…
toto je block presenter – block je ten zakladny prvok, ktory sa dynamicky
zvacsuje o nove prvky
public function createComponentEdit( $name ) {
$form = new AppForm($this, $name);
// $form->addDynamicContainer('fero');
foreach ( $this->setup->languages->codes as $lang ) {
$item = new \Model\BlockText($this->itemId, $lang);
$item->dbReload();
$form->addText($this->encodeLangTitle('title', $lang), $lang . ': ' . $this->tr('Title', 'title-tit'), 80, 128)
->setDefaultValue($item->title)
->addRule(Form::FILLED, $this->tr('...!', 'title-req'));
$form->addTextArea($this->encodeLangTitle('text', $lang), $lang . ': ' . $this->tr('Text', 'text-tit'), 80, 20)
->setDefaultValue($item->text);
}
$item = new \Model\Block($this->itemId);
$item->dbReload();
$form->addText('category', $this->tr('Category', 'category-tit'), 30, 3)
->setDefaultValue($item->category)
->addRule(Form::INTEGER, $this->tr('Category is of integral type!', 'category-req'));
$form->addText('unique', $this->tr('Unique descriptor', 'unique-tit'), 30, 3)
->setDefaultValue($item->unique)
->addRule(Form::FILLED, $this->tr('Fill in a unique block descriptor!', 'unique-req'));
$form->addCheckbox('display', $this->tr('Visible', 'visible-tit'))->setDefaultValue($item->display - 1);
$form->addSubmit('save', $this->tr('Save', 'save-btn'));
$form->addSubmit('back', $this->tr('Cancel', 'cancel-btn'))->setValidationScope(NULL);
$form->onSubmit[] = callback($this, 'processEdit');
}
toto je ta sporna metoda (handler submitu)
public function processEdit( AppForm $form ) {
if ( $form['save']->isSubmittedBy() ) {
$values = $form->getValues();
$dynamic = array_diff($form->httpData, $values);
unset($dynamic['save']);
// debug::dump($values);
// debug::dump($dynamic);
// debug::dump($_POST);exit;
// v dynamic mas dynamicky pridane prvky
// create a base model
$item = new \Model\Block($this->itemId);
$item->category = $values['category'];
$item->unique = $values['unique'];
$item->display = $values['display'] + 1;
$item->save();
$mutations = $this->decodeMultiLangInput($values);
foreach ( $mutations as $lang => $values ) {
$item = new \Model\BlockText($this->itemId, $lang);
$item->title = $values['title'];
$item->text = $values['text'];
$item->save();
}
$mutations = $this->decodeMultiLangInput($dynamic);
foreach ( $mutations as $lang => $values ) {
debug::dump($this->decodeItems($values));
// decodeItems vracia pole skupin parov hodnot z inputov
// array( 123 => array('text'=>'blablabla', 'obrazok'=>'/img/..'), 124 => ...)
// tu by sa podla typu mali vytvorit jednotlive modely, prekazdu skupinu jeden.
// naplnit a ulozit
}
exit;
$this->flashMessage($this->tr('Block modified.', 'block-midif'));
}
$this->redirect('default');
}
teraz toto je v Async presenteri
public function actionXY(){
...
$form = new Form();
$this->addItemInputs($form, $id, $number, $this->lang);
...
}
protected function addItemInputs( Form $form, $type, $number, $lang = null, $model = null ) {
$namePrefix = 'i' . sprintf('%03d', $number) . '_';
switch ( $type ) {
case \Model\Item::ITYPE_TEXT:
$this->setView('input_text');
$name = $namePrefix . 'text';
if ( $lang ) {
$name = $this->encodeLangTitle($name, $lang);
}
$comp = $form->addTextArea($name, $this->tr('Text', 'text-tit'), 80, 20);
if ( !is_null($model) ) {
$comp->setDefaultValue($model->text);
}
break;
case \Model\Item::ITYPE_IMAGE:
...
default:
$this->setView('empty');
exit;
break;
}
$name = $namePrefix . 'itype';
if ( $lang ) {
$name = $this->encodeLangTitle($name, $lang);
}
$form->addHidden($name, $type);
$name = $namePrefix . 'iorder';
if ( $lang ) {
$name = $this->encodeLangTitle($name, $lang);
}
$form->addHidden($name, $number);
return $form;
}
tak znova tu otazku – je mozne data ziskane z toho hlavneho forumlaru v obsluhe nejako zvalidovat cez takto vytvoreny formular v Async prezenteri ? ak ano – ako? pretoze neviem. dik za rady
- Filip Procházka
- Moderator | 4668
Já se snažím.. opravdu se snažím tě pochopit a pomoct ti… Ale píšeš moc abstraktně a ten kód mi moc neřekl, popravdě jsem ho prolétl a opravdu se mi to nechce studovat.
Jestli chceš vědět jak se to dělá nette-way, tak mi musíš konkrétně popsat, čeho se snažíš dosáhnout. Protože jsem to do teď nepochopil.
- Filip Procházka
- Moderator | 4668
Pokud dáš do formuláře prvek, třeba
$form->addContainer('neco')->addContainer('tamto')->addText('name', 'Jméno');
a v $_POST
bude
$_POST['neco']['tamto']['name'] = 'Lady Gaga';
Tak po připojení formuláře do presenteru bude
$form->values['neco']['tamto']['name'] === 'Lady Gaga'
I pokud budeš po připojení formuláře do presenteru přidávat další políčka, tak se automaticky bude načítat jejich hodnota.
Ale pokud budeš formulář sestavovat na základě $_POST
a né
na základě nějaké struktury, nebo uložených metadata v nějakém
nastavení, tak je to kontraproduktivní a zbytečné, protože by si tam
uživatel zase mohl naflákat co chce.
- Ani
- Člen | 226
Udělej si signál, který ti na základě požadavku uloží třeba do session, co se má do formuláře přidat.
V továrně toho formuláře koukni do session a jestli tam něco je, tak to hned v té továrně přidej do formuláře.
Zpracovat to pak můžeš normálně.
Tohle co tu máš je velká divočina :D
- frosty22
- Člen | 373
Napadlo mě, zda-li by nebylo možné, aby se dosadili přijaté hodnoty ještě před validací a v případě invalidace, by se ty dané hodnoty vyhodily, což by umožnilo i ony dynamicky závislé formulářové prvky. Akorát si nejsem jist, zda-li by nemohlo dojít k bezpečnostním problémům, když by asi nemělo. Uvedu na příkladě:
<?php
protected function createComponentFooForm()
{
$form = new Form;
$items = $db->category()->fetchPairs(...);
$form->addSelect("category", "Kategorie:", $items)
->setDefault(key($items)); // nastavení výchozí hodnoty první kategorie např.
$items = $db->subcategory()->where("category_id = ?", $form["category"]->value)->fetchPairs(...);
$form->addSelect("subcategory", "Podkategorie:", $items);
...
return $form;
}
?>
V tomto případě, pokud by formuláře prvotně naplnili přijatými hodnotami elementy a až následně je validovali, tak by to prošlo:
- Odešle se formulář
- Přijme se signál
- Přidá se element category a rovnou se zvaliduje, pokud je OK tak hodnota už se naplní, pokud není OK, tak se odstraní
- Zavolá se dotaz na podkategorie s již nově přijatým ID kategorie, čili se naplní korektně a validací projde
…
Aktuálně je zde problém, že se prvně složí celý formulář a až následně se validují elementy, čili se složí s tím, že ve $form[„category“]->value bude vždy výchozí hodnota a tím pádem, už se nenaplní onen závislý select korektními daty (pouze v případě stejné kategorie).
Snad si rozumíme, ale myslím si, že takto by to nemuselo být špatné řešení. Bohužel jsem zatím přímo neprošel, jak funguje vnitřně onen Forms/Container a Forms/Form, takže možná plácám kraviny.
Editoval frosty22 (31. 7. 2011 13:21)