Vypnutí řazení ve formulářích u addSelect()
- Webster.K
- Člen | 212
Zdravím všechny, mám takovou zapeklitost se kterou si už nevím rady. Jde o řazení prvků které dávám do formuláře do selectu.
Ve formuláři mám následující:
$form->addSelect('motor', 'Motorizace:')
->setHtmlAttribute('data-depends', $model->getHtmlName())
->setHtmlAttribute('data-url', $this->link('Car:motory', '#'))
->setHtmlAttribute('class', 'form-control form-control-sm')
->setPrompt('Nevybráno')
->setRequired('Vyberte motorizaci');
A o kus dál pak:
$form->onAnchor[] = fn() =>
$motor->setItems($model->getValue() ? $this->database->table('motorizace')->select('id, CONCAT(kw,"kw / ",hp,"hp / ",ccm,"ccm") AS motor')->where('model_id', $model->getValue())->order('kw ASC')->fetchPairs('id', 'motor') : []);
O hodně řádků je pak volána action která načítá obsah do tohoto
pole a odesílá to jako JSON. Vše voláno přes Ajax. Jde o formulář který
má asi 12 závislých prvků které se různě volají a doplňují. To co
řeším je to, že z DB se mi vrátí vše seřazeno ve formátu
[1=>‚hodnota‘,4=>‚druhá hodnota‘,2=>‚treti hodnota‘]. Což
je to čeho potřebuji dosáhnout, ale Nette mi to přehází.
Nemá někdo nápad jak toho docílit, aby Nette neřadilo prvky a nechalo je
tak, jak jdou z DB?
Editoval Webster.K (10. 11. 19:21)
- Webster.K
- Člen | 212
Ok, tak po čem jít, action ve stejném presenteru vypadá takto:
public function actionMotory($model): void {
$motor = array('Nevybráno');
$motor += $this->database->table('motorizace')->select('id, CONCAT(kw,"kw / ",hp,"hp / ",ccm,"ccm"," (",kod_motoru,")") AS motor')->where('model_id', $model)->order('hp ASC')->fetchPairs('id', 'motor');
$this->sendJson($motor);
}
a v šabloně pak script, ktery to tam sype
<script>
// najdeme na stránce všechny podřízené selectboxy
document.querySelectorAll('select[data-depends]').forEach((childSelect) => {
let parentSelect = childSelect.form[childSelect.dataset.depends]; // nadřízený <select>
let url = childSelect.dataset.url; // atribut data-url
let items = JSON.parse(childSelect.dataset.items || 'null'); // atribut data-items
// když uživatel změní vybranou položku v nadřízeném selectu...
parentSelect.addEventListener('change', () => {
// pokud existuje atribut data-items...
if (items) {
// nahrajeme rovnou do podřízeného selectboxu nové položky
updateSelectbox(childSelect, items[parentSelect.value]);
}
// pokud existuje atribut data-url...
if (url) {
// uděláme AJAXový požadavek na endpoint s vybranou položkou místo placeholderu
fetch(url.replace(encodeURIComponent('#'), encodeURIComponent(parentSelect.value)))
.then((response) => response.json())
// a nahrajeme do podřízeného selectboxu nové položky
.then((data) => updateSelectbox(childSelect, data));
}
});
});
// přepíše <options> v <select>
function updateSelectbox(select, items)
{
select.innerHTML = ''; // odstraníme vše
for (let id in items) { // vložíme nové
let el = document.createElement('option');
el.setAttribute('value', id);
el.innerText = items[id];
select.appendChild(el);
}
}
</script>
- Kamil Valenta
- Člen | 820
A není to jen tím, že používáš na dvou místech různý order()?
Ono by bylo nejlepší, kdyby to dodávala jedna modelová metoda…
$form->onAnchor[] = fn() => $motor->setItems($model->getValue() ? $this->database->table('motorizace')->select('...')->where(...)->order('kw ASC')->fetchPairs('id', 'motor') : []);
public function actionMotory($model): void { $motor = array('Nevybráno'); $motor += $this->database->table('motorizace')->select('...')->where(...)->order('hp ASC')->fetchPairs('id', 'motor'); $this->sendJson($motor); }
- Webster.K
- Člen | 212
I když order sjednotím, tak je výsledek stejný. Když tam všude naflákám debugy a koukám, co leze do prohlížeče, tak je to špatně, protože už tady je to právě zpřeházený, má to být 0, 14, 19, 13:
{
"0": "Nevybráno",
"13": "47kw / 64hp / 1198ccm (BME, AZQ)",
"14": "40kw / 54hp / 1198ccm (BMD, AWY)",
"19": "44kw / 60hp / 1397ccm (AZF, AZE)"
}
Něco to někde řadí, ale do části $this->sendJson($motor) je to správně, odsud to je špatně. Takže to dělá pravděpodobně funkce sendJson
Editoval Webster.K (14. 11. 14:06)
- Webster.K
- Člen | 212
Tak jsem o trochu dál, momentálně mám tento výsledek:
{
"0": "Nevybráno",
"14": "40kw \/ 54hp \/ 1198ccm (BMD, AWY)",
"19": "44kw \/ 60hp \/ 1397ccm (AZF, AZE)",
"13": "47kw \/ 64hp \/ 1198ccm (BME, AZQ)"
}
Což je to co potřebuju, ale ve formuláři je to stejně blbe :D obešel jsem to takto: $this->sendRawJson($motor);
private function sendRawJson(array $data): void
{
// Nastavíme hlavičku pro JSON odpověď
$this->getHttpResponse()->setContentType('application/json');
// Zakódujeme JSON ručně bez zásahu Nette, čímž zajistíme zachování pořadí
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// Ukončíme skript, aby nedošlo k dalšímu vykonávání
$this->terminate();
}
Takže, po čem jít dál? :D když do prohlížeče se to ted přes JSON dává správně. Leda už, že to buď přerovnává prohlížeč, nebo JS
- mskocik
- Člen | 62
Webster.K napsal(a):
Leda už, že to buď přerovnává prohlížeč, nebo JS
Presne tak, browser to vzdy zoradi podla abecedy. Ved si skus v konzole
vypisat: Object.keys({ 1: 2, 5: 1, 2: 5 })
. Vrati to
['1', '2', '5']
.
Ak potrebujes zachovat poradie, tak to v tom JSONE posli ako pole objektov.
- mskocik
- Člen | 62
O hodně řádků je pak volána action která načítá obsah do tohoto pole a odesílá to jako JSON.
Ty to posielas ako klasicke asociativne pole. Tak v tej predtym ako volas
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
si tie data skonvertuj na objekty.
$data = array_values(
\Nette\Utils\Arrays::map($data, fn($value, $key) => ['id' => $key, 'text' => $value])
);
Je dolezite, aby si poslal len tie hodnoty, preto pouzitie
array_values
. A v JS si tie data pred volanim
updateSelectbox(childSelect, data)
skonvertuj opat na strukturu ako
potrebujes.