Načtení nových dat do bloku po události onclick

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

Ahoj, pročetl jsem snad všechny topicy o ajaxu a přečet všechno, co jsem mohl, vč. manuálu ze školení, ale pořád nějak nemám tušení, jak vyřešit následující problém:
Stránka se skládá z několika různých bloků, který se navzájem nějak ovlivňujou – zkrátka při provedení akce v jednom, se musej načíst nový data z db v dalšim, nebo dalších blocích a navíc se vykonat nějaký JS funkce (změna stylu).

Bez použití nette, bych to řešil jednoduše, že např. na ajaxovej odkaz v jednom bloku bych dal do onclicku nějakou funkci, která by 1) vykonala JS a za 2) pomocí jQuery pluginu funkcí ajax_loadcontent bych si zavolal skript s parametrama přes get, kterej chci vykonat a jeho výsledek by se vložil do požadovanýho bloku.

Jak takovou věc udělám v nette? Představuji si, že obsah jednotlivých bloků by generovaly jednotlivý funkce presenteru, jenže, jak uděat, aby se hned zezačátku ty bloky samy naplnily těma funkcema – jen bez parametrů a po kliknutí na nějakej odkaz, se pomocí onclick, vykonal nějakej js příkaz (např změnna class u nějakýho bloku) a ještě navíc se zavolala ta funkce presenteru, který bych předal ty parametry a ona se ajaxově znovu načetla přímo do toho divu, jehož ID znám, přičemž by brala v potaz ty parametry a tudíž změnila obsah?

Díky za každou radu :)

Editoval Why?! (27. 10. 2010 1:00)

Ondrej
Člen | 110
+
0
-

Why?! napsal(a):

Bez použití nette, bych to řešil jednoduše, že např. na ajaxovej odkaz v jednom bloku bych dal do onclicku nějakou funkci, která by 1) vykonala JS a za 2) pomocí jQuery pluginu funkcí ajax_loadcontent bych si zavolal skript s parametrama přes get, kterej chci vykonat a jeho výsledek by se vložil do požadovanýho bloku.

S použitím nette, bych to řešil jednoduše: bloky bych obalil do snippetů, na ajaxovej odkaz v jednom bloku bych dal do onclicku nějakou funkci, která by 1) vykonala JS a za 2) pomocí jQuery a AJAX Nette Framework pluginu for jQuery, bych si ajaxově zavolal skript, kterej chci vykonat, ve skriptu bych invalidoval pojmenované snippety k aktualizaci a výsledek se vloží do požadovaných snippetů.

Why?!
Člen | 15
+
0
-

Díky, dost jsi mi to přiblížil, začínám v tom mít jasněji, už fakticky nevím/nechápu jen dvě věci:

  1. Jakou syntaxí si pomocí jQuery a AJAX Nette Framework pluginu for jQuery zavolám skript Presenter:action, když bude dejme tomu v nějaké fci, která bude v externim .js souboru?
  2. Proč je výsledek v nějakém formátu JSON, kterej ani teď nevím, jak vypadá a nevyhodí mi to rovnou html, který vlastně potřebuju?
Aurielle
Člen | 1281
+
0
-
  1. Pokud to chceš mít v externím souboru tak musíš zpracovávat JS skripty WebLoaderem nebo něčím podobným, protože LatteFilter se tam nedostane…
  2. V JSONu se jednak posílá HTML a jednak i stav snippetů…
Ondrej
Člen | 110
+
0
-
  1. https://componette.org/search/?…
  2. odpoved obsahuje html pro vsechny aktualizovane bloky.
Why?!
Člen | 15
+
0
-

