Ovlivneni komponenty ajaxove z presenteru

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

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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.

Azim
Člen | 41
+
0
-

to ale budu muset upravovat sablonu te komponenty, ne? jinak by se mi ten kontejner nevykreslil