Zobrazení/skrytí více formulářů pomocí Ajaxu
- flamengo
- Člen | 135
Mám dotaz ohledně zobrazování a následného schovávání formulářů po kliknutí na patřičný odkaz (tlačítko). Tlačítka a formuláře jsou v komponentě asi takto:
sablona.latte
<p>
<a n:href="showForm! form1" class="ajax">Formulář 1</a>
<a n:href="showForm! form2" class="ajax">Formulář 2</a>
<a n:href="showForm! form3" class="ajax">Formulář 3</a>
</p>
{snippet form}
{if $formShowed == 'form1'}
{control form1}
{elseif $formShowed == 'form2'}
{control form2}
{elseif $formShowed == 'form3'}
{control form3}
{/if}
{/snippet}
Výňatek z komponenty asi takto:
control.php
public $formShowed = '';
public function render(){
$this->template->formShowed = $this->formShowed;
$this->template->setFile(__DIR__ . '/sablona.latte');
$this->template->render();
}
public function handleShowForm($id){
if($this->formShowed == $id) $this->formShowed = '';
else $this->formShowed = $id;
if($this->presenter->isAjax()){
$this->redrawControl('form');
}
}
Názvy formulářů jsou vymyšleny, ve sktutečnosti mají reálné názvy a každý formulář má jinou funkci.
Idea je taková, abych kliknul na tlačítko Formulář 1
a
zobrazil se mi daný formulář form1
. Kliknu na tlačítko
Formulář 2
a zobrazí form2
(form1
zmizí). A ono to i funguje.
Ale ještě bych rád, aby když kliknu podruhé na tlačítko
Formulář 2
(po prvním kliknutí se formulář zobrazil), tak aby
tento formulář zmizel a snippet zůstal prázdný. Očekával jsem, že toho
docílím tímto kódem:
if($this->formShowed == $id) $this->formShowed = '';
else $this->formShowed = $id;
ale nestalo se tak. V metodě handleShowForm() proměnná
$this->formShowed
zřejmě obsahuje hodnotu z url odkazu
tlačítka ještě před přiřazením. Podmínka
if($this->formShowed == $id)
tedy není splněna. Očekával
jsem, že v této proměnné bude uložena hodnota z minulého volání.
Jistě to bude nějaká prkotina, budu rád za každou pomoc či nakopnutí či prozrazení jiného fíglu, jak docílit požadované.
- xrep
- Člen | 51
mozno by stalo za uvazenie .hide() (jQuery) ?
inak formShowed property bude pri kazdom requeste „null“. Aby to nebolo
null, tak by si ten parameter mal mat @persistent (to sa mi ale nejako
nepodarilo rozbehat v tomto pripade).
Dalsia moznost je ulozit si posledny zobrazeny form do cookie napr. takto:
<?php
public function handleShowForm( $id ){
if( $this->isAjax() ){
$lastForm = $_COOKIE[ 'lastForm' ];
if ( $lastForm == $id ) {
$this->template->formShowed = null;
setcookie('lastForm', 'empty');
}
else {
setcookie('lastForm', $id );
$this->template->formShowed = $id;
}
$this->redrawControl('form');
}
}
?>
to ti fungovat bude.
Ale to moje riesenie ber s rezervou, neviem nakolko je to „idealne“ a niekto ti pravdepodobne poradi lepsie, ja som noob :)
- Unlink
- Člen | 298
Tak môžeš si aj tie linky odpodmienkovať
<a n:if="$formShowed!='form1'" n:href="showForm! form1" class="ajax">Formulář 1</a>
<a n:if="$formShowed!='form2'" n:href="showForm! form2" class="ajax">Formulář 2</a>
<a n:if="$formShowed!='form3'" n:href="showForm! form3" class="ajax">Formulář 3</a>
<a n:if="$formShowed!=''" n:href="hideForm! " class="ajax">Schovaj formulář</a>
a potom pridať handle na hideForm
Editoval Unlink (14. 9. 2015 21:05)
- flamengo
- Člen | 135
jQuery
Pomocí jQuery by to určitě šlo, ale vzhledem k účelu aplikace to není
vhodné řešení. Na stránce bude cca 20 příspěvků a tyto formuláře
budou pod každým z nich a bude jich 5: 3 formuláře a 2 tabulky
obsahující až několik desítek řádků. Kdybych načetl vše a poté
schoval pomocí jQuery, byl by objem přenesených dat do prohlížeče
několikanásobně vyšší a já bych rád, aby to hlavně na mobilech bylo
svižný.
Persistent
Změna parametru na persistent
nepomohla. Zobrazování
formulářů přestalo fungovat úplně.
/** @persistent string */
public $formShowed = '';
Podmínkování linků
Tato možnost mě napadla, ale abych se přiznal, moc se mi to nelíbilo. Asi
kvůli potřebě psát další handler a komplikovat trochu šablonu.
$_COOKIE
Použití $_COOKIE mě vůbec nanapadlo, zkusil jsem a funguje pěkně. Kód
jsem trochu předělal, protože jak jsem uvedl výše, jedná se formuláře
pro více položek na jedné stránce.
public function handleShowForm($formShowed){
$id = $this->itemId;
if(isset($_COOKIE['lastForm'][$id]) && $_COOKIE['lastForm'][$id] == $formShowed){
$formShowed = NULL;
}
setcookie('lastForm['.$id.']', $formShowed);
$this->formShowed = $formShowed;
if($this->presenter->isAjax()){
$this->redrawControl('form');
}
else{
$this->presenter->redirect('this');
}
}
Do konstruktoru jsme musel přidat unset($_COOKIE['lastForm']);
,
protože když jsem např. u první položy kiknul na
Formulář 1
, tak se zobrazil a pokdu jsem potom proved reload
stránky a znova u té samé položky kliknul na Formulář 1
, tak
proměnná již obsahovala hodnotu a vlastně formulář chtěla schovat a nic
se nestalo.
No a nakonec jsem si to předělal do SESSIONS, což mi přijde vhodnější vzhledem k požadavkům na funkci.
public function handleShowForm($formShowed){
if($this->sessionSection->formShowed == $formShowed) $formShowed = NULL;
$this->sessionSection->formShowed = $formShowed;
$this->formShowed = $formShowed;
if($this->presenter->isAjax()){
$this->redrawControl('form');
}
else{
$this->presenter->redirect('this');
}
}
V konstruktoru jsme vynuloval proměnnou
$this->sessionSection->formShowed = NULL;
(stejný problém
při reloadu stránky jako s COOKIE).
Díky všem za názory!
- flamengo
- Člen | 135
Malá oprava. Po přidání
$this->sessionSection->formShowed = NULL;
do konstruktoru
přestalo fungovat schovávání. Zkoušel jsem to předtím a měl jsem za to,
že to fungovalo, nevím.
Místo toho jsem tam dal
$this->formShowed = $this->sessionSection->formShowed;
. Po
reloadu se tedy zobrazí předtím otevřený formulář, takže
přípustné.
- Unlink
- Člen | 298
No konštruktor sa volá vždy, takže aj pri tom ajaxovom požiadavku. Ak to chceš vynulovať tak v príslušnej render metóde to nejako rozumne odpodmienkovať.
Len ak takto používaš session, tak to začne robiť srandovné veci ak si to otvoríš v dvoch oknach naraz.
Ja by som tie podmienky nezavrhoval, a čo takto?
<a n:href="showForm! $showForm == 'form1' ? '' : 'form1'" class="ajax">Form 1</a>
<a n:href="showForm! $showForm == 'form2' ? '' : 'form2'" class="ajax">Form 2</a>
<a n:href="showForm! $showForm == 'form3' ? '' : 'form3'" class="ajax">Form 3</a>
public function handleShowForm($form) {
$this->showForm = $form;
if ($this->isAjax()) {
$this->redrawControl('form');
}
}
Editoval Unlink (15. 9. 2015 17:26)
- flamengo
- Člen | 135
Nevěděl jsem, co se přesně děje při Ajaxovým požadavku a to, že se konstruktor volá také mi už došlo. Škoda, že jsem to nevěděl dřív, ušetřil bych si nervy :) Každopádně díky za potvrzení této mé domněnky.
Hm ve více oknech při použití Session
to nefunguje jak má,
to je jasné.
Dal jsem tedy na tvou radu a funguje to vlastně přesně tak, jak jsem chtěl hned na začátku, takže velké díky.
Ale jeden menší zádrhel se opět vyskytnul. Pokud zobrazím
Formulář 1
a pomocí Ajaxu ho odešlu a poté bych ho chtěl
překreslit a vynulovat hodnoty a zobrazit také flash zprávu, tak šablona
vlastně neví, jaký formulář zobrazit.
public function processForm1(Form $form){
...
$this->flashMessage('Formulář 1 zpracován', 'alert-info');
$form->setValues(array(), TRUE);
if($this->presenter->isAjax()){
$this->redrawControl('flashes');
$this->redrawControl('form');
}
else{
$this->presenter->redirect('this');
}
}
Napadá tě jak z toho ven? :)
Přidat do adresy zpracování formuláře nějaký GET parametr nebo tak něco?
Jde to vůbec?
Editoval flamengo (15. 9. 2015 19:36)
- Unlink
- Člen | 298
No veď v tej process metóde vieš ktorý form si spracoval
takže pri ajaxovom požiadavku by malo stačiť
$this->showForm = 'form1';
ale pri tom klasickom možno
$this->presenter->redirect('showForm! form1');
ale niesom si
isty či sa dá spraviť redirect aj na signál, ak nie tak pomocou nejakého
parametra $this->presenter->redirect('this form=>form1');
plus úprava render metódy
- flamengo
- Člen | 135
Díky díky! Už jsme na to přišel taky a opravdu stačilo přídat
$this->showForm = 'form1';
do metod pro zpracování
formulářů (processForm1
). Takže snad již hotovo, uvádím
rekapitulaci kdyby se s tím někdo někdy pral jako já :D
Komponenta.php
class Komponenta extends \Nette\Application\UI\Control{
/** @var string */
public $showForm = '';
public function render(){
$this->template->showForm = $this->showForm;
$this->template->setFile(__DIR__ . '/komponenta.latte');
$this->template->render();
}
public function handleShowForm($showForm){
$this->showForm = $showForm;
if($this->presenter->isAjax()){
$this->redrawControl('forms');
}
else{
$this->presenter->redirect('this');
}
}
protected function createComponentForm1(){
$form = new Form();
$form->getElementPrototype()->class('ajax');
$form->addText('example', 'Příklad:');
$form->addSubmit('send', 'Vložit');
$form->onSuccess[] = array($this, 'processForm1');
return $form;
}
public function processForm1(Form $form){
// nějaký kód pro zpracování formuláře
// ....
$this->flashMessage('Formulář 1 zpracován.', 'alert-info');
$this->showForm = 'form1'; // tímto docílím zobrazení správného formuláře v šabloně
if($this->presenter->isAjax()){
$this->redrawControl('forms');
$form->setValues(array(), TRUE); // vynulování hodnot
}
else{
$this->presenter->redirect('this');
}
}
komponenta.latte
{snippet forms}
<p>
<a n:href="showForm! showForm != 'form1' ? 'form1'" class="ajax">Form 1</a>
<a n:href="showForm! showForm != 'form2' ? 'form2'" class="ajax">Form 2</a>
<a n:href="showForm! showForm != 'form3' ? 'form3'" class="ajax">Form 3</a>
</p>
<div n:foreach="$flashes as $flash" n:class="$flash->type">
{$flash->message}
</div>
{if $showForm == 'form1'}
{control form1}
{elseif $showForm == 'form2'}
{control form2}
{elseif $showForm == 'form3'}
{control form3}
{/if}
{/snippet}