Komponenta zpracuje signál, ale nepřekreslí se

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

Mám na stránce několikrát jednu komponentu (používám UI\Multiplier) a tato komponenta obsahuje tlačítko které odešle signál. Poté se má komponenta překreslit. Jednoduché jak facka, přesto mi to nefunguje.

Šablona komponenty je velmi jednoduchá (pro potřeby tohoto dotazu stačí takto):

{snippet}
	<a n:class="ajax" n:href="signal! $id">button</a>
{/snippet}

Metoda pro zpracování signálu:

public function handleSignal($id) {
	$this->model->doSomething();
	if($this->presenter->isAjax()) {
		$this->invalidateControl();
	} else {
		$this->redirect('this');
	}
}

Problém je v tom, že se signál normálně odešle a zpracuje, následně se celá komponenta invaliduje, ale nepřekreslí se. V konzoli se vypíše, že došlo k nějaké chybě při odesílání požadavku.
Došel jsem k názoru, že problém bude nejspíš v tomto:

public function render($data) {
	// some code
}

Předpokládám, že poté, co se komponenta invaliduje, odešle se požadavek na html, ale nepošlou se žádná data jako argument, tím pádem dojde k fatální chybě a komponenta se nepřekreslí.
Mám tedy dvě otázky:

  1. Je problém opravdu tam kde si myslím že je?
  2. Pokud ano, jak se to dá řešit? Pokud ne, kde jinde by mohl být?

Díky moc

na1k
Člen | 288
+
0
-

V konzoli se vypíše, že došlo k nějaké chybě při odesílání požadavku.

Tohle je dost vágní. K jaké chybě? Na straně server? 50× u ajax requestu?
Pokud ano, ve složce s logy bys měl najít uloženou výjimku.

kytart
Člen | 10
+
0
-

na1k napsal(a):

V konzoli se vypíše, že došlo k nějaké chybě při odesílání požadavku.

Tohle je dost vágní. K jaké chybě? Na straně server? 50× u ajax requestu?
Pokud ano, ve složce s logy bys měl najít uloženou výjimku.

Tak skutečně ve složce s logy vyjímka byla a potvrzuje mojí hypotézu. Metoda render() očekává argument, ale ten se nedodá…

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Chybu jsi vydedukoval zcela správně. Předávání parametrů metodě render bohužel s AJAXem není kompatibilní. Pokus se ta data předávat v továrničce nebo někde v presenteru/nadřazené komponentě, kde je máš k dispozici a můžeš ke komponentě přistoupit.

kytart
Člen | 10
+
0
-

vojtech.dobes napsal(a):

Pokus se ta data předávat v továrničce nebo někde v presenteru/nadřazené komponentě, kde je máš k dispozici a můžeš ke komponentě přistoupit.

Vyřešil jsem to následujícím způsobem:

public function render($data = null) {
	if($data != null) $this->dataToTemplate($data);
	$this->template->render();
}

public function handleVote($id) {
	$this->model->doSomething($id);
	if($this->presenter->isAjax()) {
		$data = $this->anotherModel->getData($id);
		$this->dataToTemplate($data);
		$this->invalidateControl();
	} else {
		$this->redirect('this');
	}
}

private function dataToTemplate($data) {
	$this->template->something = $data->something;
	// dalsi promenne do sablony
}

Bohužel se objevil další problém. Konzole teď ukazuje, že požadavek proběhl úspěšně, jenže response je {"state": []} a nic jiného… Tj. server v pořádku zpracoval požadavek, zavolal metodu render komponenty, protože se invaliduje (nebo by alespoň měl), ale šablona se nevykreslí… To už vůbec nechápu

kytart
Člen | 10
+
0
-

Nakonec jsem na to po čase přišel sám, tak to sem dám, aby to tu bylo, kdyby někdo narazil na podobný problém.
Problém byl v tom, že předávám jako parametr pro render() celé pole. Řešení z minulého příspěvku by teoreticky mělo fungovat taky, jenže nefungovalo. Proto jsem to obešel následujícím způsobem:

public function render($id = null) {
	if($id != null) $this->getData($id);
	$this->template->render();
}

public function handleSignal($id) {
	$this->model->doSomething($id);
	if($this->presenter->isAjax()) {
		$this->getData($id);
		$this->invalidateControl();
	} else {
		$this->redirect('this');
	}
}

protected function getData($id) {
	$data = $this->modelOther->getDataArray($id);
	$this->template->value1 = $data->value1;
	// dalsi promenne do sablony
}

tedy řešení spočívá v tom, že ani v metodě render() ani nikde jinde nepředávám metodě celé pole, ale pouze ID a až následně podle ID získám data z databáze a nasypu do šablony. Hotovo!

fabian
Člen | 20
+
+2
-

Ahoj,
myslim, ze jsem ted resil stejny problem: pokud ma render() metoda controlu nejaky parametr, po prekresleni snippetu ajaxem se ji tento parametr uz znovu nedostane, takze nemuze udelat svoji praci a odeslat payload. Skonci chybou napr. Fatal error: Missing argument 1 for PostRateControl::render() (treba to nekomu pomuze pri googleni;)

Ja to vyresil takhle:

class PostRateControl extends \Nette\Application\UI\Control
{
    private $postId;

    public function render($postId = NULL)
    {
        if (!is_null($postId)) { // nastavujeme $postId, pokud je control volan ze sablony {control postRateControl, 1} napr.
            $this->postId = $postId;
        }
        if (is_null($this->postId)) { // takova pojistka:)
            throw new Exception('no post id');
        }

        ...

        nejake veci, co ma metoda render obstarat a poslat sablone

        ...

        return $this->template->render();
    }

    public function handleRate($postId, $rate)
    {
        $this->postId = $postId; // nastavime privatni promennou postId, kterou pouzije metoda render() po invalidaci

        ...

        tady si vyresime zapis hodnoceni ..

        ...

        if ($this->presenter->isAjax()) {
            $this->invalidateControl();
        }
    }
}