Dependency select Ajax a ztráta event handleru
- Daewoo
- Člen | 37
Ahoj
Řeším jednoduchý problém s dynamickým načítáním seznamu krajů a okresů v závislosti na státu. Mám definovaný snippet pro překreslení selectu s kraji a okresy (v závislosti na státu) a snippet pro překlesení selectu s okresy (v závislosti na kraji). Při prvním načtení stránky se JS event listenery na selecty zaregistrují. Při výběru státu a překreslení selectu s kraji, se však handler selectu s výběrem kraje zruší a druhý (vnořený) snippet tak vůbec nefunguje. Mám za to, že je třeba listener onchange události na element registrovat znovu, což mě ale trochu mate, poněvadž když jsem při výběru státu select s okresy nepřekresloval, a tudíž jsem nepotřeboval užívat vnořeného snippetu (v kódu byly dva odděleně), listener se nerušil. Dokážete mi poradit, co s tím? Děkuju.
Šablona:
<form n:name=companyForm>
<div class="form-group form-group-sm">
<div class="col-sm-3 control-label"><label n:name="state">Stát</label></div>
<div class="col-sm-9"><select n:name="state"></select></div>
</div>
{snippet stateSnippet}
<div class="form-group form-group-sm">
<div class="col-sm-3 control-label"><label n:name="region">Kraj</label></div>
<div class="col-sm-9"><select n:name="region"></select></div>
</div>
{snippet regionSnippet}
<div class="form-group form-group-sm">
<div class="col-sm-3 control-label"><label n:name="okres">Okres</label></div>
<div class="col-sm-9"><select n:name="okres"></select></div>
</div>
{/snippet}
{/snippet}
<p class="text-right"><input n:name=submit></p>
</form>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
</script>
$(function () {
$.nette.init();
});
</script>
<script>{include #jsCallback, input => state, link => stateChange}</script>
<script>{include #jsCallback, input => region, link => regionChange}</script>
{define #jsCallback}
$('#{$control["companyForm"][$input]->htmlId}').on('change', function() {
$.nette.ajax({
type: 'GET',
url: '{link {$link}!}',
data: {
'value': $(this).val(),
}
});
});
{/define}
Presenter:
namespace App\AdminModule\Presenters;
use Nette\Application\UI;
use Nette\Utils\Finder;
use Nette\Forms\Form;
use Nette\Forms\Controls;
use Nette\Utils\Html;
class CompanyPresenter extends BasePresenter
{
protected function beforeRender()
{
parent::beforeRender();
$this->template->companyForm = $this['companyForm'];
$this->template->_form = $this['companyForm'];
}
public function createComponentCompanyForm()
{
$formCompany = new \Nette\Application\UI\Form();
$states = $this->database->table("state")->fetchAssoc("id=title");
$SelectState = $formCompany->addSelect("state", "Stát", $states)->setDefaultValue(37);
$regions = $this->database->table("region")->where("state=?", 37)->fetchAssoc("id=title");
$SelectRegion = $formCompany->addSelect("region", "Kraj", $regions)->setDisabled(count($regions) == 0);
$okresy = count($regions) ? $this->database->table("okres")->where("region=?", $regions[0])->fetchAssoc("id=title") : array();
$SelectOkres = $formCompany->addSelect("okres", "Okres", $okresy)->setDisabled(count($okresy) == 0);
$formCompany->addSubmit("submit", "Odeslat");
$formCompany->onSuccess[] = $this->companyFormSucceeded;
return $formCompany;
}
public function handleStateChange($value)
{
if ($value)
{
$data = $this->database->table("region")->where("state=?", $value)->fetchAssoc("id=title");
}
else
{
$data = array();
}
$this['companyForm']['region']->setItems($data)->setDisabled(count($data) == 0);
$this['companyForm']['okres']->setItems(array())->setDisabled(true);
$this->invalidateControl('stateSnippet');
}
public function handleRegionChange($value)
{
if ($value)
{
$data = $this->database->table("okres")->where("region=?", $value)->fetchAssoc("id=title");
}
else
{
$data = array();
}
$this['companyForm']['okres']->setItems($data)->setDisabled(count($data) == 0);
$this->invalidateControl('regionSnippet');
}
}
- kleinpetr
- Člen | 480
Pokud ti po načtení stránky vše funguje a po překlreslení ne, tak budeš muset listener zaregistrovat znovu po překreslení snippetu, já to dělám takhle, pomocí ajax rozšíření:
$.nette.ext('ajax', {
success: function (payload) {
for (snippet in payload.snippets) {
//reinitialize listeners
$('#'+snippet+' #{$control["companyForm"][$input]->htmlId}').on('change',function() {
$.nette.ajax({
type: 'GET',
url: '{link {$link}!}',
data: {
'value': $(this).val(),
}
});
});
}
}
});
Nebo můžeš samozřejmě tou horší variantou a to tak, že si dáš ten js listener do snippetu, který také budeš překreslovat.
Plus používej redrawControl()
místo
invalidateControl()
P.S. Tak i tak ti to neprojde přes onSuccess()
funkci
formuláře, jelikož budeš měnit data ajaxově, takže select bude obsahovat
data, která tam při načtení nebyla. Takže až narazíš na tento problém,
tak použij onSubmit()
Editoval kleinpetr (4. 3. 2016 11:17)
- CZechBoY
- Člen | 3608
@kleinpetr asi takhle nějak:
function bindLoaders($snippet)
{
$('select', $snippet).on('change', function() {
$.nette.ajax({
type: 'GET',
url: $(this).data('url'),
data: {
'value': $(this).val(),
}
});
};
Šlo mi hlavně o změnu ze success
(která se volá
s každým requestem) metody na init
(která se volá jen
jednou).
Editoval CZechBoY (18. 10. 2016 13:22)