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

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

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

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

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

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

Š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:&nbsp;&nbsp;{$qty}</div>
		<div class="top-row">Suma:&nbsp;&nbsp;{$totalPrice}&nbsp;{$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
+
0
-

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

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.

kitanaf
Člen | 6
+
0
-

Presne ako vravíš, dáta som načítal v tom startupe.. Díky za pomoc :)