Invalidace renderu z jiné akce?

Kcko
Člen | 465
+
0
-

Ahoj,

Presenter → 2 akce nebo rendery (to je fuk)

Default – výpis položek
Detail – detail položek

Na stránce bude vyhledávací pole, které omezí / vyfiltruje výpis položek. Dojde tedy k invalidaci snipetu v Default akci. To je OK.

Ale pokud budu na detailu položky, netuším, jak bez přesměrování na default to také udělat AJAXEM (bez refreshe). Ideálně aby se mi měnila i URL (možná existuje nějaká extenze).

Díky za popostrčení.

Kcko
Člen | 465
+
0
-

Vyřešeno.

Kcko
Člen | 465
+
0
-

Změny URL po AJAXovém requestu řeší nette.history.ajax od @VojtěchDobeš
A co se týká onoho překreslení snippetu, tak stačí mít v obou šablonách (default/detail) stejný snippet a pak jej invalidovat.

Už mi nefunguje akorát „přesměrování“. Potřebuji vyvolat handle a přesměrovat na nějakou akci s nějakým parametrem.
Lze to?

MajklNajt
Člen | 470
+
0
-

ahoj, čo tak kúsok kódu, pretože napr. mne stále nie je jasné, čo sa snažíš dosiahnuť – v prvom príspevku píšeš „bez presmerovania“, teraz zase „nefunguje presmerovanie“… btw. ja vyhľadávanie, ktoré je umiestnené vo viacerých šablónach, riešim cez komponentu ⇒ nemusím tak ten istý formulár renderovať a obaľovať snippetom na 5 miestach

Kcko
Člen | 465
+
0
-

MajklNajt napsal(a):

Ahoj, vyznívá to zmateně, protože jsem něpočítal s vyhledávacím formulářem.
Popíši to znovu:

Jedná se o výpis gistů (jsem napojen na API githubu a stahuju si pro svoji potřebuju svoje gisty, které mají štítky atd.) (vypadá to nějak takhle): http://bit.ly/2DivrAK

Celý kód asi není potřeba, je to základní logika a základní práce s Nette:

  • 1 presenter
  • 2 render metody (default = pro výpis gistů, detail pro detail gistu s jeho náležitostmi)

Vše mi funguje, vše OK.

Chci tam i vyhledávání a líbilo by se mi, aby fungovalo skrze ajax + nějaký preloader (ten si dodělám přes extenzi do nette.ajax.js).

Na vyhledávácí formulář není potřeba komponenta, stačí jednoduchá továrnička v presenteru.

Takže napíši něco do vyhledávacího inputu, odešlu formulář AJAXem, obslužný handle to zpracuje a potřebuji se dostat na

  • na 3 render<Search> s (parametrem $q = hledaný výraz).

Kdyby to nebylo ajaxem, tak prostě

<?php
	$this->redirect("search", $q);
?>

Ale jak to udělat s ajaxem? Když si vygeneruji testovací odkaz ručně <a n:href=„search tracy“ class=„ajax“>testovací</a>
⇒ vygeneruje se URL <web>/gists/search/tracy a jelikož mám v šabloně , stejně jako v ostatních dalších 2, nadřazený div, který je snippetem, tak provedu invalidaci a funguje to.

Ale nevím, jak to udělat, když potřebuji v Nette přesměrovat z handlu na nějaký render s parametrem bez refreshe?
Nebo by stačilo, abych uměl nějak vyvolat nějaký request, který se děje kdybych ten odkaz udělal ručně viz (search tracy)

Editoval Kcko (11. 11. 2018 9:39)

Phalanx
Člen | 310
+
0
-

@Kcko Odešli vyhledávací formulář ajaxem, přiřaď hodnotu z vyhledávání do persistentního parametru a dej redrawControl(‚tvujSnippet‘)

Poslat ho můžeš buď přes submit button

<input type="text" name="search">
<input type="submit" name="submit" class="ajax">

nebo si na to napíšeš javascriptové odeslání přes $.nette.ajax post. Záleží na tobě.

Nefunguje ti to kvůli tomu, že tam máš jen odkaz místo poslání formuláře nebo poslání přes javascript.

Editoval Phalanx (11. 11. 2018 11:47)

Kcko
Člen | 465
+
0
-

Phalanx napsal(a):

@Kcko Odešli vyhledávací formulář ajaxem, přiřaď hodnotu z vyhledávání do persistentního parametru a dej redrawControl(‚tvujSnippet‘)

Poslat ho můžeš buď přes submit button

<input type="text" name="search">
<input type="submit" name="submit" class="ajax">

