Snippet sa na prvý krát neprekreslí, až na druhý

- kitanaf
 - Člen | 6
 
Zdravím, používam Nette 2.0.6 a PHP 5.3. Mám nasledujúci problém:
Mám dve externé komponenty, prvú z nich volám v CatalogPresenter a druhú v BasePresenter (CatalogPresenter rozširuje BasePresenter). Akcia v komponente volanej v CatalogPresenter potrebuje prekresliť snippet v sebe, ale aj snippet v tej komponentne volanej z BasePresenteru. Ten snipper u seba prekreslí vždy a v poriadku, ale ten snippet v tej komponente volanej z BasePresenteru prekreslí vždy až na druhý krát. To znamená, že stlačím tlačidlo prvý krát → prekreslí sa len prítomny snippet v tejto komponentne, stlačím druhý krát → prekreslia sa obidva, stlačím tretí krát → prekreslia sa obidva, …
Invalidáciu volám takto:
$this->invalidateControl();
$this->presenter->getComponent('topBar')->invalidateControl('topCart');
Vedel by mi niekto s tým poradiť? Ďakujem!
Editoval kitanaf (13. 12. 2012 20:28)

- Vojtěch Dobeš
 - Gold Partner | 1316
 
Co znamená přesně, že se překreslí až na podruhé? Přichází už napoprvé snippet v odpovědi serveru a jen se nevykreslí? Nebo přichází skutečně až v té druhé odpovědi?

- kitanaf
 - Člen | 6
 
Ďakujem za reakciu, tvoje otázky ma prinútili trochu hlbšie sa na to pozrieť. Zistil som, že ten snippet sa v skutočnosti prekreslí, ale hodnota sa neupraví. V tej akcii po stlačení tlačidla pridávam daný produkt do košíka:
$this->repository->addItem(...);
if (!$this->presenter->isAjax()) {
    $this->presenter->redirect('this');
} else {
    $this->invalidateControl();
    $this->presenter->getComponent('topBar')->invalidateControl('topCart');
}
Ale správa sa to tak, ako keby sa to robilo naopak. To znamená, že najprv sa snippet prekreslí a až potom sa pridá do košíka. Takže pri prvom pridaní do košíka, žiadna zmena neprebehne a až pri druhom stlačení je vidieť aj zmenu počtu produktov v košíku (+1).
Ešte doplním, že v tej komponente TopBar využívam v šablóne premennú $qty, ktorú napĺňam v komponente pomocou count($this->cartItems) a $this->cartItems som nastavil v konštruktore komponenty pri inicializácií komponenty v BasePresenteru.
Ono to proste vyzerá, že pred prekreslením neprebehne načítanie nových $cartItems, ale zrejme prebehne až potom… keďže po opakovanom stlačení sa už hodnota zvýši o jeden (ajaxovo). Nechápem, kde je problém…
Editoval kitanaf (14. 12. 2012 16:33)

- Vojtěch Dobeš
 - Gold Partner | 1316
 
Aby se ta záhada dala rozřešit, ukaž celý kód šablony a metod, kde do nich přiřazuješ proměnné. Někde v tom bude zakopaný pes.

- kitanaf
 - Člen | 6
 
Šablóna komponenty topBar:
<div id="mini-cart">
		<span class="top-title"><a href="{$presenter->link('Cart:default')}">Nákupný košík</a></span>
		{snippet topCart}
		<div class="top-row">Položiek:  {$qty}</div>
		<div class="top-row">Suma:  {$totalPrice} {$currency}</div>
		{/snippet}
</div>
Jej render metóda:
public function render()
    {
        $this->template->setFile(__DIR__ . '/TopBarControl.phtml');
        $this->template->customer = $this->customer;
        $itemsCount = 0;
        foreach ($this->cartItems as $item) {
            $itemsCount += $item->qty;
        }
        $this->template->qty = $itemsCount;
        $itemsPrice = 0.0;
        foreach ($this->cartItems as $item) {
            $itemsPrice += $item->price_excl_tax*$item->qty;
        }
        $this->template->totalPrice = $itemsPrice;
        $this->template->render();
    }
A jej konštruktor:
public function __construct($customer,$cartItems)
    {
        parent::__construct();
        $this->customer = $customer;
        $this->cartItems = $cartItems;
    }
Komponentu topBar vytváram v BasePresenter:
protected function createComponentTopBar()
    {
       return new TopBarControl(
        	$this->customer,
        	$this->cartItems
        	);
    }
A volám ju v @layout.latte:
{control topBar}
Šablóna komponenty addToCart:
{form addToCartForm class => ajax}
        <div class="qty"><span>{label qty/}</span>{input qty}</div>
        {input submit}
{/form}
Formulár vytváram v komponente, tu je submitted metoda:
public function addToCartFormSubmitted($form) {
        $values = $form->getValues();
        $this->addToCart($values['qty']);
    }
A tu je metóda addToCart:
public function addToCart($qty) {
        $this->repository->addItem($this->customer_ID,$this->product_ID,$qty);
        $this->flashMessage('Produkt bol pridaný do košíka.');
        if (!$this->presenter->isAjax()) {
            $this->presenter->redirect('this');
        } else {
            $this->invalidateControl();
            $this->presenter->getComponent('topBar')->invalidateControl('topCart');
        }
    }
Komponentu addToCart volám v CatalogPresenter:
protected function createComponentAddToCart()
    {
    	$repository = $this->shoppingCartItemRepository;
    	$customer_ID = $this->customer->ID;
    	$controlMain = new UI\Multiplier(function ($product_ID) use ($repository,$customer_ID){
    		$control =  new AddToCartControl();
    		$control->setProductId($product_ID);
    		$control->setCustomerId($customer_ID);
    		$control->setRepository($repository);
    		return $control;
    	});
    	return $controlMain;
    }
A nakoniec, volám ju v šablone Catalog/default.phtml:
{control "addToCart-$product->ID"}
Díky moc za pomoc :)
Editoval kitanaf (15. 12. 2012 0:42)

- kitanaf
 - Člen | 6
 
Tak už som to vyriešil, neviem ale nakoľko je to správne riešenie. Do metody addToCart som pridal funkciu, ktorá zavolá funkciu refreshCart na rodicovskom presentery a tá refreshne obsah premennej, ktorá uchováva tie položky v košíku. Toto by mala robiť aj tá komponenta topBar, ale z nejakého dôvodu to nerobí. Zmena teda vyzerá následovne:
public function addToCart($qty) {
        $this->repository->addItem($this->customer_ID,$this->product_ID,$qty);
		$this->presenter->refreshCart();
        $this->flashMessage('Produkt bol pridaný do košíka.');
        if (!$this->presenter->isAjax()) {
            $this->presenter->redirect('this');
        } else {
            $this->invalidateControl();
            $this->presenter->getComponent('topBar')->invalidateControl('topCart');
        }
}
					Editoval kitanaf (18. 12. 2012 0:27)

- Vojtěch Dobeš
 - Gold Partner | 1316
 
Myslím, že jsem objevil, kde má čmelák žihadlo. Kde nastavuješ
proměnnou itemCarts, co používáš v tovarničce
topBar? Předpokládám, že to bude před tím, než se zpracuje
ten formulář (nejspíš ve startup). A proto ti tam zůstanou
stará data – komponenta se vytvoří s neaktuálními daty. Řešením je
buď provést to, co jsi udělal ty, anebo data shánět lazy až
v továrničce, takže se načtou až po volání addItem.