NasExt/DependentSelectBox
- duskohu
- Člen | 778
Zdravím
Určíte sa nájde dosť komponent tohto typu, ja som mal stále nejaký
problém ich rozchodiť, alebo sa mi na nich niečo nepáčilo, tak som napísal
svoju variantu ktorú vám ponukám na užívanie.
Ponúka možnosť závislosti nie len na jednom selectboxe, ale aj na viacerých formulárových prvkoch naraz a to napr. text input checkbox a pod.
Rozšírenie nájdete na Addons, Githube doplnené o dokumentáciu, odporúčam inštaláciu cez composer.
Editoval duskohu (19. 10. 2015 10:31)
- Ages
- Člen | 128
@duskohu
Navrhuji modifikovat dokumentaci aby fungovala registrace doplňku viz:
https://forum.nette.org/…ly-selectbox#…
Editoval Ages (22. 2. 2016 13:53)
- surani
- Člen | 6
Ahoj. Dík za doplněk.
Všiml jsem si chybného pořadí zobrazených položek selectu.
DependentSelectBoxu je předané pole s pořadím klíčů např. 5 2 1, ale
položky jsou zobrazeny v pořadí 1 2 5.
K chybnému řazení dochází až po načtení AJAXem (po změně hodnoty
selectu „country“).
$form->addSelect('country', 'Country', $country)
->setPrompt('- Select -');
$form->addDependentSelectBox('city', 'City', array($form["country"]), function ($values) {
$data = new \NasExt\Forms\Controls\DependentSelectBoxData();
return $data->setItems([5 => 'a', 2 => 'b', 1 => 'c']);
})->setPrompt('- Select -');
Dík.
- duskohu
- Člen | 778
Surda napsal(a):
Ahoj. Dík za doplněk.
Všiml jsem si chybného pořadí zobrazených položek selectu.
DependentSelectBoxu je předané pole s pořadím klíčů např. 5 2 1, ale položky jsou zobrazeny v pořadí 1 2 5.
K chybnému řazení dochází až po načtení AJAXem (po změně hodnoty selectu „country“).$form->addSelect('country', 'Country', $country) ->setPrompt('- Select -'); $form->addDependentSelectBox('city', 'City', array($form["country"]), function ($values) { $data = new \NasExt\Forms\Controls\DependentSelectBoxData(); return $data->setItems([5 => 'a', 2 => 'b', 1 => 'c']); })->setPrompt('- Select -');
Dík.
Dik za info.
je to velmi zaujimave kedze data sa posielaju ok ale az js-ko samo ten json
zoradi podla id-ciek
Pokusim sa na to pozriet ako by sa to dalo fixnut.
- duskohu
- Člen | 778
Takze zda sa ze riesenie je dost hnusne: http://stackoverflow.com/…utomatically , otazka znie ci je to nutne.
- surani
- Člen | 6
duskohu napsal(a):
@Surda Dakujem za info, Fixnute: https://github.com/…348d693d75fc
Děkuji.
- ladec
- Člen | 5
Ahoj,
nějak se mi nedaří rozchodit ajaxové překreslování. Příklad jsem zkopíroval z dokumentace. Díky
v layout mám:
<script>
<script type="text/javascript" src="{$basePath}/js/jquery.js"></script>
<script type="text/javascript" src="{$basePath}/js/jquery-ui.js"></script>
<script type="text/javascript" src="{$basePath}/js/netteForms.js"></script>
<script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script>
<script type="text/javascript" src="{$basePath}/js/dependentSelectBox.js"></script>
</script>
inicializace
<script>
$('country').dependentSelectBox();
</script>
- duskohu
- Člen | 778
ladec napsal(a):
Ahoj,
nějak se mi nedaří rozchodit ajaxové překreslování. Příklad jsem zkopíroval z dokumentace. Díky
v layout mám:
<script> <script type="text/javascript" src="{$basePath}/js/jquery.js"></script> <script type="text/javascript" src="{$basePath}/js/jquery-ui.js"></script> <script type="text/javascript" src="{$basePath}/js/netteForms.js"></script> <script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script> <script type="text/javascript" src="{$basePath}/js/dependentSelectBox.js"></script> </script>
inicializace
<script> $('country').dependentSelectBox(); </script>
Ahoj @ladec
- nette.ajax.js si si inicializoval?
- toto je co za selector?
$('country').dependentSelectBox();
toto neni selector ani na classu, element takyto neexistuje
skus pouzit ten z mojej „dokumentacie“ :-) https://github.com/…/en/index.md#…:
$('[data-dependentselectbox]').dependentSelectBox();
- ladec
- Člen | 5
duskohu napsal(a):
ladec napsal(a):
Ahoj,
nějak se mi nedaří rozchodit ajaxové překreslování. Příklad jsem zkopíroval z dokumentace. Díky
v layout mám:
<script> <script type="text/javascript" src="{$basePath}/js/jquery.js"></script> <script type="text/javascript" src="{$basePath}/js/jquery-ui.js"></script> <script type="text/javascript" src="{$basePath}/js/netteForms.js"></script> <script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script> <script type="text/javascript" src="{$basePath}/js/dependentSelectBox.js"></script> </script>
inicializace
<script> $('country').dependentSelectBox(); </script>
Ahoj @ladec
- nette.ajax.js si si inicializoval?
- toto je co za selector?
$('country').dependentSelectBox();
toto neni selector ani na classu, element takyto neexistuje
skus pouzit ten z mojej „dokumentacie“ :-) https://github.com/…/en/index.md#…:$('[data-dependentselectbox]').dependentSelectBox();
Už to jede, díky moc. V jquery jsem začátečník :)
- Re4DeR
- Člen | 71
Ahoj, jsem unavenej blboun, chtel jsem dotaz smazat, ale byl jsi moc rychly s odpovedi :). Díky moc!
Byla to moje chyba.
$form->setDefaults(); funguje parádně, jen jsem zapomněl nastavit uplně první select (mám na sobě 3 zavislosti)).
Mám ještě jeden dotaz, jak by prosím šlo nastavit spinner, když se čeká na ajaxovou odpověd. zkoušel jsem přes $.nette.ext(‚callbacks‘) ale to nefunguje. priznám se ze v ajaxu moc nedelam tak je to možná uplna blbost.
- Croc
- Člen | 270
Zdravím,
snažím se rozchodit tento doplněk, ale nějak se mi to nedaří. JS se
zavolá, ale druhý select box se prostě nerefreshne. Když kouknu co přišlo
JSONem, tak přišly výchozí (prázdné) hodnoty pro druhý list co při
prvním zobrazení.
id
"frm-dependentForm-dependentForm-city"
items
[]
value
null
prompt
"--- Select country first ---"
disabledWhenEmpty
null
PHP 7.1.9
Nette 2.4 – nejnovější update
Formulář mám v komponentě:
<?php
namespace App\Forms;
use NasExt\Forms\DependentData;
use Nette\Application\UI\Control;
use Nette\Application\UI\Form;
/**
* Class DependentFormControl
* @package App\Forms
*/
class DependentFormControl extends Control {
public $onSave = array();
/**
* DependentFormControl constructor.
*/
public function __construct() {
parent::__construct();
}
/**
*
*/
public function render() {
$this['dependentForm']->render();
}
/**
* @return Form
*/
public function createComponentDependentForm() {
$form = new Form;
$country = [
1 => 'Slovakia',
2 => 'Czechia',
3 => 'USA',
];
$citySlovakia = [
1 => 'Bratislaba',
2 => 'Kosice',
3 => 'Zilina',
];
$cityCzechia = [
1 => 'Praha',
2 => 'Brno',
3 => 'Ostrava',
];
$cityUsa = [
1 => 'Toronto',
2 => 'Philadelphia',
3 => 'Boston',
];
$form->addSelect('country', 'Country', $country)
->setPrompt('--- Select ---');
$form->addDependentSelectBox('city', 'City', $form['country'])
->setDependentCallback(function ($values) use ($citySlovakia, $cityCzechia, $cityUsa) {
$data = new DependentData;
if ($values['country'] === 1) {
$data->setItems($citySlovakia)->setPrompt('---');
} elseif ($values['country'] === 2) {
$data->setItems($cityCzechia)->setPrompt('---');
} elseif ($values['country'] === 3) {
$data->setItems($cityUsa)->setPrompt('---');
}
return $data;
})
->setPrompt('--- Select country first ---');
$form->addProtection('Error, try again!');
$form->addSubmit('save', 'Uložit')
->setAttribute('class', 'btn-primary')
->setAttribute('id','submit')
->onClick[] = array($this, 'formSucceeded');
return $form;
}
/**
* @param $form
* @param $values
*/
public function formSucceeded($form, $values) {
$this->onSave();
}
}//class
/**
* Interface IDependentFormControl
* @package App\Forms
*/
interface IDependentFormControl {
/**
* @return DependentFormControl
*/
public function create();
}
EDIT: Už jsem to rozchodil.
// v dokumentaci - nefunguje
if ($values['country'] === 1) {//...
// funguje
if ($values['country'] == 1) {//...
Editoval Croc (19. 9. 2017 19:01)
- Croc
- Člen | 270
Tak mám ještě problém s implementací spolu s Replicatorem(WebChemistry/Multiplier). Pokud tam je DependentSelectBox nadefinován jednou, funguje to, ale jakmile přidám další „skupinu“, AJAX se nezavolá ani u původního, ani u nového. Nějaký typ kde by mohl být problém? :(
Moc děkuju
- Croc
- Člen | 270
Snažím se zjistit kde je problém. Zde je můj testovací kód:
//Presenter
/**
* @return \App\Forms\MultiplierDependentFormControl
*/
protected function createComponentMultiplierDependentForm() {
$form = $this->multiplierDependentFormFactory->create();
$form->onSave[] = function($form, $values) {
};
return $form;
}
// Komponentta
<?php
namespace App\Forms;
use NasExt\Forms\DependentData;
use Nette;
use Nette\Application\UI\Control;
use Nette\Application\UI\Form;
/**
* Class MultiplierDependentFormControl
* @package App\Forms
*/
class MultiplierDependentFormControl extends Control {
public $onSave = array();
/**
* MultiplierDependentFormControl constructor.
*/
public function __construct() {
parent::__construct();
}
/**
*
*/
protected function beforeRender() {
parent::beforeRender();
if($this->isAjax()) $this->template->getLatte()->addProvider('formsStack', [$this['multiplierDependentForm']]);
}
/**
*
*/
public function render() {
$this['multiplierDependentForm']->render();
//$this->template->setFile(__DIR__ . '/multiplierDependentForm.latte');
//$this->template->render();
}
/**
* @return Form
*/
public function createComponentMultiplierDependentForm() {
$form = new Form;
$copies = 1;
$maxCopies = 10;
$array = array(
1 => 'jedna',
2 => 'dva',
3 => 'tři',
);
$lookup_data = array(
1 => array (
1 => '1/1',
2 => '1/2',
3 => '1/3',
),
2 => array (
1 => '2/1',
2 => '2/2',
3 => '2/3',
),
3 => array (
1 => '3/1',
2 => '3/2',
3 => '3/3',
),
);
$multiplier = $form->addMultiplier('multiplier', function (Nette\Forms\Container $container, Nette\Forms\Form $form) use ($array, $lookup_data) {
$container->addSelect('array', 'Array', $array)
->setPrompt('--- Select ---');
$container->addDependentSelectBox('city', 'City', $container['array'])
->setDependentCallback(function ($values) use ($array, $lookup_data) {
$data = new DependentData;
if ($values['array']) {
$data->setItems($lookup_data[$values['array']])->setPrompt('---');
} else {
$data->setItems(array())->setPrompt('---');
}
return $data;
})
->setPrompt('--- Select array first ---');
}, $copies, $maxCopies);
$multiplier->addCreateButton('Add');
$multiplier->addRemoveButton('Remove');
$form->addProtection('Error, try again!');
$form->addSubmit('save', 'Uložit')
->setAttribute('class', 'btn-primary')
->setAttribute('id','submit')
->onClick[] = array($this, 'formSucceeded');
return $form;
}
/**
* @param $form
* @param $values
*/
public function formSucceeded($form, $values) {
$this->onSave();
}
}//class
/**
* Interface IMultiplierDependentFormControl
* @package App\Forms
*/
interface IMultiplierDependentFormControl {
/**
* @return MultiplierDependentFormControl
*/
public function create();
}
Pokud přidávám další skupiny atributů pomocí Multiplieru, tlačítka Add (ne-ajaxově), tak se HTML na nově přidaných nastaví správně:
<select name="multiplier[0][city]" id="frm-multiplierDependentForm-multiplierDependentForm-multiplier-0-city" data-dependentselectbox-parents="{"array":"frm-multiplierDependentForm-multiplierDependentForm-multiplier-0-array"}" data-dependentselectbox="/sandbox/homepage/multiplier-dependent?do=multiplierDependentForm-multiplierDependentForm-multiplier-0-city-load"><option value="" selected="">--- Select array first ---</option></select>
Nicméně takto přidaná atribut hodní následující chybu:
The signal receiver component 'multiplierDependentForm-multiplierDependentForm-multiplier-1-city' is not found.
Shrnutí:
- pokud jsou skupiny atributů vykresleny už při prvním zobrazení, fungují správně i když jich je tam více
- atributy přidané pomocí tlačítka add, nefungují a zobrazí se hláška viz výše. Nicméně atributy, co byly vykresleny hned při prvním zobrazení, stále fungují.
Chování při ajaxu:
Pokud mám tlačítko Add zaajaxované, po přidání atributů
DependentSelectBox nezavolá ani ajax
- duskohu
- Člen | 778
@Croc , Nahodil som si WebChemistry/Multiplier
a pouzil
tvoj priklad. Problem je v tom ze ked sa snazis zment DSB ktory si prave
naklonoval, tak signal je v tvare
?do=multiplierDependentForm-multiplierDependentForm-multiplier-1-city-load
,
cize na zaklade tochto signalu sa nette snazi spracovat tento signal a vytvorit
component strom v processSignal
problem je v tom ze Multiplier v tom okamihu nedokaze vytvorit komponentu
multiplier-1-city
. Preco to tak je, to uz neviem nevrtal som sa
v komponente Multiplier. Ale bohuzial sa zda ze tento problem nesposobuje DSB,
lebo jeho komponenta sa ani nevytvori ked sa zavola signal a vypise ti
The signal receiver component 'multiplierDependentForm-multiplierDependentForm-multiplier-1-city' is not found.
.
- plasmo
- Člen | 66
Ahoj,
doplněk perfektní, ale docela teď bojuji s rychlostí. Mám jeden select
s výběrem zákazníka, na kterém jsou přes tvůj doplněk vytvořeny
další tři závislé selecty. Pokud vyberu zákazníka, tak se pro každý
select provede samostatné volání a přijde JSONem odpověď s daty pro
select, každé toto volání trvá cca 3.2s, přitom samotné zpracování
poždavku na straně serveru je otázka cca 0.03s. V projektu máme použitou
verzi 2.7.2, pomůže aktualizace na poslední rel.? Případně, kdy by mohl
být problém? Díky
Editoval plasmo (30. 9. 2017 23:53)
- Tomáš Vodička
- Člen | 28
Ahoj,
díky za doplněk, funguje parádně, ale všiml jsem si v konzoli warningu
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.
Po chvíli bádání jsem se dočetl, že synchronní ajax se nedoporučuje používat, ale bez něho zase doplněk nefunguje správně. Do téhle oblasti moc nevidím, je možné to vyřešit nějak jinak?
Díky
- duskohu
- Člen | 778
Tomáš Vodička napsal(a):
Ahoj,
díky za doplněk, funguje parádně, ale všiml jsem si v konzoli warningu
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.
Po chvíli bádání jsem se dočetl, že synchronní ajax se nedoporučuje používat, ale bez něho zase doplněk nefunguje správně. Do téhle oblasti moc nevidím, je možné to vyřešit nějak jinak?
Díky
Ahoj predpokladam ze to sposobuje toto
problem je v tom ze to nemoze ist async, pretoze kazdy request sa ma spracovat
postupne.
Momentalne neviem ako by som tuto situaciu riesil. Ako konfigurovat tento ajax
request aby to nevyhedzovalo tento warning. Ked budem mat cas, skusim sa na to
pozriet, alebo ked ta nieco napadne, budem rad ked to tu napises.
- iguana007
- Člen | 970
Ahoj, nedari se mi prijit na to, jakou verzi si mam pres composer stahnout, aby mi fungovalo razeni polozek, tak jak mi dorazi z databaze. Radi mi to podle ciselnych id polozek vzestupne, ale z databaze si to vracim podle abecedy obsahu options. Zkousel jsem verzi 3.1.1 a taky dev-master.
- duskohu
- Člen | 778
iguana007 napsal(a):
Ahoj, nedari se mi prijit na to, jakou verzi si mam pres composer stahnout, aby mi fungovalo razeni polozek, tak jak mi dorazi z databaze. Radi mi to podle ciselnych id polozek vzestupne, ale z databaze si to vracim podle abecedy obsahu options. Zkousel jsem verzi 3.1.1 a taky dev-master.
Hmmm to bude asi problem v tom ze ked sa posiela pre js ten json na spracovanie, tak js preusporiadava tie polozky v poli podla id a to je vlastnost js, musim sa na to pozriet a zistit ci sa to neda nejako obist.
- iguana007
- Člen | 970
duskohu napsal(a):
iguana007 napsal(a):
Ahoj, nedari se mi prijit na to, jakou verzi si mam pres composer stahnout, aby mi fungovalo razeni polozek, tak jak mi dorazi z databaze. Radi mi to podle ciselnych id polozek vzestupne, ale z databaze si to vracim podle abecedy obsahu options. Zkousel jsem verzi 3.1.1 a taky dev-master.
Hmmm to bude asi problem v tom ze ked sa posiela pre js ten json na spracovanie, tak js preusporiadava tie polozky v poli podla id a to je vlastnost js, musim sa na to pozriet a zistit ci sa to neda nejako obist.
Podle me se to bude muset upravit timto zpusobem, tj. posilat si zvlast klice a hodnoty: https://github.com/…ull/18/files
- iguana007
- Člen | 970
Aby jsem to upresnil … co se mi vcera podarilo k tomuto dohledat, je to, ze do JS dorazi JSON object u ktereho nelze uchovat puvodni order. Reseni existuje na to nekolik (viz. Google „each json persist order“), ale nejjednodussi mi prijde prave to, co jsem posilal v predchozim prispevku, v podstate totez doporucuji i v nekolika vlaknech na stackoverflow.
- kralik
- Člen | 230
Ahoj,
mohu tuto komponentu použít i na doplnění inputu typu text či integer, dle
vybranné hodnoty ze selectboxu.
$auta = [ 1 => 'Octávia', 2 => 'Superb', 3 => 'Fabia' ];
$autaSpotreba = [ 1 => '6', 2 => '8', 3 => '4' ];
...
$form->addSelect('car', 'Přiřazené vozidlo', $auta)
$form->addDependentSelectBox('spotreba', 'Spotřeba', $form['car'])
->setDependentCallback(function ($values) use ($autaSpotreba) {
$data = new \NasExt\Forms\DependentData;
$data->setValue($auta[$values['car']]);
return $data;
})
Spíš mám na mysli něco jako addDependentInput();
Prakticky jde o doplnění hodnoty form prvku, např. addText nebo addInteger, na základě vybrané hodnoty z předchozího SelectBoxu.
Případně jaký je best practice?
Moc díky za pomoc
Tomáš
- Kamil Valenta
- Člen | 815
Myslím, že nechceš přidávat závislý input, ale jen měnit defaultní hodnotu inputu, který je společný pro všechny optiony toho selectu…
- kralik
- Člen | 230
kamil_v napsal(a):
Myslím, že nechceš přidávat závislý input, ale jen měnit defaultní hodnotu inputu, který je společný pro všechny optiony toho selectu…
Ano, měnit defaultní hodnotu inputu v závislosti na vybrané položce v selectboxu(auta). Tedy, že každé auto v selectBoxu má jinout spotřebu, která se vypní do dalšího formulářového prvku(inputu).
Ale jak na to?
Díky
- Kamil Valenta
- Člen | 815
Záleží, jaký FW pro JS používáš, ale já si prostě v šabloně
vygeneruju funkci, která v argumentu přijme ID toho option a vrátí
defaultní data.
Tu funkci generuju v latte tak, že prostě foreachem proběhnu to pole.
Netroufnu si říct, že by to bylo best practice, ale pro pár hodnot je to to nejrychlejší, co se asi dá vymyslet. Pokud by dat bylo hodně, už bych na select navázal ajax a defaulty si vracel třeba v JSONu. Ale pokud je dat málo, je zbytečné dělat subrequest…
Editoval kamil_v (9. 7. 2020 15:36)
- kralik
- Člen | 230
kamil_v napsal(a):
Záleží, jaký FW pro JS používáš, ale já si prostě v šabloně vygeneruju funkci, která v argumentu přijme ID toho option a vrátí defaultní data.
Tu funkci generuju v latte tak, že prostě foreachem proběhnu to pole.Netroufnu si říct, že by to bylo best practice, ale pro pár hodnot je to to nejrychlejší, co se asi dá vymyslet. Pokud by dat bylo hodně, už bych na select navázal ajax a defaulty si vracel třeba v JSONu. Ale pokud je dat málo, je zbytečné dělat subrequest…
Používám jQuery.
Dat není tolik, takže by se to bez subrequstu dalo pořešit.
Mohl bys poskytnout příklad tvého řešení?
Nevíš zda je k dispozici nějaký best practice na toto téma?
I třeba s tím jak udělat subrequest.
Moc díky
- kralik
- Člen | 230
Pro úplnost doplňuji mé použití.
Použil jsem toto: https://gist.github.com/…24b70f2a0f2f
Funguje to super.
Třeba se to někomu hodí.
- Robin Martinez
- Člen | 89
Ahoj, mám problém, který nevím jak vyřešit:
Mám select A s dopravci a pak select B se zeměmi, které má daný dopravce povolené. Vyberu si dopravce v A, v B se mi z DB doplní správní dopravci. Když ale teď v A změním dopravce na jiného a v B mám stále tu aktuální zemi, dostanu chybu:
Value '10' is out of allowed set [8, 11, 12] in field 'country'
Ta 10 je země, která byla vybrána před změnou dopravce a po změně samozřejmě v listu chybí. Jak toto opravit? Potřeboval bych před načtením nových DependentDat asi select vynulovat.
Díky
Editoval Robin Martinez (21. 9. 2020 15:06)
- Robin Martinez
- Člen | 89
nevím, jestli je to správně, ale vyřešeno metodou
` ->checkDefaultValue(false); `