Použití vlastního ajaxu s jQuery a JSON pro selectboxy
- koprkuba
- Člen | 24
Ahoj, z důvodu, že mi nefungují snippety tak jak bych potřeboval (přestane fungovat jQuery validace atp.) jsem se rozhodl použít svůj ajaxový kód.
<script>
$(function() {
$("#frmsignInForm-country").change(function() {
$.getJSON("countryChange/",{ country: $(this).val(), ajax: 'true' }, function(j) {
var options = '';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
}
$("#frmsignInForm-state").html(options);
$('#frmsignInForm-state option:first').attr('selected', 'selected');
});
});
});
</script>
tj. když změním selectbox s názvem země(country) tak chci šáhnout to
databáze a zjistit si kraje(state) a vypsat je do jiného selectboxu.
nevím jak to udělat v presenteru
<?php
public function actionCountryChange($country) {
???
}
?>
chtěl bych aby se mi vygeneroval dokument který bude vypadat například takto a předá se javascriptu který ho zpracuje podle příkladu zhora:
[{"optionValue": "52", "optionDisplay": "Hlavní město Praha"}, {"optionValue": "79", "optionDisplay": "Jihočeský kraj"}, ..., {"optionValue": "90", "optionDisplay": "Zlínský kraj"}]
Editoval koprkuba (15. 4. 2012 13:11)
- koprkuba
- Člen | 24
Jo tak to jsem přesně četl a přesně tohle nechci.
Použití snippetu a jeho následná invalidace mi znemožní jQuery validaci
nad celým formulářem. Sice to funguje, ale radši bych to měl napsané přes
svůj AJAX. Mimojiné na té stránce pracuji s GoogleMaps API a ta mi také
přestane fungovat.
- koprkuba
- Člen | 24
Nestačí protože při prvotním načtení stránky zjišťuji polohu pomocí GeoIP. Následně pokud uživatel změní některé pole formuláře tak se změní Marker na Google Mapce. Pokud to mám v snippetu tak se znova zjišťuje poloha a to nechci. Pokud je inicializace mapky venku ze snippetu tak přestanou fungovat změny ve formuláři ovlivňující marker na mapě. Zdá se to jako jednoduché řešení, ale bohužel nejde udělat inicializace GeoIP a GoogleMapy jen při prvotním načtení, protože pak nemohu přistupovat k objektům v invalidovaném scriptu.
Je to trochu zmatené, ale opravdu jsem to se snippetem zkoušel vymyslet a strávil jsem na tom 10 hodin a nic, proto to chci řešit svým vlastním AJAXem ve kterém to vyřešit umím, jen potřebuji dostat ty JSON data do mého javascriptu.
- Keksa
- Člen | 23
$this->sendResponse(new Nette\Application\Responses\JsonResponse($payload));
https://api.nette.org/…esponse.html
Aneb v dokumentaci: AJAX & snippety
Editoval Keksa (15. 4. 2012 14:37)
- koprkuba
- Člen | 24
Jasný a $payload má být tedy pole hodnot? V mém případě tedy 2D pole
array(array("optionValue" => "52", "optionDisplay" => "Hlavní město Praha"), array(...) ,...)
optionValue je totiž klíč(hodnota) selectu a „optionDisplay“ je název selectu.
Editoval koprkuba (15. 4. 2012 15:02)
- koprkuba
- Člen | 24
Mějme následující problém:
Potřebujeme dynamicky závislé selecty, ale z nějakého důvodu nemůžeme
použít Nette Snippet, ať už z důvodu validace formuláře nebo
spouštění jiného javascriptu, já měl problém zejména s použitím
googleMaps API a GeoIP.
Co budeme potřebovat:
jQuery verze která již umí pracovat s ajaxem (nevím která to je) nejjednodušší je stáhnout právě tu nejnověší.
Nalinkujte jQuery do šablony @layout.latte můžete využít google knihovnu.
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
Nejdříve si připravíme náš formulář v Presenteru sloužícímu k registraci:
<?php
protected function createComponentSignInForm() {
$form = new MyForm();
$form->addText('nick', 'Přezdívka:', 30, 30)
->addRule(MyForm::FILLED, 'Pole PŘEZDÍVKA musí být vyplněno.');
$form->addPassword('password', 'Heslo:', 30, NULL)
->addRule(MyForm::FILLED, 'Pole HESLO musí být vyplněno.')
->addRule(MyForm::MIN_LENGTH, 'Heslo je příliš krátké, musí být alespoň %d znaků dlouhé.', 6)
->addRule(MyForm::MAX_LENGTH, 'Heslo je příliš dlouhé, může obsahovat maximálně %d znaků.', 30);
$form->addPassword('passwordCheck', 'Heslo pro kontrolu:', 30, NULL)
->addRule(MyForm::FILLED, 'Pole HESLO PRO KONTROLU musí být vyplněno.')
->addRule(MyForm::EQUAL, 'Zadaná hesla se neshodují.', $form['password']);
$form->addSelect('country', 'Země:', $this->context->createCountry()->order('name ASC')->toArray())
->setPrompt('-- Vyberte --')
->addRule(MyForm::FILLED, 'Musíte vybrat zemi.');
$form->addSelect('state', 'Kraj:', $this->context->createStates()->order('name ASC')->toArray())
->setPrompt('-- Vyberte --');
$form->addSubmit('signIn', 'Registrovat');
$form->onSuccess[] = callback($this, 'signFormSubmitted');
return $form;
}
?>
V late šabloně pro vykreslení formuláře přidáme javascript s AJAXem:
{block content}
<h2>Zaregistrovat se</h2>
{control signInForm}
<script type="text/javascript">
$(function() {
$("#frmsignInForm-country").change(function() {
$.getJSON({link ChangeCountry!},{ country: $(this).val(), ajax: 'true' }, function(array) {
var options = '';
for (var key in array) {
options += '<option value="' + key + '">' + array[key] + '</option>';
}
$("#frmsignInForm-state").html(options);
$('#frmsignInForm-state option:first').attr('selected', 'selected');
});
});
});
</script>
Vysvětlivky k proměnným v javascriptu
<script type="text/javascript">
$("#frmsignInForm-country") // ukazatel s použitím jQuery na select s výběrem zemí.
$("#frmsignInForm-state") // ukazatel s použitím jQuery na select s výběrem krajů(států).
{link ChangeCountry!} // odkaz na handlerChangeCountry() tento handler nám vrátí požadované hodnoty do selectu s výběrem krajů.
{ country: $(this).val() } // Zde předáváme proměné pomocí metody get, proměnná country nabývá hodnoty $(this).val() což je hodnota zvolené možnosti v selectu.
// POZOR !! Nezapomeňte vložit mezi "chlupaté" závorky {} a další text mezeru aby si late šablona nemyslela že jde o latte macro.
function(array) // array zde reprezentuje vrácené JSON pole.
var options = ''; // Inicializujeme proměnnou pro vytvoření html kódu pro možnosti selectu s krajem
// o naplnění této proměnné se nám stará foreach cyklus
$("#frmsignInForm-state").html(options); // zde nastavíme závislému selectu námi zpracované hodnoty
$('#frmsignInForm-state option:first').attr('selected', 'selected'); // a zde nastavíme první hodnotu na selected
</script>
Nyní nám to ještě nebude fungovat, jelikož nemáme vytvořený hanndler v Presenteru, ten si nyní vytvoříme:
<?php
public function handleChangeCountry($country) {
$result = $this->context->createStates()->where(array('country' => $country))->order('name ASC')->toArray();
$this->sendResponse(new JsonResponse($result));
}
?>
V proměnné $result jsou nyní záznamy z databáze splňující podmínku
where() a seřezené podle abecedy.
Tuto proměnnou pošleme zpět do šablony o to se nám postará metoda
sendResponse()
Nezapomeňte přidat na začátek souboru Presenteru:
use Nette\Application\Responses\JsonResponse;
Snažil jsem se zde vytvořit návod jak si vytvořit dynamicky závislý select, bez použití Nette snippetu, snad se to povedlo, pokud najdete nějaké nejasnosti, nebo gramatické chyby nebojte se mne kontaktovat, budu se je snažit vysvětlit/opravit.