Použití vlastního ajaxu s jQuery a JSON pro selectboxy

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
koprkuba
Člen | 24
+
0
-

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
+
0
-

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.

22
Člen | 1478
+
0
-

a nestačí po tom AJAX requestu akorat znova inicializovat ty javascripty?

koprkuba
Člen | 24
+
0
-

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
+
0
-
$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
+
0
-

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
+
0
-

Jo tak už to šlape.
S dvojdimenzionálním polem to nejde, ale řešení je foreach cyklus v js. Ještě tady tedy připravím kuchařku jak jsem toho docílil kdyby to někdo někdy potřeboval.

koprkuba
Člen | 24
+
0
-

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.

sabrx
Člen | 47
+
0
-

Ahoj, vdaka za kod, len by som dodal, ze parameter ajax: ‚true‘ je tam zbytocny, kedze v signali handleChangeCountry sa vobec nespracovava.