Tak jsem si s tím hrál, a nevím si pořád rady :( Kód je níže… Potřebuji, když kliknu na odkaz <a href="#" onclick="ajaxrefresh(1);">atualizuj snippet s id 1</a>, aby se aktalizoval snippet a to tak, aby se znovunačtená akce v presenteru function handleLoadFiltry_ulozene($id) zavolala s parametrem 1, jenže nevím, jak to v tom externim js souboru poslat do presenteru, aby se to vykonalo, navíc se mi zdá, že to vůbec nic nedělá

Presenter WallPresenter.php:

<?php
class WallPresenter extends BasePresenter
{
    private $wallModel;

    function startup()
    {
        parent::startup();
        if (!$this->user->isLoggedIn()) {                // kontrola, jestli je přihášenej
            $this->flashMessage('Abyste mohl sledovat zeď, musíte se přihlásit.');
            $this->redirect('Sign:in');
        }
    }
    public function handleLoadFiltry_ulozene($id) {

      if ($this->presenter->isAjax()) {
                      if ($id==1) $filtry_ulozene=0;
                      else $filtry_ulozene=array(1=>"první položka", 2=>"druhá položka");
                      $this->invalidateControl('filtry_ulozene');
                      $this->presenter->terminate();
      } else {
              $this->presenter->redirect('this');
      }
      $this->presenter->sendPayload();
    }
}

Šablona:

{block content}
          <h2>Uložené filtry</h2>
          {snippet filtry_ulozene}
            {if empty($filtry_ulozene)}
                <div class="info2" id="rychlyfiltr">Nemáte uložený žádný filtr. Uložení stavu filtru vám umožní tento stav později jediným klikem vyvolat. Pokud například označíte všechna políčka filtru, můžete si vytvořit rychlý filtr "vše", po jehož stisknutí se na zdi zobrazí všchny kategorie. Začněte kliknutím na ikonku pro uložení.</div>
            {else}
                <ul id="rychlyfiltr">
                {foreach $filtr as $id => $nazev}
                <li><a href="#zpr">{$nazev}</a><span class="ikonyvpravo"><a onclick="spanner{$id}" title="settings" class="ico_settings"></a><a href="#" title="drag" class="ico_drag"></a></span></li>
                {/foreach}
                </ul>
            {/if}
          {/snippet}
          <a href="#" onclick="ajaxrefresh(1);">atualizuj snippet s id 1</a>
          <a href="#" onclick="ajaxrefresh(2);">atualizuj snippet s id 2</a>

V nalinkovaném js sobor mám:

function ajaxrefresh(id)
{
    event.preventDefault();
    $.get(link loadFiltry_ulozene);    // a jak si předám ten parametr ID?
}

Díky za trpělivost, jsem ještě lama :)

Editoval Why?! (28. 10. 2010 14:02)

Aurielle
Člen | 1281
+
0
-

https://componette.org/search/?… !!
A odkaz uděláš pomocí {link loadFiltry_ulozene} (+ ještě musíš předat ID)

Podívej se na http://banlist.battleforce.cz, tam mám funkční AJAX (rozklikávací řádky té tabulky).

Why?!
Člen | 15
+
0
-

Nepomáhá… Tu stránku už jsem několikrát pročet a pomocí ní jsem udělal ten kód, co je výše, průběžně h aktualizju podle toho co se dovim. Mám to tam nalinkovaný a jediný co jsem se v tom manuálu dozvěděl je, že tam mám dát někam $.get("someUrl"); – ale kam a jak, jak tam dám link na presenter a akci (už jsem to udělal jak jsi říkal ale pořád to nefunguje), jak pošlu parametry, třeba to ID? Nevím, a to už jsem tam nenašel :(

Tady všichni předpokládaj, že takový „jednodchosti“ jsou každýmu zřejmý, ale já s tim nikdy nedělal, js umim okrajově a nette trochu ze školení, jenže tam už na ajax nebylo moc času… Já ten princip asi chápu, bez nette jsem ajax přes jquery normálně úplně jednodše používal…

Jen prostě nevim, jak to mam zapsat syntaxí, potřeboval bych nějakou ukázku kde to takhle funguje, nebo přesně upravit ten kód výše, co mám napsat jinak… Ta tvoje ukázka je sice hezká a tak nějak bych si to představoval, jenže k čemu mi je, když nevidím do její vnitřní struktury.. :)

Editoval Why?! (28. 10. 2010 14:03)

Aurielle
Člen | 1281
+
0
-
  1. Funkci zajišťující AJAX submit nemůžeš mít v externím souboru – makro link se tam nezpracuje…
  2. Podívej se na tohle:
