Načtení hodnoty z databáze do textarey po výběru hodnoty ze selectu na formuláři

ForestCZE
Člen | 209
+
0
-

Ahoj, mám za úkol něco, s čím si nevím moc rady.

Mám tento formulář. Metoda, která připraví data pro select, vypadá takto:

public function getTemplatesAssoc(): array
{
	return $this->database->getTournamentTemplates()->fetchAssoc('id=name');
}
$form->addSelect('templates', null, $this->templates) // do $this->templates se pošle ta metoda
     ->setPrompt('Vyberte šablonu')
     ->setRequired('Vyberte šablonu.');

V databázi mám tabulku a v ní je name, info a prizes. Ve formuláři tedy vyberu Test, což je to jméno a v tu chvíli potřebuji z DB získat info a prizes a načíst je do těch dvou (textarea) info a ceny.

JS vypadá takto:

function templateChoosing()
{
    const template = document.querySelector("#frm-newTournament-templates");
    if(template !== null)
    {
        template.addEventListener("change", function(){
            var xhttp;
            xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function(payload){
                if(xhttp.readyState === 4 && xhttp.status === 200)
                    console.log(payload.test); // konzole vyhodí undefined
            };

            xhttp.open("POST", location.href, true);
            xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhttp.send();
        });
    }
}

V presenteru by se mělo stát něco jako:

if($this->isAjax())
{
	$this->payload->test = "test";
	$this->sendPayload();
}

Takže teoreticky vím, jak by to asi mělo fungovat, ale prakticky téměř vůbec.

Musím použít payload? Pokud ano, je nutné použít $.nette.ajax nebo mohu použít AJAX tak, jak ho mám napsaný ve vanilla JS? A jak na to? Pokud se nevyhnu payloadu, tak kdy a kde v tom presentru poslat ta data do JS? A jak vlastně vytáhnout data z té databáze na základě toho výběru, když ta položka má ID toho záznamu jako value? Možná na to jdu špatně a složitě. Budu vděčný za nějakou ukázku a vysvětlení. Děkuji moc předem.

Editoval ForestCZE (18. 3. 2021 8:33)

ForestCZE
Člen | 209
+
0
-

Vážně se nikdo nenajde? Nemuselo by to tahat až na základě toho change, můžou být ty data vytaženy klidně v šabloně najednou a nejspíš se obejdu i bez AJAXu, ale pořád nevím, jak to správně vytáhnout, když fetchAssoc vytáhne jen dvě hodnoty. A hlavně, jak to v JS zpracovat, abych načetl jen ty hodnoty, které potřebuju?

David Matějka
Moderator | 6445
+
0
-
  • ten callback, který dáváš do onreadystatechange nepříjímá přímo payload. když si to dumpneš, tak tam uvidíš field responseText, který musíš prohnat přes JSON.parse (více viz https://www.google.com/search?…)
  • ale XMLHttpRequest bych se úplně vyhnul a použil fetch api
  • a nevolej přímo location.href, ale signál v presenteru, který vrátí ten json (jestli přes payload nebo přímo přes this->sendJson je jedno)
dakur
Člen | 493
+
0
-

Nevím, jestli jsem to úplně dobře pochopil, ale jak to chápu, tak bych to udělal buď přes snippety nebo přes payload. Ty snippety mi přijdou jednodušší – select bude mít v <option value> ID šablony, to se po výběru requestem pošle na server, vyrenderují se v šabloně ty dvě textarea podle ID, které mi přišlo a pak invaliduješ snippety redrawControl().

Pomocí payloadu to děláš správně, akorát ten kód není zasazený do kontextu (např. v jaké metodě se co volá), takže těžko říct, proč to nefunguje. Když si před $this->payload->test něco dumpneš, tak se to zobrazí v response? Dobrý je pak debugger, pokud s ním umíš.

edit: too late :-)

Editoval dakur (25. 3. 2021 12:39)

ForestCZE
Člen | 209
+
0
-

@DavidMatějka Právě nevím, jak to je s tím signálem. Jsem zvyklý volat signál na odkazu, ale tady odkaz není, takže netuším kam s signal!

@dakur Jde o to, že mám nějaký easy formulář, který jednoduše insertne data do DB. Ještě předtím mám v administraci jakési šablony a ty jsou pak v selectu součástí toho formuláře. Ten formulář má dvakrát textareu, kde píšeš informace a mně jde o to, že místo textu ručně zadaného to vyplní textem z DB na základě výběru toho selectu.

