Nette\InvalidStateException, AJAX, komponenty a špatné využití snippetu?

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

Zdravím, tímto dotazem navazuji na toto vlákno.
Po kliknutí na řádek jisté tabulky volám handleDetails, ve které vytvářím instanci komponenty NotesList.

public function handleDetails()
{
    $idticket = $this->getParameter('idticket');
        $notesTable = $this->db->formNotesTable($idticket);
        $grid = $this->createGrid('notesg', $notesTable);
        new NotesList($grid);
        $this->invalidateControl('middle');
}

V NotesList vytvářím další komponentu:

class NotesList extends Nette\Application\UI\Control
{

    protected $notesGrid;

    public function __construct($grid)
    {
        parent::__construct();

        $this->notesGrid = $grid;
        $this->render();
    }

    public function render()
    {
        $this->template->setFile(__DIR__.'/NotesList.latte');
        $this->template->render();
    }

    public function createComponentNotesTable()
    {
        $notes = $this->notesGrid;
        $notes->addColumn('idnote', 'idnote');
        //atd.
	return $notes;
    }
}

Tu chci zobrazit v NotesList.latte:
{block middle}
{control notesTable}
{/block}
To dělám proto, abych sem ještě něco mohl vložit.

Blok middle mám podmíněně includenutý v @layout.latte a obaleny ve snippetu:
{snippet middle}{ifset #middle}{include #middle}{/ifset}{/snippet}

Nette ale přijde v logu se zvláštní zprávou: Component '' is not attached to Nette\Application\UI\Presenter. Takhle to vypadá.

Můj dotaz zní: co dělám špatně? Díky moc :)

P.S.: Jak by se dala jinak vykreslit komponenta podmíněně a AJAXem, až po kliknutí na řádek tabulky (volané jQuery)?

Editoval mere.gee (24. 7. 2013 10:09)

jiri.pudil
Nette Blogger | 1032
+
0
-

Podívej se, jakým způsobem inicializuješ NotesTable a jakým NotesList. Jeden z nich je správný, druhý je příčinou tvého problému. (hint)

mere.gee
Člen | 54
+
0
-

jiri.pudil napsal(a):

Podívej se, jakým způsobem inicializuješ NotesTable a jakým NotesList. Jeden z nich je správný, druhý je příčinou tvého problému. (hint)

Takhle to je správně?

	public function handleDetails()
{
    $this->idticket = $this->getParameter('idticket');
    $this['notesList'];
    $this->invalidateControl('middle');
}

public function createComponentNotesList() {
    $notesTable = $this->db->formNotesTable($this->idticket);
    $grid = $this->createGrid('notesg', $notesTable);
    return new NotesList($grid);
}
mere.gee
Člen | 54
+
0
-

S touhle úpravou se to pořád chová stejně. Chybu to začne totiž hlásit až když se volá metoda render() té třídy NotesList a program se pokouší vykreslit příslušný template. Pak asi hledá nějakou bezejmenou komponentu (jakou?), která není „připojená“ na UI\Presenter – což nevím, co znamená. Všechno, co mě napadá, mě vede k tomu prohlásit, že chyba je někde v Nette, ale já pořádně nevím, jak nette funguje, proto se ptám odborníků :)

David Matějka
Moderator | 6445
+
0
-

v NotesList nemuzes v konstruktoru volat hned render

mere.gee
Člen | 54
+
0
-

matej21 napsal(a):

v NotesList nemuzes v konstruktoru volat hned render

A jak mám inicializovat to vykreslení? Ta createComponentNotesTable se zavolá, až když se při vykreslování narazí na {control notesTable}… Mám ty komponenty nějak připojit k presenteru pomocí monitorů , aby věděli, jaký presenter je vykresluje? Nejsem si jistý, že jim rozumím…

David Matějka
Moderator | 6445
+
0
-

pockej, rekni, co chces udelat.. cely je to tam nejaky divny a nemuze to fungovat (ten block z komponenty se ti do layoutu dostat nepovede)

mere.gee
Člen | 54
+
0
-

Píšu to nahoře – chci na sigál (detail) vedle tabulky s daty zobrazit tabulku s detaily (komponentu s komponentou (datagridem) a mnou v šabloně definovaným obsahem) pomocí ajaxu.

David Matějka
Moderator | 6445
+
0
-

tak dej do presenteru:

