Ajaxový formulář odešle správný požadavek, vrátí se správná odpověď, ale snippet se nepřekreslí
- tdavis
- Člen | 2
Zdravím, v ajaxu jsem nováčkem, tak doufám že nedělám nějakou banální chybu, ale bohužel už se s tím peru druhý den a opravdu nevím, kde by mohla být chyba. Snažím se vytvořit ajaxový formulář, který mi bude filtrovat produkty (něco jako na alza.cz že si posuvníkem nastavím parametry a produkty se ajaxově překreslí).
Mám vytvořenou komponentu FrameListControl, která má svoji šablonu a stará se o vykreslení potřebných produktů (v mém případě rámů jízdních kol). Tato komponenta obsahuje mimo jiné také parametr allData, do kterého si při jeho vytvoření vytahuji všechny dostupné produkty (rámy) pro danou sekci a typ rámů z databáze. Druhým parametrem je visibleData, který obsahuje pouze data, které mají být vidět. Komponenta poté obsahuje formulář FilterForm, který bude odesílat ajaxové požadavky. Snad lépe osvětlí situaci následující kód komponenty.
<?php
class FrameListControl extends Control
{
/** @var FrameModel */
public $frameModel;
private $section;
private $frameType;
private $parameters;
private $allData; //all frames
private $visibleData; //filtered frames
public function __construct(FrameModel $frameModel)
{
parent::__construct();
$this->frameModel = $frameModel;
}
public function render()
{
$this->template->setFile(__DIR__ . '/templates/FrameListControl.latte');
$this->template->frames = $this->visibleData;
$this->template->filterForm = $this->getComponent('filterForm');
$this->template->render();
}
public function setVisibleData($parameters = null)
{
$this->visibleData = null;
if (!$parameters){
$this->visibleData = $this->allData;
$this->visibleData = null;
return;
}
if (isset($parameters['inchSize']) && $this->allData){
foreach ($this->allData as $key => $frame){
foreach($frame['sizes'] as $size){
foreach($parameters['inchSize'] as $inch){
if ($inch == $size->inchSize){
$this->visibleData[$key] = $this->allData[$key];
break;
}
}
}
}
}
}
public function setFramesType($type)
{
$this->frameType = $type;
$this->allData = $this->frameModel->getAllFramesFromSection($this->frameType);
$this->visibleData = $this->allData;
}
public function setSection($section)
{
if ($section == 'cbw' || $section == 'geer')
$this->section = $section;
else
throw new \Exception("filterForm, section must be 'cbw' or 'geer'");
}
public function createComponentFilterForm()
{
$form = new Form();
$form->setMethod('get');
foreach($this->frameModel->getFrameSizes() as $key => $size){
$inchSizes[$size] = $size.'"';
}
$form->addCheckboxList('inchSize', 'Velikosti rámu:', $inchSizes);
$form->addSubmit("submit");
$form->onSuccess[] = callback($this, 'actionFilterFormSucceeded');
return $form;
}
public function actionFilterFormSucceeded(Form $form, $values)
{
$parameters = null;
foreach ($values as $key=>$value){
if (!empty($value))
$parameters[$key] = $value;
}
$this->setVisibleData($parameters);
if (!$this->getPresenter()->isAjax())
$this->redirect('this');
else {
$this->redrawControl();
}
}
}
?>
Šablona pro předchozí komponentu je následující.
FrameListControl.latte
{form filterForm class=>'ajax'}
{label inchSize /}
{input inchSize}
{input submit}
{/form}
{snippet frames}
{ifset $frames}
{foreach $frames as $frame}
<div class="frameDiv">
<h2><span class="bold">{$frame->Name}</span></h2>
{ifset $framesImages[$frame->Id]}
<img src="{$basePath}/{$framesImages[$frame->Id]['min'][0]}">
{else}
<img src="{$basePath}/images/frontEnd/icons/noImage.png" alt ="noImage">
{/ifset}
<table class="frameSizesTbl">
<tr>
<th>Palce</th><th>Rozměr A</th>
<th>Rozměr B</th>
<th>Rozměr C</th>
</tr>
{foreach $frame['sizes'] as $size}
<tr>
<td>{$size->inchSize}"</td>
<td>{$size->sizeA}cm</td>
<td>{$size->sizeB}cm</td>
<td>{$size->sizeC}cm</td>
</tr>
{/foreach}
</table>
<span class="bottomSpan">
<p>Materiál: {$frame->Material}</p>
<p>Cena: {$frame->Price|number:0:',':' '},- kč</p>
</span>
</div>
{/foreach}
{/ifset}
{/snippet}
Zde je presenter, který využívá a vykresluje tuto komponentu.
<?php
class CbwPresenter extends BasePresenter
{
/** @var FrameModel @inject*/
public $frameModel;
/** @var FrameListControl @inject */
public $frameListControl;
private $section = 'cbw';
//************************************************STARTUP***************************************
public function startup()
{
parent::startup();
$this->frameModel->setSection($this->section);
}
//**************************************************ACTIONS*************************************
public function actionFrames($type)
{
$this->frameListControl = $this->getComponent('frameList');
$this->frameListControl->setFramesType($type);
if($this->isAjax() ){
$this->redrawControl();
}
}
//**************************************************RENDERS*************************************************
public function renderFrames($type)
{
$this->template->frameList = $this->frameListControl;
}
public function createComponentFrameList()
{
$frameList = new FrameListControl($this->frameModel);
$frameList->setSection($this->section);
return $frameList;
}
}
?>
A jeho šablona frames.latte.
{block head}
<link rel="stylesheet" media="screen,projection,tv" href="{$basePath}/css/frontEnd/frames.css">
<link rel="stylesheet" media="screen,projection,tv" href="{$basePath}/css/frontEnd/filterForm.css">
{/block}
{block content}
<div id="frameBox">
<h1 class="pageHeaderH1">Zjistit typ rámy</h1>
{snippet frameList}
{control frameList}
{/snippet}
<img src="{$basePath}/images/frontEnd/frameSizeDescript.png" alt="frameSizeDescript" class="frameSizeImg">
</div>
{/block}
V ajaxové odpovědi se mi vrátí snippet s názvem **snippet--frameList**, což by odpovídalo snippetu v šabloně *frames.latte*. Nikde mi to žádnou chybu nehlásí všechno se provede tak jak má, ale bohužel nahrazení snippetu (divu) novýmy ajaxovými daty neproběhne.
Napadá mě jedině že by problém mohl být v javascriptu. Využívám plugin **nette.ajax.js**, který inicializuji následovně.
<script>
$(function () {
$.nette.init();
});
</script>
Jestli jsem to pochopil správně tak o zpracování ajaxové odpovědi a její vykreslení by se měl postarat tento plugin. Vyzkoušel jsem volat funcki **redrawControl()** snad na všech možných místech (handle, action, ...), v presenteru i v komponentě. Poté jsem zkoušel si hrát i s JS nastavovat si různě ajaxové požadavky pomocí proměnné **$.nette.ajax({})**.
Nezdá se mi pouze jak tam mám zanořené jakoby dva snippety v sobě. První v **frames.latte**, který vykresluje komponentu **FrameListControl** a druhý snippet v **FrameListControl.latte**, který obsahuje již samotné vypsání rámů, ale bohužel netuším jak to lépe vytvořit.
Pokud by někoho napadl nějaký nápad, nebo návrh byl bych opravdu vděčný... Z mého pohledu jsem snad vyzkoušel všechny možné metody a stejně si nevím rady....
Děkuji.
Editoval tdavis (16. 7. 2015 14:38)
- Kori
- Člen | 73
Ahoj, v rychlosti par rad na uplny zacatek.
Vyhod inject, nepredavas si zadnou factory, ale vytvaris novou instanci tridy v createComponentFrameList()
/** @var FrameListControl @inject */
public $frameListControl;
Navic si nemusis drzet instanci controly a predavat si ji do sablony (vytvori
se sama), takze pravdepodobne ani nebudes
potrebovat public $frameListControl;
$this->template->frameList = $this->frameListControl;
To same v komponente
$this->template->filterForm = $this->getComponent('filterForm');
Pokud si predavas factory, pak uprav
new FrameListControl($this->frameModel);
na volani te factory,
jinak si ji predavas uplne zbytecne :-)
Z actionFrames vyhod redraw snippetu, nema to tam co delat
if($this->isAjax() ){
$this->redrawControl();
}
Ted by ti to teoreticky mohlo zacit fungovat…
Editoval Kori (17. 7. 2015 4:57)