Ten snippet zní dobře, ale asi v tom pořád hledám vědu a jsem zmatený, jak by to mělo být. Jde nějak jednoduše vytáhnout ty data z DB až po výběru, abych nemusel dělat API? Nebo si to mám vytáhnout předem a nějak s tím pracovat?

David Matějka
Moderator | 6445
+
+1
-

buď tam můžeš hardcodnout ?do=signalName nebo si někam – třeba do data atributu nějakého prvku nebo do nějaké JS variable, kterou naplníš v latte, uložíš tu URL, kterou pak v JS přečteš, třeba

<script>
var loadDataUrl = {link signal!}
</script>
dakur
Člen | 493
+
+1
-

@ForestCZE Já bych řekl, že payload je na data, snippety na HTML. Takže záleží, jestli chceš posílat obsah textarea nebo celou textareu. Při tom první musíš dostat obsah do tinymce, při druhém zas musíš reinicializovat tinymce. Každé má své využití, špatně není ani jedno. 🙂

ForestCZE
Člen | 209
+
0
-

dakur napsal(a):

@ForestCZE Já bych řekl, že payload je na data, snippety na HTML. Takže záleží, jestli chceš posílat obsah textarea nebo celou textareu. Při tom první musíš dostat obsah do tinymce, při druhém zas musíš reinicializovat tinymce. Každé má své využití, špatně není ani jedno. 🙂

Chtěl bych posílat pouze text. Takže v tomto případě payload?

dakur
Člen | 493
+
0
-

ForestCZE napsal(a):

Chtěl bych posílat pouze text. Takže v tomto případě payload?

Dává mi to smysl.

ForestCZE
Člen | 209
+
0
-

dakur napsal(a):

ForestCZE napsal(a):

Chtěl bych posílat pouze text. Takže v tomto případě payload?

Dává mi to smysl.

A mohu poprosit o nakopnutí? Půjde to ve vanilla JS?

dakur
Člen | 493
+
+1
-

No tak máš select, na jeho change události nasloucháš, vytáhneš si value toho option, který je vybraný – to bude ID řádku v DB. Pošleš fetch na server (něco jako fetch('GET', '/xyz?do=getData&id=X')), server sáhne do DB, do payloadu nacpeš info a prizes, to si v JS vezmeš a přes editor.setContent() nacpeš do tinymce.

Editoval dakur (25. 3. 2021 14:03)

ForestCZE
Člen | 209
+
0
-

@DavidMatějka a @dakur Funguje to bezvadně. Vážně moc děkuji, vážím si toho – vytrhnuli jste mi trn z paty :-)

Mám teď script.js a v něm:

function templateChoosing()
{
    const template = document.querySelector("#frm-newTournament-templates");
    if(template !== null)
    {
        template.addEventListener("change", function(){
            fetch('/?act=addtournament&template=' + this.value + '&do=getTemplate');
        });
    }
}

templateChoosing();

A signal v presentru:

public function handleGetTemplate($template): void
    {
        if(isset($template))
        {
            $getTemplate = $this->userManager->getTemplate(intval($template));
            $templateData = [];
            $templateData[] = $getTemplate->info;
            $templateData[] = $getTemplate->prizes;
            $this->payload->templateData = $templateData;
        }
    }

Jak se teď k tomu dostanu v tom JS? Může to být externě nebo ten script musí být v šabloně? Nějak mi to nedává smysl. Jak se JS dozví o tom, co je v presentru? Díky

ForestCZE
Člen | 209
+
0
-

David Matějka napsal(a):

viz treba https://developer.mozilla.org/…/Using_Fetch

Háže mi to error.

Na netu jsem se dočetl, že musím přidat headers:

fetch('/?act=addtournament&template=' + this.value + '&do=getTemplate', {
                headers : {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
               }
            })
            .then(response => response.json())
            .then(data => console.log(data));

Ale error trvá. S JSON nemám zkušenosti. Čím to je? PS. Vím, že už to nesouvisí s Nette, ale rád bych to dotáhnul :-)

EDIT: Vracelo to celou stránku. Musel jsem poslat JSON

$this->sendJson($templateData);

Editoval ForestCZE (26. 3. 2021 20:43)

dakur
Člen | 493
+
0
-

Jak se JS dozví o tom, co je v presentru?

K tomu právě slouží ten payload. Je to objekt typu stdClass (takže do něj můžeš nacpat, co chceš), který se při odeslání zpět na klienta serializuje (naformátuje) do datové struktury JSON pomocí PHP funkce json_encode(). Tomu rozumí i JS, takže si to na druhé straně zase rozparsuje a používáš to v JS jako tzv. object literal – prostě normální JS objekt s tečkovou notací data.whatever

Editoval dakur (29. 3. 2021 10:53)