public function handleDetails()
    {
        $this->idticket = $this->getParameter('idticket');
        $this->showNotesList = TRUE;
        $this->invalidateControl('middle');
    }

    public function createComponentNotesList() {
        $notesTable = $this->db->formNotesTable($this->idticket);
        $grid = $this->createGrid('notesg', $notesTable);
        return new NotesList($grid);
    }

a do sablony presenteru presun ten snippet z layoutu (nebo ho tam potrebujes?)

{snippet middle}
	{default $showNotesList = FALSE}
	{if $showNotesList}
		{control notesList}
	{/if}
{/snippet}
mere.gee
Člen | 54
+
0
-

{control notesTable} v NotesList.latte mi nevolá továrničku createComponentNotesTable, která je definovaná ve třídě, která renderuje NotesList.latte (NotesList.php) – píše to, že neexistuje komponenta se jménem notesTable… Přece jí nemusím definovat v prezenteru, ne?

mere.gee
Člen | 54
+
0
-

Tak jsem v NotesList.latte zapomněl odstranit definici bloku, ve kterém by se měla komponenta objevit; teď už to chybu nehlásí. Což je škoda, protože to pořád nefunguje :)

Odezva serveru zní: {„state“:[],„snippets“:{„snippet–middle“:""}} a vrací JSON: snippet–middle=""…

David Matějka
Moderator | 6445
+
0
-

zkus si to nejdriv zprovoznit bez ajaxu

mere.gee
Člen | 54
+
0
-

To udělat nemůžu, ten handler volám takhle:

<script>
$('table#dashboard tbody tr').click(function(){
    var idticket = $(this).children('td.grid-cell-idticket').text().replace(/\s/g, '');
    $.ajax({
        url: {link details!},
        type: 'GET',
        data: { 'idticket' : idticket }
     });
});
</script>

Musel bych udělat něco jako: window.location.replace("{link details! … no a jak teď předat ten var idticket?

David Matějka
Moderator | 6445
+
0
-

koukni se do nejaky konzole v prohlizeci, na jakou url to posila pozadavek (v chrome F12 a zalozka network); nebo staci pridat k url parametry ?do=details&idticket=123456

kdyz na tu url pudes, tak se to bude chovat stejne, jen to nebude ajaxovy

mere.gee
Člen | 54
+
0
-

Vrací to tu samou stránku, ta komponenta notesTable se vůbec nevykresluje… Vlastně se nevykreslí nic z NotesList.latte.

Editoval mere.gee (24. 7. 2013 15:54)

David Matějka
Moderator | 6445
+
0
-

jo, jsem idiot, v handleDetails ma byt samozrejme

public function handleDetails()
    {
        $this->idticket = $this->getParameter('idticket');
        $this->template->showNotesList = TRUE;
        $this->invalidateControl('middle');
    }

zapomnel jsem na template :)

mere.gee
Člen | 54
+
0
-

To jsem zkoušel změnit, pak to řve, že neexistuje ‚notesTable‘… Říkal jsem si, že možná musí být v prezenteru, viz 10. příspěvek… No, ale když jí přesunu tam, tak jí pořád nemůže najít :) A vymazat cache nepomůže…

Editoval mere.gee (24. 7. 2013 16:18)

David Matějka
Moderator | 6445
+
0
-

ne, ta tovarnicka musi byt v NotesList, jak vytvaris tu grid? v createGrid?

mere.gee
Člen | 54
+
0
-

notesTable JE ten grid

V NotesList.php:

public function createComponentNotesTable()
    {
        $notes = $this->notesGrid;
        $notes->addColumn('idnote', 'idnote');
        $notes->setPrimaryKey('idnote');
        $notes->addColumn('note_type', 'Typ');
        $notes->addColumn('note_subject', 'Předmět');
        $notes->addColumn('note_worktime', 'Hodiny');
        $notes->addColumn('note_state', 'Stav');
        $notes->addColumn('note_priority', 'Priorita');
        $notes->addColumn('note_delivery', 'Do', Grido\Components\Columns\Column::TYPE_DATE);
        $notes->addColumn('note_created', 'Vytvořeno', Grido\Components\Columns\Column::TYPE_DATE);
        return $notes;
    }

A obsah NotesList.latte (zatím):
{control notesTable}

Editoval mere.gee (24. 7. 2013 16:20)

mere.gee
Člen | 54
+
0
-

