Ovlivneni komponenty ajaxove z presenteru
- Azim
- Člen | 41
Zdravim!
Resim pokladni presenter, ve kterem je seznam drinku, pro kazdy drink nekolik
checkboxu pro jednoltive objemy drinku. Pri kliknuti na checkbox se komponenta
ajaxove odesle a zobrazi se input pro navoleni mnozsvi drinku daneho objemu a
input zobrazujici cenu. (toto cele je jedna komponenta).
ted se pokousim k tomu pridat slevu – pokladni muze zvolit pomoci radiobuttonu slevu. Sleva uz je normalni form v presenteru. Idea je takova, ze po kliknuti na slevu se slevovy form ajaxove odesle ke zpracovani nejakemu signalu kompomenty a ten prekresli ceny v inputech.
Toho se mi zatim nepodarilo dosahnout, komponenta se mi vzdy „vynuluje“ navolena data v ni nezustanou.
Asi by to slo vyresit pridanim volby slevy do komponenty, ale logicky to tam
nepatri a nechci to tam motat. Nejaky rady?
Prikladam kod relevantni komponenty a ukazku sablony, jak ajaxove odesilam
public function handleUpdateSleva(MyForm $form) {
$sleva = $form['sleva']->getValue();
if ((0 <= $sleva) and ($sleva <= 100)) {
$this->sleva = $sleva;
}
else {
throw new InvalidArgumentException("Sleva musi byt v rozmezi 0 - 100.");
}
$this->sleva = $sleva;
$this->invalidateControl('vybraneDrinky');
}
public function render() {
$this->template->setFile(__DIR__ . '/objednavka.latte');
$this->template->form = $this['objednavkaForm'];
$this->fillForm();
$this->template->drinky = $this->getDrinky();
$this->template->objemy = Drink::$objemySelect;
$this->template->zobrazit = $this->polozky;
$this->template->render();
}
private function fillForm() {
$sum = 0;
foreach ($this->polozky as $polozka) {
$arr = explode("_", $polozka);
$drink = $this->em->find('Drink', $arr[0]);
$cena = $drink->getCenaZaObjem($arr[1]);
$mnozstvi = 1;
if (isset($this->formData['radky'][$polozka])) {
$mnozstvi = $this->formData['radky'][$polozka]['mnozstvi'];
}
$this['objednavkaForm']['radky'][$polozka]['cena']->setValue($cena*$mnozstvi*(1-$this->sleva/100));
$this['objednavkaForm']['radky'][$polozka]['mnozstvi']->setValue($mnozstvi);
$sum += $cena*$mnozstvi;
}
$this['objednavkaForm']['soucetContainer']['soucet']->setValue($sum);
}
private function getDrinky() {
if ($this->drinky == NULL)
$this->drinky = $this->em->getRepository('Drink')->findAll();
return $this->drinky;
}
public function createComponentObjednavkaForm() {
$form = new MyForm;
$form->getElementPrototype()->class = 'drinkyForm';
$drinky = $form->addContainer('vybraneDrinky');
$radky = $form->addContainer('radky');
foreach ($this->getDrinky() as $drink) {
foreach (Drink::$objemySelect as $objem => $mnozstvi) {
$key = $drink->id . '_' . $objem;
$drinky->addCheckbox($key, $drink->getCenaZaObjem($objem))->setAttribute('class', 'vyberDrinku');
$radek = $radky->addContainer($key);
$radek->addText('cena', 'Cena')
->setAttribute('readonly', 'readonly');
$radek->addText('mnozstvi', $drink->nazev . ' ' . \Drink::$objemySelect[$objem])
->setAttribute('class', 'mnozstviDrinku');
}
}
$form->addContainer('soucetContainer');
$form['soucetContainer']->addText('soucet', 'Celková částka');
$form->addSubmit('ok', 'Odeslat');
$form->onSuccess[] = callback($this, 'ObjednavkaFormSubmitted');
return $form;
}
public function ObjednavkaFormSubmitted($form) {
if ($this->getPresenter()->isAjax()) {
$data = $form->getHttpData();
$this->formData = $data;
foreach ($data['vybraneDrinky'] as $key => $value) {
$this->polozky[] = $key;
}
$this->invalidateControl('vybraneDrinky');
}
}
$('.vyberDrinku').live('change', function(){
var form = $(this).closest('form');
$.nette.ajax({
type: 'POST',
url: form.attr('action'),
data: form.serialize(),
});
return false;
});
- Vojtěch Dobeš
- Gold Partner | 1316
Ono je to logické – pokud překreslíš form v nějakém signálu, tak se na serveru logicky nenastaví v daný okamžik vyplněné hodnoty…
Řešením by bylo invalidovat pouze ty ceny samotné (nejsem si jistý,
jestli to tak máš). Proč by ceny měly být v inputech? Nestačí
v nějakém <span>
u?
- Vojtěch Dobeš
- Gold Partner | 1316
Btw, ten Javascript může vypadat i takto:
$.nette.ext({
load: function () {
$('.vyberDrinku').off('change.app').on('change.app', function (e) {
$(this).closest('form').netteAjax(e);
return false;
});
}
});
- Azim
- Člen | 41
spany by asi stacily… problem bude v tom, ze pokud si naklikam checkboxy, form se mi odesle na tuhle funkcni
public function ObjednavkaFormSubmitted($form) {
if ($this->getPresenter()->isAjax()) {
$data = $form->getHttpData();
$this->formData = $data;
foreach ($data['vybraneDrinky'] as $key => $value) {
$this->polozky[] = $key;
}
$this->invalidateControl('vybraneDrinky');
}
ktera podle zakliknutych checkboxu preda promenne do sablony tak, aby se
vykreslily jen relevantni inputy/spany. resenim by mohlo byt pridani do handleru
pro update slevy aktualni hodnoty formulare, tj
z
public function handleUpdateSleva(MyForm $form) {
udelat
public function handleUpdateSleva(MyForm $form, MyForm $drinkForm) {
Co vy na to? Porad se mi to zda osklive…
- Vojtěch Dobeš
- Gold Partner | 1316
Omlouvám se, ale nerozumím, nemohl bys to nějak více popsat? Btw, ten poslední řádek nechápu, toho přeci nijak nelze docílit.
- Azim
- Člen | 41
Moje chyba, kdyz to po sobe zpetne ctu, i mne to prijde ne moc pochopitelny. Problem je ten, ze pri volani handleUpdateSleva potrebuju nejakym zpusobem zjistit i aktualni hodnoty formu, protoze jinak se mi ztrati informace o tom, ktery checkboxy jsou zaklikany a tudiz i tom, pro ktery drinky vypsat radky pro zadani mnozstvi. Jde to nejak, nebo uvazuju spatne a ty slevovy radiobuttony musim zahrnout do komponenty a pak odesilat cely form?
Prikladam sablonu komponenty
{form objednavkaForm}
{if $form->hasErrors()}
<ul class="errors">
{foreach $form->errors as $error}
<li>{$error}</li>
{/foreach}
</ul>
{/if}
{snippet vypisDrinku}
<table>
<tr>
<th>Název</th>
{foreach $objemy as $objem}
<th>{$objem}</th>
{/foreach}
</tr>
{foreach $drinky as $drink}
<tr>
<td>{$drink->nazev}</td>
{foreach $objemy as $objem => $text}
<td>{$form['vybraneDrinky'][$drink->id.'_'.$objem]->getLabel()} {$form['vybraneDrinky'][$drink->id.'_'.$objem]->getControl()}</td>
{/foreach}
</tr>
{/foreach}
</table>
{/snippet}
{snippet vybraneDrinky}
<table>
{foreach $form['radky']->getComponents() as $key => $radek}
{if in_array($key, $zobrazit)}
<tr>
<td>{$radek['mnozstvi']->getLabel()}</td><td>{$radek['mnozstvi']->getControl()}</td>
<td>{$radek['cena']->getLabel()}</td><td>{$radek['cena']->getControl()}</td>
</tr>
{/if}
{/foreach}
</table>
<table>
{if isset($form['soucetContainer']['soucet'])}
<tr><td>{$form['soucetContainer']['soucet']->getLabel()}</td><td>{$form['soucetContainer']['soucet']->getControl()}</td></tr>
{/if}
<tr><td>{$form['ok']->getControl()}</td></tr>
</table>
{/snippet}
{/form}
- Vojtěch Dobeš
- Gold Partner | 1316
Obávám se, že budeš muset odesílat celý formulář :). Nepřijde mi to špatné, rozhodně ti to zjednoduší práci. Vyčleňovat to nějak zvlášť by dávalo smysl pouze tehdy, když bys tu samotnou část potřeboval použít někde jinde. Pak by se to asi dalo řešit nějakou subkomponentou…
- Azim
- Člen | 41
Problem je, ze tu komponentu potrebuju vyuzivat i na jinem miste bez slevove
casti. jeste me napadlo resit to pres sessions – po ajaxovem odeslani
(=zakliknuti checkboxu) si ulozim udaje z formu do session a v handleru public
function handleUpdateSleva(MyForm $form) si je z ni vytahnu.
Co vy na to?
- Vojtěch Dobeš
- Gold Partner | 1316
Ne! To mi přijde jako škrábání se nohou od kuchyňského stolu za
dveřmi od spíže. Udělej si tu slevovou část třeba jako
Nette\Forms\Container
, a připoj ho jak do tohohle formuláře, tak
do jakéhokoliv jiného.