Naja + form snippet a opětovná aplikace events
- Fires
- Člen | 97
Zdravím, prosím o pomoc. Seznamuju ses Naja a Ajaxem. Trochu jsem z toho vypadnul. Mám jednoduchou stránku na které je formulář (4 inputy a submit). Ve formuláři je tabulka vložených položek. A ajaxem chci tuto tabulku položek upravovat (add, change quantity, delete).
Vše „fungovalo“ ok, ale narazil jsem na problém. Když mi ajax/naja vráti překreslenou část tabulky už na jednotlivích prvcích nemám eventy které voláji naja/ajax(logické, přidávají se .ready(). Konkrétně třeba když se mění množství položek. Trochu jsem se začetl do dokumentace naja a nette a nakonec jsem se totálně ztratil a nevím zda vůbec je něco správně :D Může mě prosím někdo poradit jaké je správně řešení?
Presenter
...
public function handleChangeQuantity($productId, $quantity)
{
if ($this->isAjax()) {
$itemsData = $this->getSession('orderList')->get('items');
$itemsData[$productId] = $quantity;
$this->getSession('orderList')->set('items', $itemsData);
$this->redrawControl('itemsTable');
$this->redrawControl('form');
}
}
...
<div class="container m-4">
{snippetArea form}
{form sellListForm}
<div class="row">
<div class="mb-3 col-6">
<label for="" class="form-label">Převzato dne</label>
<input n:name="date" type="date" class="form-control">
</div>
<div class="mb-3 col-6">
<label for="" class="form-label">Email</label>
<input n:name="email" type="email" class="form-control">
</div>
</div>
<div class="row">
<div class="mb-3 col-6">
<label for="" class="form-label">Zákazník</label>
<textarea n:name="customer" type="text" class="form-control" rows="4"></textarea>
</div>
<div class="mb-3 col-6">
<label for="" class="form-label">Popis</label>
<textarea n:name="note" type="text" class="form-control" rows="4"></textarea>
</div>
</div>
<div n:snippet="itemsTable">
<table class="table">
<thead>
<tr>
<th scope="col">Položka</th>
<th scope="col">Název</th>
<th scope="col">Množství</th>
<th scope="col">Jednotka</th>
<th scope="col">Cena ks</th>
<th scope="col">Cena celkem</th>
<th scope="col">Akce</th>
</tr>
</thead>
<tbody>
{var $sum=0}
{foreach $items as $key=>$value}
<tr>
<th scope="row">{$iterator}</th>
<td>{$itemsForSale[$key]->POPIS}</td>
<td><input data-id="{$key}" data-url={link ChangeQuantity!} type="number" class="ajaxInputEdit"
value="{$value}"></td>
<td>{$itemsForSale[$key]->MJ}</td>
<td>{$itemsForSale[$key]->CENA_PRODEJ} Kč</td>
{var $sum+=$itemsForSale[$key]->CENA_PRODEJ*$value}
<td>{$itemsForSale[$key]->CENA_PRODEJ*$value} Kč</td>
<td><a n:href="removeItem! $itemsForSale[$key]->ID"><button n:name="generate" type="button"
class="btn btn-danger">Smazat</button></a></td>
</tr>
{/foreach}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td><b>Celkem</b></td>
<td>{$sum} Kč</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td><b>Celkem s DPH</b></td>
<td>{$sum*1.21|round} Kč</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<input type="hidden" n:name="signature" id="signatureInput">
<div class="row">
<div class="col-6">
<button n:name="generate" type="submit" class="btn btn-primary">Vygenerovat</button>
</div>
<div id="signatureparent" class="col-6">
<h3>Podpis</h3>
<canvas id="signaturecanvas" width="100%" height="100" style="border:2px solid; width: auto;"></canvas>
</div>
</div>
{/form}
{/snippetArea}
$(document).ready(function () {
naja.initialize();
//.ajaxInputEdit
$(".ajaxInputEdit").change(function (e) {
naja.makeRequest('GET',$(this).attr("data-url") , {
productId: $(this).attr("data-id"),
quantity: $(this).val()
});
}
);
$("#frm-sellListForm").submit(function (event) {
console.log();
$("#signatureInput").val(document.getElementById('signaturecanvas').toDataURL());
});
});
Předem díky.
- m.brecher
- Generous Backer | 864
@Fires
Když mi ajax/naja vráti překreslenou část tabulky už na jednotlivích prvcích nemám eventy které voláji naja/ajax
Ahoj,
jquery neznám, ale ono se to dá odhadnout, protože moderní javascript to dost okopíroval. Předpokládám, že ty eventy, které Ti mizí po překreslení jsou toto:
$(".ajaxInputEdit").change(function (e) {
naja.makeRequest('GET',$(this).attr("data-url") , {
productId: $(this).attr("data-id"),
quantity: $(this).val()
});
Myslím, že po překreslení je potřeba, aby Naja přes nějaký vhodný
event obnovila ty eventy, co překreslením zmizely. Ty se totiž nastavily
v události DOMContentLoaded documentu, a tato událost se volá jenom při
prvním neajaxovém natažení stránky (
javascriptová obdoba toho $(document).ready()).
$(document).ready(function () {...}
Takže musíš ty samé eventy vyvolat v eventu Naja.?, který reprezentuje překreslení ajaxového snippetu.
Z hlavy teď nevím, jaký event to je, ale bude to v dokumentaci Naja.
Editoval m.brecher (11. 3. 2023 0:44)
- m.brecher
- Generous Backer | 864
@Fires
Ještě posílám nástřel řešení v čistém javascriptu, protože kód jquery mě přijde zbytečně komplikovaný. Psal jsem to z hlavy, takže je potřeba to otestovat a doladit. Takhle nějak bych doporučil to napsat.
<script>
function addInputEvents(inputClass)
{
document.querySelectorAll(inputClass).forEach(input => {
input.addEventListener('change', () => {
naja.makeRequest('GET', input.dataset.url, {
productId: input.dataset.url,
quantity: input.value
})
})
})
}
document.addEventListener('DOMContentLoaded', () => {
naja.initialize();
/* input eventy po loadu stránky a po překreslení snippetů */
let inputClass = '.ajaxInputEdit'
addInputEvents(inputClass)
naja.addEventListener('?', () => addInputEvents(inputClass)) // tady doplň ten správný event naja
/* submit formuláře */
document.querySelector('#frm-sellListForm')
.addEventListener('submit', () =>
document.querySelector('#signatureInput').value = document.getElementById('signaturecanvas').toDataURL()
)
})
</script>
Editoval m.brecher (11. 3. 2023 2:16)
- m.brecher
- Generous Backer | 864
@Fires
Ta událost v Naja ve které je potřeba znovu nastavit input eventy je complete:
- Fires
- Člen | 97
m.brecher napsal(a):
@Fires
Ta událost v Naja ve které je potřeba znovu nastavit input eventy je complete:
Super diky. Jinak přístup ze strany nette je takto v pořádku? Obalit celý form do snippetarea, poté tu část kterou regenerovat jako snippet a invalidovat to pak cele?
- m.brecher
- Generous Backer | 864
@Fires
Obalit celý form do snippetarea, poté tu část kterou regenerovat jako snippet a invalidovat to pak cele?
Hmm… spíš ne, ty by Jsi sice mohl překreslovat vždy jeden řádek tabulky + patičku tabulky pomocí dynamických snippetů, ale udělal Jsi to tak, že překreslíš celou tabulku – což úplně stačí a je to jednoduché.
SnippetArea se dle dokumentace použije pro označení inkludované šablony, ve které je překreslovaný snippet. O tom, že by {form} se měl obalovat jsem v dokumentaci nic nenašel, tak by měl stačit jenom ten snippet.
Ale když překresluješ v podstatě celý formulář, nebylo by jednodušší prostě překreslit rovnou celou komponentu (formulář), když už se stejně vykresluje skoro celá šablona? Kód šablony se stejně vykoná celý, jenom se pošle o pár bytů html více. https://doc.nette.org/…ication/ajax#…
To by Jsi ale musel mít formulář zabalený do vykreslovací komponenty odvozené z třídy Control, aby měla komponenta vlastní šablonu. Což tady asi není. Takže to nechej jak je a zkus snippetArea odstranit.
Editoval m.brecher (11. 3. 2023 21:44)
- Fires
- Člen | 97
m.brecher napsal(a):
@Fires
Obalit celý form do snippetarea, poté tu část kterou regenerovat jako snippet a invalidovat to pak cele?
Hmm… spíš ne, ty by Jsi sice mohl překreslovat vždy jeden řádek tabulky + patičku tabulky pomocí dynamických snippetů, ale udělal Jsi to tak, že překreslíš celou tabulku – což úplně stačí a je to jednoduché.
SnippetArea se dle dokumentace použije pro označení inkludované šablony, ve které je překreslovaný snippet. O tom, že by {form} se měl obalovat jsem v dokumentaci nic nenašel, tak by měl stačit jenom ten snippet.
Ale když překresluješ v podstatě celý formulář, nebylo by jednodušší prostě překreslit rovnou celou komponentu (formulář), když už se stejně vykresluje skoro celá šablona ?? Kód šablony se stejně vykoná celý, jenom se pošle o pár bytů html více. https://doc.nette.org/…ication/ajax#…
To by Jsi ale musel mít formulář zabalený do vykreslovací komponenty odvozené z třídy Control, aby měla komponenta vlastní šablonu. Což tady asi není. Takže to nechej jak je a zkus snippetArea odstranit.
Mno muj problém je takovej že jsem se zaleknul dynamického formuláře a ty jednotlivé řádky nejsou součástí formuláře. Případně nevím jak řešit „košík“ ve formuláři. Proto to volání externě. Ajax upravi pouze pole v session a při odeslání formuláře se vemou hlavičková data (jméno, etc.) a to co je v session a poskládá se z toho „objednávka“.
- m.brecher
- Generous Backer | 864
@Fires
Mno muj problém je takovej že jsem se zaleknul dynamického formuláře
OK, jde to překreslovat celé a funguje to taky, rozdíl bude jen pár stovek bytů html
a ty jednotlivé řádky nejsou součástí formuláře
potom máš od sebe oddělená data v session a vykreslená v tabulce, při submitu formuláře data co jsou v tabulce vidět neposíláš, ale uložíš to, co máš v session. Ajax sice data ze session překresluje do tabulky, ale stačí nějaká drobná chyba někde v javascriptu a může se ti stát, že v session nebude úplně přesně to, co bude vidět v tabulce. Navíc nevyužíváš zabezpečení a sanitizace dat která je ve formulářích vestavěná.
Lepší je mít všechny data ve formulářových prvcích a při submitu formuláře je uložit standardním způsobem a data v session mít pouze jako takovou dočasnou zálohu.
- Fires
- Člen | 97
m.brecher napsal(a):
@Fires
Mno muj problém je takovej že jsem se zaleknul dynamického formuláře
OK, jde to překreslovat celé a funguje to taky, rozdíl bude jen pár stovek bytů html
a ty jednotlivé řádky nejsou součástí formuláře
potom máš od sebe oddělená data v session a vykreslená v tabulce, při submitu formuláře data co jsou v tabulce vidět neposíláš, ale uložíš to, co máš v session. Ajax sice data ze session překresluje do tabulky, ale stačí nějaká drobná chyba někde v javascriptu a může se ti stát, že v session nebude úplně přesně to, co bude vidět v tabulce. Navíc nevyužíváš zabezpečení a sanitizace dat která je ve formulářích vestavěná.
Lepší je mít všechny data ve formulářových prvcích a při submitu formuláře je uložit standardním způsobem a data v session mít pouze jako takovou dočasnou zálohu.
Mnohokrát děkuji za vyčerpávající odpovědi. Vrátím se zpět k samotnému návrhu a zkusím to předělat celé do formu. Není asi problém si do formu přidat dynamicky inputy do zvláštního containeru, podle toho co bude v session jako uložený košík.
- m.brecher
- Generous Backer | 864
@Fires
Není asi problém si do formu přidat dynamicky inputy do zvláštního containeru, podle toho co bude v session jako uložený košík.
Ano, košík se ukládá do session při zobrazení košíku se formulář vygeneruje z dat v session košíku – tedy jednotlivé produkty, cena/produkt, počty kusů, sazba DPH atd… a form se vykreslí do šablony.
Je mnoho cest jak to udělat.
Třeba takhle. Nemusíš vůbec řešit eventy na jednotlivých inputech, ale centrálně si zachytit událost onchange rovnou na formuláři jako takovém, protože eventy v javascriptu v DOM bublají, tj. událost change na inputu bublá nahoru strukturou formuláře a tatáž událost jde odchytit a zpracovat v hierarchii výše tj. i na samotném <form>. A není nutné zpracovávat ajax či snippety jednotlivých inputů, ale jednoduše při change na formuláři odpálit ajaxový submit formuláře a nechat překreslit celou šablonu formuláře. Musíš ale odlišit ajaxový submit formu, který se vyvolá událostí change a uživatelský submit formu, kdy se kliká na tlačítko, abys na serveru věděl jak to zpracovat.