Promiň, asi jsem tě špatně pochopil – createGrid je metody BasePresenteru, od kterýho dědí ten presenter, v kterém vytvářím NotesList

public function createComponentNotesList() {
    $notesTable = $this->db->formNotesTable($this->idticket);
    $grid = $this->createGrid('notesg', $notesTable); //Vytvoří instanci Grido\Grid
    return new NotesList($grid);
}
David Matějka
Moderator | 6445
+
0
-

ukaz mi, jak vytvaris tu instanci Grido\Grid v createGrid

mere.gee
Člen | 54
+
0
-
public function createGrid($name, $table)
    {
        $lang = new Grido\Translations\FileTranslator();
        $lang->setLang('cs');
        $grid = new Grido\Grid($this, $name);
        $grid->setModel($table);
        $grid->setTranslator($lang);
        return $grid;
    }

To by ale mělo být v pořádku, v dřívějších verzích toho programu to fungovalo…

David Matějka
Moderator | 6445
+
0
-

no to je spatne, protoze to pripojujes k presenteru pod jmenem notesg, musi to byt pripojeno k te komponente pod nazvem notesTable.
standardne komponenty nevyzaduji okamzite pripojeni k presenteru, zkus tedy pri instancovani Grid neposilat $this a $name, at si to nette udela samo

mere.gee
Člen | 54
+
0
-

Výborně, tak jsem vytvořil tu instanci gridu přímo v továrničce na notesList a teď to funguje, ale jenom bez ajaxu. Teď už zbývá jenom zjistit, proč nefunguje ten ajax…

mere.gee
Člen | 54
+
0
-

Odezva už je v pořádku… Takže to bude tou invalidací…
default.latte:
{block content}

{snippet middle}
{default $showNotesList = FALSE}
{if $showNotesList}
{control notesList}
{/if}
{/snippet}
{/block}

DashboardPresenter.php:

	public function handleDetails()
{
    $this->idticket = $this->getParameter('idticket');
    $this->template->showNotesList = TRUE;
    $this->invalidateControl('middle');
}

public function createComponentNotesList() {
    $lang = new Grido\Translations\FileTranslator();
    $lang->setLang('cs');
    $notesTable = $this->db->formNotesTable($this->idticket);
    $grid = new Grido\Grid();
    $grid->setModel($notesTable);
    $grid->setTranslator($lang);
    return new NotesList($grid);
}

A <script src=„{$basePath}/js/nette.ajax.js“></script> v layoutu… A ano, mám to až za ajaxem a je to inicializované v main.js… Co nesedí?

Editoval mere.gee (24. 7. 2013 17:49)

mere.gee
Člen | 54
+
0
-

Dobrá, už to funguje jak má! Jsem ti hrozně moc vděčný, Matěji… Chyba byla v tom, že jsem tady místo $.nette.ajax psal $.ajax…

<script>
$('table#dashboard tbody tr').click(function(){
    var idticket = $(this).children('td.grid-cell-idticket').text().replace(/\s/g, '');
    $.nette.ajax({
        url: {link details!},
        type: 'GET',
        data: { 'idticket' : idticket }
     });
});
</script>

Jaký je v tomhle případě rozdíl, když volám $.nette.ajax a $.ajax? Ve zpracování té odpovědi?

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

$.ajax() je prostá obyčejná metoda jQuery. Vytvoří ajaxový požadavek. Její API je zde: http://api.jquery.com/jQuery.ajax/.

Metoda $.nette.ajax() je metodou doplňku, a prakticky dělá to samé, co výše zmíněná starší sestra, až na to, že do vytvořeného requestu zahookuje všechny registrované extenze.

mere.gee
Člen | 54
+
0
-

vojtech.dobes napsal(a):

$.ajax() je prostá obyčejná metoda jQuery. Vytvoří ajaxový požadavek. Její API je zde: http://api.jquery.com/jQuery.ajax/.

Metoda $.nette.ajax() je metodou doplňku, a prakticky dělá to samé, co výše zmíněná starší sestra, až na to, že do vytvořeného requestu zahookuje všechny registrované extenze.

Ale já jsem žádné extenze neregistroval… Takže některé vytváří automaticky?

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

U doplňků, které používáš, jistě čteš dokumentaci, že :) ?

mere.gee
Člen | 54
+
0
-

vojtech.dobes napsal(a):

U doplňků, které používáš, jistě čteš dokumentaci, že :) ?

Více či méně pozorně :) Podívám se tam, díky…