Nahrávání RadioListu AJAXove podle vyberu
- cuga
- Člen | 210
Zkusil jsem vyuzit threade „Spojení formulářů s AJAXem“, kde David popisuje, jak na to, ale moc uspesny sem nebyl.
Nevim jak pak dostat druhy RadioList, ktery se nacte na zaklade prvniho vybraneho.
V presenteru mam
$form->addGroup('Způsob dodání');
$form->addRadioList('shipping','', $shipping->getShipping()->select('*')->fetchPairs('id','title'));
$form->addGroup('Způsob platby');
$form->addRadioList('payment','');
$form['shipping']->getControlPrototype()
->onchange('loadBox(1, this.value);');
$form['payment']->getControlPrototype()
->onchange('loadBox(2, this.value);');
...
if ($form->isSubmitted()) {
// teprve nyni dosadime hodnoty
$form['payment']->setItems( ... tady netusim co hodit ...);
if ($form->isValid()) {}
} else {
$form['payment']->setDisabled();
$form['submit1']->setDisabled();
}
v sablone mam
<script type="text/javascript">
function loadBox(phase, value)
{
if (phase === 1) {
// zvolena hodnota prvniho select boxu
$('#frmform-submit1').attr('disabled', true);
// natáhne obsah druhého selectboxu pomocí AJAXu
$.get("?do=loadData", {"value": value, "phase": phase}, function(data) {
$('#frmform-payment').parent().html(data);
});
} else if (phase === 2) {
$('#frmform-submit1').attr('disabled', false);
}
}
</script>
{$form}
a pak jeste handler
public function handleLoadData($phase, $value) {
$form = $this->template->form;
$payment = new Payments();
if ($phase == 1) {
// naplníme select box prvky a vypíšeme na výstup
$form['payment']->setItems($payment->getPayments()->select(array('id','title'))->where('shippingId = %i',$value)->fetchPairs('id','title'));
$form['payment']->setDisabled(FALSE);
echo $form['payment']->getControl();
}
// konec zpracování
$this->terminate();
}
handler mi vrati spravne to co ma, ale uz nevim jak to dostat zpatky do toho formulare…
DOPLNENO: a jeste by me zajimalo, jak docasne do te druhe skupiny napsat „Vyberte způsob platby“. Jakmile by uzivatel vybral způsob, text by se vyhodil a misto nej by byl pozadovany RadioList… diky
Editoval cuga (16. 5. 2009 16:13)
- nAS
- Člen | 277
Podívej se třeba na tento příklad. Jde o to, že bys měl vyrenderovat rovnou vše a nepotřebné věci skrýt. A poté po kliknutí pouze zobrazit konkrétní část a ne načítat AJAXem. Takhle ti aplikace bude fungovat (i když méně komfortně) i bez JavaScriptu a vyhneš se časovému zdržení při AJAXovém požadavku.
- cuga
- Člen | 210
to nAS:
hmmm, krome toho, ze se mi to nepodarilo rozchodit, je taky problem, ze nevim,
jak vytahnout z jednoho radiolistu aktualni hodnotu a podle toho odkryt
pozadovany div…
zkusil sem to takhle:
$form->addGroup('Způsob dodání');
$sub = $form->addContainer('shipping');
foreach($shipping->getShipping()->select('*')->fetchPairs('id','title') as $id => $title) {
$sub->addRadioList('shipping'.$id,'', array($id => $title))
->addRule(Form::FILLED, 'Vyberte způsob dodání')
->addCondition(Form::FILLED, TRUE) // conditional rule: if is checkbox checked...
->toggle('paymentBox'.$id); // toggle div #sendBox
}
$form->addGroup('Způsob platby');
$sub = $form->addContainer('payment');
foreach($payments->getPayments()->select('shippingId')->toFluent()->setFlag('DISTINCT')->fetchAll() as $row) {
$form->addGroup()
->setOption('container', Html::el('div')->id('paymentBox'.$row->shippingId));
$sub->addRadioList('payment'.$row->shippingId,'', $payments->getPayments()->select('*')->where('shippingId = %i',$row->shippingId)->fetchPairs('id','title'))
->addRule(Form::FILLED, 'Vyberte způsob platby');
}
Aaaakorat, ze diky tomu mam vic radiolistu, takze muzu vybrat zaroven dva druhy dopravy i dva zpusoby platby…
- nAS
- Člen | 277
Třeba takhle:
// Shipping type
$shipping = $form->addRadioList('shipping', 'Shipping type', array('plane' => 'by plane', 'bus' => 'by bus'));
$shipping->addCondition(Form::EQUAL, 'plane')
->toggle('planeBox');
$shipping->addCondition(Form::EQUAL, 'bus')
->toggle('busBox');
// group Plane
$form->addGroup()
->setOption('container', Html::el('div')->id('planeBox'));
$form->addText('planeNum', 'Plane Number', 35);
// group Bus
$form->addGroup()
->setOption('container', Html::el('div')->id('busBox'));
$form->addText('busNum', 'Bus Number', 35);
- phx
- Člen | 651
Vcera jsem ten ajax resil taky a problem je v tom, ze to co pouzivas posila HTML fragment NEobaleny v JSON. Pokud jsi jeste nacetl neco takovehoto tak vsechny prichozi pozadavky v AJAX jsou ocekavany v JSON coz ty nemas. Takze to nenacti a je to vyresene:)
Vcera mi to trvalo asi hodinu nez jsme to vyresil:)
Asi by to chtelo aktualizovat onen https://forum.nette.org/…aru-s-ajaxem nebo dovysvetlit problem s JSON. Ja na to nemam znalosti – zaitm.
- dotTwelve
- Člen | 167
Tak nakonec jsem to rozpohyboval (pozadavek totiz skoncil pri volani neexistujici funkce spinner() – casem dopisu), ale nenacitaji se mi hodnoty do druheho selectboxu:
Mam to takto:
<?php
if ($form->isSubmitted())
{
// teprve nyni dosadime hodnoty
$form['mesto']->setItems( ... );
if ($form->isValid()) {
}
} else {
$form['mesto']->setDisabled();
$form['submit1']->setDisabled();
}
?>
Tady nevim co mam dosadit za hodnoty i kdyz dam napr $form[‚mesto‘]->setItems(array(1 ⇒ ‚hodnota1‘)); tak se mi toto pole nenacte.
Dale mam funkci loadBox()
<script type="text/javascript">
function loadBox(phase, value)
{
if (phase === 1) {
// zvolena hodnota prvniho select boxu
$('#frmregistraceForm-submit1').attr('disabled', true);
// zobrazi symbol, že se něco načítá
//spinner();
// natáhne obsah druheho selectboxu pomocí AJAXu
$.get("?do=loadData", {"value": value, "phase": phase}, function(data) {
$('#frmregistraceForm-mesto').parent().html(data);
});
} else if (phase === 2) {
// zvolena hodnota druheho select boxu, povolí tlačítko submit
$('#frmregistraceForm-submit1').attr('disabled', false);
}
}
</script>
handler je takovyto:
<?php
public function handleLoadData($phase, $value)
{
$form = $this->template->form;
$data = new Database();
if ($phase == 1) {
// naplníme select box prvky a vypíšeme na výstup
$form['mesto']
->setItems($data->getMesta()->select(array('id', 'nazev'))->where('kraj = %s', $value)->orderBy('nazev')->fetchPairs('id', 'nazev'));
$form['mesto']->setDisabled(FALSE);
echo $form['mesto']->getControl();
}
// konec zpracování
$this->terminate();
}
?>
Editoval dotTwelve (24. 6. 2009 18:12)
- dotTwelve
- Člen | 167
Druhy SELECTbox se mi v pozadi nacte, s tim ze:
<select onfocus="this.onmousewheel=function(){return false}" onchange="loadBox(2, this.value);" name="mesto" id="frmregistraceForm-mesto"><option value="646">ADAMOV</option>
atd...
Jenze po vybrani kraje v prvnim selectu se skryje druhy select a uz se nezobrazi…
Kde muze byt chyba? :-(
Ztroskota mi to na funkci echo:
<?php
echo $form['mesto']->getControl();
?>
Editoval dotTwelve (26. 6. 2009 12:32)
- cuga
- Člen | 210
aha :) no problem je v tom, ze kdyz pouzijes ten jquery kod, tak ti Handler vraci vysledky v JSONu, ale s tim navod v tom druhe threadu nepocita, takze to nebude fungovat…
kdyz ho nepouzijes (tzn. nedas do <head> tag <script … /> tak ti to bude vracet HTML a melo by to byt v cajku…
- dotTwelve
- Člen | 167
problem je v tom, ze jelikoz pouzivam i datagrid, tak mam v hlavicce spoustu tagu <script>
<!-- jQuery -->
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="http://jqueryui.com/latest/ui/ui.core.js"></script>
<script type="text/javascript" src="http://jqueryui.com/latest/ui/ui.datepicker.js"></script>
<script type="text/javascript" src="/0.1/document_root/js/jquery.livequery.js"></script>
<!-- custom JS -->
<script src="/0.1/document_root/js/jquery.nette.js" type="text/javascript"></script>
<script src="/0.1/document_root/js/datagrid.js" type="text/javascript"></script>
<script src="/0.1/document_root/js/form.js" type="text/javascript"></script>
tak a ted kterej vyhodit?
- dotTwelve
- Člen | 167
Tak uz mi to funguje, akorat problem nastava pri vyberu jine, nez prvni
polozky v prvnim select boxu.
Prvni polozka posila:
Date Wed, 29 Jul 2009 12:23:24 GMT
Server Apache
X-Powered-By Nette Framework
Expires Mon, 23 Jan 1978 10:00:00 GMT
Cache-Control s-maxage=0, max-age=0, must-revalidate
Pragma no-cache
Set-Cookie PHPSESSID=928b10a40fded10dfee37d4921d4b5384b9e735c; path=/; httponly
nette-browser=0.068650825888999; path=/; httponly
Content-Length 222
Keep-Alive timeout=15, max=96
Connection Keep-Alive
Content-Type application/json
zatimco ostatni polozky ze select boxu posilaji hlavicku
Date Wed, 29 Jul 2009 12:25:20 GMT
Server Apache
X-Powered-By Nette Framework
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Set-Cookie PHPSESSID=928b10a40fded10dfee37d4921d4b5384b9e735c; path=/; httponly
nette-browser=0.068650825888999; path=/; httponly
Vary Accept-Encoding
Content-Encoding gzip
Content-Length 12561
Keep-Alive timeout=15, max=100
Connection Keep-Alive
Content-Type text/html
Vidim zde problem v Content-Type. Mate nejaky napad jak rici vsem polozkam
pri vyberu v select boxu aby posilaly content-type: application/json?
Respektive to posila znova hlavicku, coz by asi nemelo…
Editoval dotTwelve (29. 7. 2009 16:46)
- MartinJanda
- Člen | 60
Tak Content-Type v hlavičce odezvy handleru změníš takto:
$response = Environment::getHttpResponse();
$response->setHeader('Content-type', 'application/json');
- MartinJanda
- Člen | 60
Problém má 2 řešení, buď pro danou stránku vynecháš:
<script src=„/0.1/document_root/js/jquery.nette.js“ type=„text/javascript“></script>
nebo tu komunikaci, resp. odpověď z handleru předěláš na json řetězec a potřebně upravíš.
Bohužel tomu rozumím dost málo, abych ti konkrétněji pomohl, ale třeba se někdo najde.
Ten ti vypíše ten HTML kód pro formulář.
Pořadí by mělo být:
- hlavička
- obsah
- v handleru musíš mít
$this->terminate();
Ještě se může stát, že z handleru ti to vrací chybu, tedy celou stránku s Debug výstupem, kde se hlavička už posílá. Nevím jestli používáš Firebug, ale tam by to bylo vidět.
Editoval romansklenar (30. 7. 2009 11:36)
- romansklenar
- Člen | 655
Pokud máš v InstitutionPresenter.php
na řádku 286
echo $form['mesto']->getControl();
tak čemu se potom divíš?
Nemá to tam co dělat. Ta hlavička se neposílá „znova“, tam kde ti to
řve by se měla hlavička odesílat poprvé, jenže tím echem už jsi poslal
něco na výstup…
EDIT: to už měsíc řešíš takovouto chybu?
- romansklenar
- Člen | 655
Vykreslovat formulář v šabloně, tam kde patří – echo v presenteru nemá co dělat.
- MartinJanda
- Člen | 60
A v jaké situaci vlastně ty selectBoxy chceš použít? Nebude
vhodnější použít jeden selectBox s větší hloubkou?
Jako že do addSelect nacpeš:
array(
'test' => 'test',
'test1' => 'test1',
'podtest' => array(
'test2' => 'test2',
'test3' => 'test3'
)
)
Pokud těch položek není stovka, tak to bude fungovat, bude to přístupnější a v konečném důsledku použitelnější, ne?
- dotTwelve
- Člen | 167
Prave ze je tam toho dost, jedna se totiz nejdriv o vyber kraje, pak vyber mesta, a pokud existuji mestske casti tak jeste treti select.
Cuga – presne tak, vzal jsem to z prikladu, kde to takto je…rad bych uvital moznost dodelani pro jQuery.
Nasel by se nejaky dobrak, co by byl ochoten vysvetlit problem s jQuery, popripade upravil priklad od Davida?
Editoval dotTwelve (31. 7. 2009 14:27)
- Panda
- Člen | 569
Máš 3 varianty:
- zajistit, aby měl formulář po odeslání stejnou definici, jako před změnou AJAXem – toho můžeš docílit pomocí dodatečných parametrů
- podědit třídu
SelectBox
a nastavit pole$allowed
po nastavení položek v poli na všechny možné hodnoty $form['select']->getRawValue()
a ověřovat ručně
- Ola
- Člen | 385
Zrovna před týdnem jsem začal pracovat na komponentě AjaxSelectBox, která umožňuje propojení s normálním SelectBoxem, s vypuštěním jsem čekal na úpravu v Nette, pokud to nepůjde, budu ji muset vydat „zaprasenou“. Má to ale pár mušek:
- musí se to renderovat ručně, nebo se zobrazí jen label
- musíš tomu předat dost speciální pole položek (prostě pro každou hodnotu z „nadřazenýho selectu“ musíš přidat alespoň jednu podřazenou položku), které může být dost velké (plánuju napojení na DibiDataSource, zatím jsem to ale s dibi nechtěl moc svazovat)
- je to dost svázané s AJAXem, bez něj se nezobrazí ovládací prvek a je třeba formulář odeslat ručně (pak se již prvek zobrazí)
- mohou blbnout chybové hlášky
Editoval Ola (7. 3. 2010 8:56)
- Panda
- Člen | 569
Ten getRawValue()
musíš volat až ve zpracování
formuláře – data ze selectboxu nebudeš tahat z
$form->values
, ale z
$form['select']->getRawValue()
.
A ta stejná definice se bez konkrétního příkladu docela špatně vysvětluje. Když zobrazuješ formulář, tak si ho nadefinuješ s nějakými hodnotami a vytvoříš si komponentu. Když ten formulář odesíláš, tak se Ti ta komponenta vytváří znovu. Pokud jsi ale mezi vykreslením formuláře a jeho odesláním formulář změnil pomocí AJAXu, tak už Ti pak definice odeslaného formuláře nemusí korespondovat s tou, která se Ti vytvoří při jeho odeslání. A Ty by jsi právě měl zajistit, aby byly shodné.
Doufám, že je tomu alespoň trochu rozumět.
- cuga
- Člen | 210
ukazu ti jak to mam a co mi nefunguje :)
$form->addSelect('shipping', 'Doprava', $shippingsArray)
->setDefaultValue($shipping)
->controlPrototype->class('select');
...
$form->addGroup('Dodací údaje');
$sub = $form->addContainer('delivery');
...
$sub->addSelect('country', 'Stát', $countries)
->controlPrototype->class('select');
$sub['country']->getControlPrototype()
->onchange('loadBox(this.value);');
potom handler
public function handleLoadData($part, $value)
{
$form = $this->template->form;
if($part == 'shipping') {
...
$form['shipping']->setItems($shippingsArray);
echo $form['shipping']->getControl();
} else if($part == 'payment') {
...
}
// konec zpracování
$this->terminate();
}
a zpracovani formulare
$shipPrice = $this->shippingsModel->getShippingPrice($form['shippingLimit']->value,$form['shipping']->value,$form['delivery']['country']->value,$cart->cartSum);
a pokud nekdo zmeni stat, tak je v $form[‚shipping‘]->value NULL dle ocekavani… pokud dam $form[‚shipping‘]->getRawValue()->value, tak si taky nepomuzu, protoze mi vraci to puvodne vybrane ID
- cuga
- Člen | 210
tak nakonec jsem to poresil pres to getRawValue, ale pri finalnim testovani v IE6–8 jsem narazil na hodne velkou neprijemnost, kdyz zmenit stat, tak se mi misto zmenenych selectu vypise
{"redirect":"http:\/\/localhost\/div-shop\/kosik\/"}
pritom JSON data by vracet vubec nemel. resili jste to nekdo? zadny nette jquery plugin nalinkovany nemam…
pokud nekomu pomuze, tak hlavicka vracena FF
object(RedirectingResponse)#55 (2) { ["uri":"RedirectingResponse":private]=> string(83) "http://localhost/div-shop/kosik/dodaci-udaje/?do=loadData%3Fpart%3Dshipping&value=2" ["code":"RedirectingResponse":private]=> int(301) }
a IE vraci
object(RedirectingResponse)#64 (2) { ["uri":"RedirectingResponse":private]=> string(32) "http://localhost/div-shop/kosik/" ["code":"RedirectingResponse":private]=> int(302) }
Editoval cuga (17. 3. 2010 15:51)
- mlha
- Člen | 58
Panda napsal(a):
A ta stejná definice se bez konkrétního příkladu docela špatně vysvětluje. Když zobrazuješ formulář, tak si ho nadefinuješ s nějakými hodnotami a vytvoříš si komponentu. Když ten formulář odesíláš, tak se Ti ta komponenta vytváří znovu. Pokud jsi ale mezi vykreslením formuláře a jeho odesláním formulář změnil pomocí AJAXu, tak už Ti pak definice odeslaného formuláře nemusí korespondovat s tou, která se Ti vytvoří při jeho odeslání. A Ty by jsi právě měl zajistit, aby byly shodné.
Formulář se mi zobrazuje po přijetí signálu s parametry. Jak zajistím, aby se tyto parametry uchovaly v componentě formuláře. Formulář je „obecná komponenta“ – nemůžu použít persistentní parametry definované na úrovni třídy. Existuje něco jako „dynamicky definované persistentní parametry“ componenty?
- mlha
- Člen | 58
Toto jsem už vyřešil. Ne přes persistentní parametry, ale přes hidden pole. Zásadní je uvědomit si, jak se komponenta formuláře chová při jeho odeslání.
Vždy se volá nejprve createComponent!!!
Při signálu s parametrem id není tento parametr po odeslání formuláře již dostupný, takže správný postup:
<?php
$form = new AppForm($this, 'form'); //v tento okamžik má formulář k dispozici i parametry signálu
$id = $form->getParam('id'); //při odeslání formuláře není dostupný
$input = $form->addHidden('id');
if (is_null($id)) $id = $input->getValue(); //při odeslání formuláře nahrazuje parametr hidden
$input->setValue($id);
...
?>