$('tr.ajax').live('click', function(event) {
	event.preventDefault();
	if ($.active) return;

	$.post({link banDetails!}, { id: this.id.substr(4) }, function(payload) {
		$.nette.success(payload);
		$('#ban-details').hide();
		$.fancybox($('#ban-details').html(), {
			'autoDimensions': true,
			'autoScale': false,
			'scrolling': 'no',
			'onComplete': function() {
				$.fancybox.resize();
			}
		});
	});

	$.nette.spinner.css({
		position: 'absolute',
		left: event.pageX,
		top: event.pageY
	});
});
	public function handleBanDetails($id)
	{
		/** Zpracovani **/

		$this->template->bannedFrom = $bannedFrom;
		$this->template->blocked = $timesBlocked;
		$this->invalidateControl('bandetails');
	}
{snippet bandetails}
<div id="ban-details">
@{if isset($ban)}
{* Kod uvnitr snippetu, nezapomen na zavinace (jen v 2.0 alpha + 0.9.x, v 2.0 dev momentalne snippety nejdou *}
@{/if}
</div>
{/snippet}
Why?!
Člen | 15
+
0
-

No, možná se někomu bude zdát že jsem natvrdlej… :-)) ale pořád tomu nerozumím, ten js teda patří do hlavní šablony toho presenteru?

a tím $('tr.ajax').live('click', function(event) určuješ fci, co se má vykonat po kliknutí na element tr s třídou ajax? Kde si v tom kódu posíláš to ID, který se objeví jako parametr fce v presenteru?

Ta druhá část je z presenteru a říkáš tam, že template tý fce je nějaká proměnná, tu získáš z modelu? Co v ní je? A tím si nějak zalinkuješ, aby se pro ten snippet použil nějakej konkrétní template, kterej vypadá tak, jak jsi napsal?

A do templatu si ho pak vložíš normálně {include #bandetails} ?

Omlouvám se za tolik otázek, ale nemám funkční příklad, kde by fungoval odkaz posílající parametry do fce presenteru, ze kterýho bych to snad nějak vykoumal :( Nemá náhodou někdo něco takovýho? Jestli ne, tak pokud se mi to podaří vyřešit, mohl bych to tu poskytnout, protože myslím, že takový základní příklad použití by ulehčil cestu mnoha lidem :) Pak už se to dá modifikovat na všechno, třeba na akci onkeyup s tím, že jako parametr se pošle aktuální value inputu a může to bejt třeba našeptávač… zkrátka se s tim už pak dá udělat skoro cokoliv, ne? (nebo aspoň co si já dovedu představit…)

Dík za trpělivost :))

Editoval Why?! (2. 11. 2010 1:07)

Aurielle
Člen | 1281
+
0
-
	$.post({link banDetails!}, { id: this.id.substr(4) }, function(payload) {
        $.nette.success(payload);
        $('#ban-details').hide();
        $.fancybox($('#ban-details').html(), {
                'autoDimensions': true,
                'autoScale': false,
                'scrolling': 'no',
                'onComplete': function() {
                        $.fancybox.resize();
                }
        });
});

Tato část zajišťuje, že po kliknutí se zavolá POST požadavek. ID mám uložené jako ID přímo u toho řádku a vytáhnu si je pomocí substr. A poté function(payload) zajistí akci, která se provede po vykonání požadavku, tzn. zobrazení fancyboxu a opětovné skrytí obsahu snippetu (nechci ho mít na stránce 2×)

K tvým dalším dotazům – do templatu nic nevkládám. Díky řádku $.nette.success(payload); se mi aktualizují všechny změněné snippety. Tzn. že kdybych ho nechtěl zobrazit ve fancyboxu, tak nechám snippet zobrazený (nebudu na něj volat hide) a díky tomu se mi při úspěchu překreslí daný div novými daty.

handleXxx() metoda nepoužívá žádnou další šablonu (není to komponenta). Jak už jsem psal předtím, řádek invalidateControl('nazevSnippetu'); pošle nové HTML právě v JSONu zpátky a takto invalidovaný snippet se zaktualizuje o tato nová data.

Asi je to trochu chaotické, ale klidně se ptej nebo přijď na jabber…

Editoval gmvasek (2. 11. 2010 16:06)

Why?!
Člen | 15
+
0
-

