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
.