nebo si na to napíšeš javascriptové odeslání přes $.nette.ajax post. Záleží na tobě.

Nefunguje ti to kvůli tomu, že tam máš jen odkaz místo poslání formuláře nebo poslání přes javascript.

Ahoj, předně dík za reakci.

Kdyby to nebylo AJAXEM tak

  1. jsem v renderDefault nebo renderDetail (to je uplně jedno).
  2. Vyhledávací formulář , něco napíši klik … ⇒ vyvolá se subrequest (tj. handle formuláře) a přesměruji na renderSearch($q)
  3. v renderSearch si přes model zobrazím gisty, které obsahují hledaný výraz.'

Nějak nechápu v čem mi persistentní parametr pomůže. Já samozřejmě chápu, že odkaz je odkaz a já tu řeším něco jiného :-)

Já se prostě ptám, jestli jde nějak AJAXově přesměrovat z jednoho renderu na druhý bez refreshe.
Pokud ne, tak samozřejmě asi půjde v případě AJAXu bod 2 upravit tak, že

<?php

function handleSearchForm($form, $values)
{
	if ($this->isAjax())
	{
		$this->template->gists = $this->model->findGistBySearch($values->q);
		$this->redrawControl("gists");
	}
	else
	{
		$this->redirect("search", $values->q);
	}
}

function renderSearch($q)
{
	$this->template->gists = $this->model->findGistBySearch($values->q);
	// ... atd
}

?>

Tohle asi bude fungovat, ale není to to co jsem chtěl, tady dělám díky AJAXU 2× to samé (a defakto to jsou 2 různá URL, handle a render).

Takže moje otázka pořád zní:

„Já se prostě ptám, jestli jde nějak AJAXově přesměrovat z jednoho renderu na druhý bez refreshe.“

Díky :-)

Felix
Nette Core | 1183
+
0
-

„Já se prostě ptám, jestli jde nějak AJAXově přesměrovat z jednoho renderu na druhý bez refreshe.“

Moc nerozumim co je timhle mysleno.

Jestli myslis predat request, interne v Nette, z jedne action/render metody do druhe, v ramci jednoho requestu, tak na to slouzi $presenter->forward().

MajklNajt
Člen | 470
+
0
-

Ja by som len poznamenal, že handle metóda je iba signál, čiže nemal by meniť action/view. Presmerovanie samo o sebe z jednej action na inú action bez refresha by ti mal plné vyriešiť nette.history.ajax

Kcko
Člen | 465
+
0
-

Felix napsal(a):

„Já se prostě ptám, jestli jde nějak AJAXově přesměrovat z jednoho renderu na druhý bez refreshe.“

Moc nerozumim co je timhle mysleno.

Jestli myslis predat request, interne v Nette, z jedne action/render metody do druhe, v ramci jednoho requestu, tak na to slouzi $presenter->forward().

Ano to je ono. Zbývá dořešit jednu věc a tou je to, že i když mám nalinkovaný nette.history.ajax (který normálně funguje) tak v případě handlu mi přidá GET parametr ?do=test, snippet se mi ovšem správně překreslí, jen ta URL je blbě.

<web>/gist/34?do=test // detail gistu s přidaným handlem

<?php
	// jen na otestovani
	public function handleTest()
	{
		if ($this->isAjax())
			$this->forward('default', 'php'); // na <renderDefault> s argumentem $slug = php
	}
?>
Kcko
Člen | 465
+
0
-

MajklNajt napsal(a):

Ja by som len poznamenal, že handle metóda je iba signál, čiže nemal by meniť action/view. Presmerovanie samo o sebe z jednej action na inú action bez refresha by ti mal plné vyriešiť nette.history.ajax

Jak? Jakým způsobem? Chci z handlu na akci/render, forward sice přesměruje, ale URL není taková jaká by být měla, viz předchozí reakce na Felixe.

Edit: v případe handlu formuláře, mi to history.ajax nezmění URL vůbec (je tam furt ta, ze které formulář ajaxově odesílám), což teda už není problém Nette, ale spíš té JS extenze, nevíte čím to je?

<?php
	public function createComponentSearchForm()
	{
		$form = new UI\Form;
		$form->getElementPrototype()->setClass('ajax');
		$form->setMethod('GET');
		$form->addText('q', 'Hledaný výraz')
			  ->addRule($form::MIN_LENGTH, 'Nebuď línej a zadej něco', 2);
		$form->addSubmit('_submit', 'Submit');

		$form->onSuccess[] = function($form, $values) {

			if ($this->isAjax())
				$this->forward('default', NULL, $values->q);
			else
				$this->redirect('default', NULL, $values->q);


		};

		return $form;
	}