Tak jsem se k tomu po delší době dostal, a chápu to zase o trochu víc, nicméně mi to pořád nejde. Tak jsem se to snažil maximálně zjednodušit a udělal jsem novej nette project, kde jsem v sandboxu změnil jen homepagepresenter a jeho template, ukázka zde: http://netteajax.whys.cz/root/

  • funkčnost týhle ukázkový aplikace má být taková: nad tlačítka se implicitně načte, že není zvolen žádný parametr. Po stitku tlačítka ovoce nebo zelenina se místo tohoto textu načte seznam ovoce nebo zeleniny, který předá presenter. Kód vypadá takto:

presenter:

class HomepagePresenter extends BasePresenter
{

	public function renderDefault()
	{
		$this->template->anyVariable = 'any value';
	}
  public function handleAjax_blok($id) {
            /** Zpracovani **/
      if ($id==1) $this->template->polozky = array ('jahoda', 'banán', 'jablko');
      elseif ($id==2) $this->template->polozky = array ('mrkev', 'okurka', 'zelí' );
      $this->template->blocked = $timesBlocked;
      $this->invalidateControl('ajax_blok');
  }
}

template:

{block content}

  {snippet ajax_blok}
    @{if empty($parametr)}
        <div class="info2" id="rychlyfiltr">Nemáte uložený žádný parametr.</div>
    {else}
        <ul id="ajax_blok">
        {foreach $parametr as $nazev}
        <li>{$nazev}</li>
        {/foreach}
        </ul>
    @{/if}
  {/snippet}


  <input type="submit" class="ajax-ovocezelenina" id="polozka-1" value="ovoce">
  <input type="submit" class="ajax-ovocezelenina" id="polozka-2" value="zelenina">

  <script type="text/javascript">
  $('input.ajax-ovocezelenina').live('click', function(event) {
  	event.preventDefault();
  	if ($.active) return;

  	$.post("\/?dalsiparametr=nejakejparametr", { id: this.id.substr(8) }, function(payload) {
  		$.nette.success(payload);
  		$('#ajax_blok').hide();
  		$.fancybox($('#ajax_blok').html(), {
  			'autoDimensions': true,
  			'autoScale': false,
  			'scrolling': 'no',
  			'onComplete': function() {
  				$.fancybox.resize();
  			}
  		});
  	});

  	$.nette.spinner.css({
  		position: 'absolute',
  		left: event.pageX,
  		top: event.pageY
  	});
  });
  </script>

… jenže to zase nic nedělá… :(

Aurielle
Člen | 1281
+
0
-

Snad se dneska dostanu k tomu že ti napíšu ukázkovou aplikaci… protože na fóru se vzájemně nepochopíme :D

Jen namátkově:

  • Zavináče do snippetu nepatří
  • Řádek $this->template->blocked = $timesBlocked do presenteru vůbec nepatří, to je jen další proměnná kterou jsem potřeboval já.
  • Fancybox a schování snippetu v šabloně taky nepotřebuješ, to používám akorát pro výpis banu ala „modální okno“…
Aurielle
Člen | 1281
+
0
-

Tak tady je demo AJAXu, postaveno na Nette 2.0-alpha pro PHP 5.3 a jde o skeleton s přidaným AJAXovým voláním. Doufám že aspoň tohle pomůže…

Why?!
Člen | 15
+
0
-

Díky :) Akorát, jak by se to lišilo v PHP 5.2? Já používám právě to…

Po zkoušení (zkopíroval jsem si do mýho nette pro php 5.2 tvůj presenter, layout a default template) jsem zjistil, že to funguje jenom když zadám ten link (http://netteajax.whys.cz/root/?…) přímo do url, ale ne, když na něj kliknu – to se nic nestane, tak chyba bude asi někde v tom js/ajaxu – když odmažu třídu ajax, tak to funguje bezajaxově. Ale zalinkovaný to v layoutu mám jako ty… Nebo to může bejt verzí toho PHP?

Editoval Why?! (9. 11. 2010 13:33)

Aurielle
Člen | 1281
+
0
-

V 5.2 to funguje úplně stejně. Nainstaluj si Firebug a podívej se co je špatně, mě to včera normálně fungovalo…

Why?!
Člen | 15
+
0
-

Jo, bylo to špatnym zalinkovánim ajax.nette :) Tak paráda, konečně se můžu posunout dál, díky moc! :)