?>

Editoval Kcko (11. 11. 2018 13:45)

MajklNajt
Člen | 470
+
0
-

$this->redirect('default', NULL, $values->q); by ti spolu s nette.history.ajax malo zmeniť url bez refreshu

Kcko
Člen | 465
+
0
-

MajklNajt napsal(a):

$this->redirect('default', NULL, $values->q); by ti spolu s nette.history.ajax malo zmeniť url bez refreshu

Ano, je to tak, v response vidím (http://bit.ly/2Dgrdde), ale ted se mi zas nepřekreslí snippet :/

MajklNajt
Člen | 470
+
0
-

A pri použití forward sa ti snippet prekreslí?

Kcko
Člen | 465
+
0
-

MajklNajt napsal(a):

A pri použití forward sa ti snippet prekreslí?

Ano, v response jsou snippety atd, překreslí. Při redirectu mám v reponse pouze redirect a URL, takže se nemá ani co překreslit.

Nikde jsem nenašel jak to má korektně fungovat, takže to nechám s tím forwardem a do payloadu si hodím současnou URL a poté stejně tak jak to dělá extenze history.ajax to přes JS vložím do URL (tj napíšu si svoji primitivní extenzi která bude z payloadu brát URL a vkládát ji do adresního řádku).

Nic jiného me už nenapadá a ani nerozumím tomu history.ajax chování.

MajklNajt
Člen | 470
+
0
-

A ten snippet invaliduješ až v renderDefault?

Kcko
Člen | 465
+
0
-

Zkousel semv handle formulare pak v akci i renderu.

Kcko
Člen | 465
+
0
-

není invalidovat, viz ten screen s odpovedi

Kcko
Člen | 465
+
0
-

*není co

Kcko
Člen | 465
+
0
-

Přikládám celý presenter:

<?php

namespace App\FrontModule\Presenters;

use App\Model,
	App\FrontModule\Components,
	Nette,
	Nette\Application\UI;


class GistPresenter extends BasePresenter
{

	/** @inject @var Model\Gist */
	public $modelGist;

	/** @inject @var Model\GistLabel */
	public $modelGistLabel;

	/** @inject @var Model\GistGistLabel */
	public $modelGistGistLabel;

	/** @inject @var Model\GistFile */
	public $modelGistFile;


	public function startup()
	{
		parent::startup();
		$this['breadCrumbs']->add('Gists', $this->link('default'));
	}


	public function createComponentPaginator()
	{
	    return new Components\VisualPaginator;
	}

	public function createComponentSearchGistForm()
	{
		$form = new UI\Form;
		$form->getElementPrototype()->setClass('ajax');
		$form->setMethod('GET');
		$form->addText('q', 'Hledaný výraz')
			  ->addRule($form::MIN_LENGTH, 'Nebuď línej a zadej něco', 2);
		$form->addSubmit('_submit', 'Submit');

		$form->onSuccess[] = function($form, $values) {

			// if ($this->isAjax())
			// else
			//$this->invalidateControl();
			$this->presenter->payload->url = $this->link('default', NULL, $values->q);
			$this->redrawControl();
			//$this->redirect('default', NULL, $values->q);
			$this->forward('default', NULL, $values->q);


		};

		return $form;
	}


	public function renderDetail($guid)
	{

		$gist = $this->modelGist->findBy(array('id' => $guid))->fetch();

		if (!$gist)
			$this->error();

		$this->template->heading = $gist->title;
		$this->template->gist = $gist;
		$this['breadCrumbs']->add($gist->title, $this->link('this'));



	}


	public function renderRaw($guid)
	{
		$gistFile = $this->modelGistFile->findBy(array('guid' => $guid))->fetch();

		if (!$gistFile)
			$this->error();

		$this->template->gistFile = $gistFile;
	}


	public function actionDefault($slug = NULL, $q = NULL)
	{
		if ($this->isAjax())
		{

			$this->redrawControl();
		}
	}
	public function renderDefault($slug = NULL, $q = NULL)
	{
		if ($this->isAjax())
		{
			$this->redrawControl();
		}

		$this->template->heading = 'Gists';

		$gists = $this->modelGist->findAll();


		if ($slug) {
			$labelRow = $this->modelGistLabel->findAll()->where('slug', $slug)->fetch();
			if (!$labelRow)
				$this->error();

			$gists->where(':gist_gist_label.gist_label_id', $labelRow->id);

			$this->template->heading .= ' - ' . $labelRow->title;
			$this['breadCrumbs']->add($labelRow->title, $this->link('this'));
		}

		// vyhledavani
		if ($q)
		{
			$gists->where('

				title LIKE ?
				OR description LIKE ?
				OR :gist_file.filename LIKE ?
				OR :gist_file.content LIKE ?
			',
				'%'.$q.'%',
				'%'.$q.'%',
				'%'.$q.'%',
				'%'.$q.'%'
			);
		}


		$gists->order('updated DESC');

		$vp = $this['paginator'];
		$paginator = $vp->paginator;
		$paginator->itemsPerPage = 20;
		$paginator->itemCount = $gists->count("*");


		$gists->limit($paginator->itemsPerPage,
		              $paginator->offset);

		$this->template->gists = $gists;

	}


	public function handleTest()
	{
		if ($this->isAjax())
			$this->forward('default', 'php'); // na <renderDefault> s argumentem $slug = php
	}


	public function beforeRender()
	{
		parent::beforeRender();
		$this->template->labels = $this->modelGistLabel->findAll()->order('title ASC');
		$this->template->labelsCnt = $this->modelGistGistLabel->findAll()
															  ->select('COUNT(1) AS cnt, gist_label_id')
															  ->group('gist_label_id')
															  ->fetchPairs('gist_label_id', 'cnt');

	}



}

Editoval Kcko (11. 11. 2018 17:22)

Phalanx
Člen | 310
+
0
-

@Kcko Nejjednodušší možný případ:

<?php

/** string|null @persistent */
public $q;

function handleSearchForm($form, $values)
{
	$this->q = $values->q;
    if ($this->isAjax())
    {
		// tento řádek tu volat nemusíš, protože redrawControl projde přes renderSearch
        // $this->template->gists = $this->model->findGistBySearch($values->q);
        $this->redrawControl("gists");
    }
    else
    {
        $this->redirect("search");
    }
}

function renderSearch()
{
    $this->template->gists = $this->model->findGistBySearch($this->q);
    // ... atd
}

?>

Editoval Phalanx (12. 11. 2018 8:38)

Kcko
Člen | 465
+
0
-

@Phalanx Díky za reakci. Překreslí, ale nezmění URL.

Jak jsem zkoušel (předchozí moje komentáře) všechno možné, tak mi bud jde změnit URL a nepřekreslí se snippet nebo obráceně.
Zkoušel jsem redirect nebo forward, zkoušel jsem zapnout history extenzi nebo vypnout, posílat do payloadu URL, nic z toho nevede k chtěnému výsledku:

  • překreslit snippet (resp forwardnout na správný render s q parametrem)
  • změnit url

Asi do toho hodíme vidle, nechci tady s tím otravovat do nekonečna.
Zkusím to vyřešit přesměrováním přes forward a vyřešit si tu změnu URL sám přes vlastní extenzi, která jen nějak tupě nastavovat URL (škoda, že to history extenze neřeší nebo je to prostě nefunkční).

Je zajímavé, že když použiji redirect, tak to history extenze pochopí, ale nepošle snipety a nemá se co překreslit.

Editoval Kcko (12. 11. 2018 10:47)

Phalanx
Člen | 310
+
0
-

Promiň, pořád jsem tě nechápal. Zkus ještě poslední věc:

<?php
if ($this->isAjax()) {
   $this->payload->url = $this->link('this', ['q' => $values->q]);
   $this->redrawControl('gists');
} else {
   $this->redirect('search', ['q' => $values->q]);
}
?>
Kcko
Člen | 465
+
0
-

Phalanx napsal(a):

Promiň, pořád jsem tě nechápal. Zkus ještě poslední věc:

<?php
if ($this->isAjax()) {
   $this->payload->url = $this->link('this', ['q' => $values->q]);
   $this->redrawControl('gists');
} else {
   $this->redirect('search', ['q' => $values->q]);
}
?>

Z renderDetail to pořád zlobí, URL se změní, ale obsah zůstane stejný.
Ze snippetu přijde pořád stejný obsah (tj renderDetail).
Už tomu fakt nerozumím.

Kašlem na to, holt ten Ajax oželím, díky za trpělivost a snahu to vyřešit.

Editoval Kcko (12. 11. 2018 13:01)

Kcko
Člen | 465
+
0
-

Vyřešeno.

Nakonec jsem použil history extenzi s tím, že jsem ji lehce upravil (co se týká chování formulářů s GET metodou), aby ony parametry rvala do URL + jsem vyhodil handle z obslužného formuláře a rovnou onen formulář nastavuji na renderSearch.

A je to celé ajaxové.