A drupal.hu fórumán tette fel andrew a kérdést, hogy hogyan tudja megoldani a Drupal-lal, hogy egy legördülő lista tartalma egy másik “select” mező változásakor automatikusan frissüljön. A megoldáshoz modul fejlesztési, form API és minimális jQuery ismeretekre lesz szükségünk. A megértést elősegítendő készítettem egy deszkamodellt, hogy a hosszadalmas és ködös magyarázkodás helyett egy konkrét példán keresztül tudjam bemutatni a megoldást.

Az elkészített modul 3 fájlból áll. Az probaform.info fájl a minden modulnál elengedhetetlen információkat tartalmazza. A prbaform.module a php kódot, a probaform.js pedig a JavaScript kódot tartalmazza.

A probaform.module függvényei.

probaform_menu

<?php function formproba_menu($may_cache) { global $user; $items = array();

$items[] = array(
  'path' =&gt; 'formproba',
  'callback' =&gt; 'formproba_page', 
  'title' =&gt; 'Form próba',
  'access' =&gt; user_access('access content'),
  );
$items[] = array(
  'path' =&gt; 'formproba/data',
  'callback' =&gt; 'formproba_data',
  'access' =&gt; user_access('access content'),
  'type' =&gt; MENU_CALLBACK);

return $items; } ?>

Két útvonalat definiálunk. Az egyik (probaform) egy oldal, mely a formot jeleníti meg. A tesztelést megkönnyítendő a menübe is elhelyeztük, csak rá kell kattintani. A második útvonal (probaform/data) mely a JS kérésekre fog válaszolni.

probaform_page

<?php function formproba_page(){ drupal_add_js(drupal_get_path(‘module’,‘formproba’).'/formproba.js'); return drupal_get_form(‘formproba_form’); } ?>

Ez a függvény fogja megjeleníteni a formot, valamint a probaform.js fájlt betöltéséről gondoskodik. Fontos, hogy ne a sminkbe hegesszük bele a .js fájljaink betöltését, hanem a drupal_add_js függvénnyel hívjuk be azokat. A Drupal ugyanis csak akkor fogja beletenni a header részbe a drupal.js és jquery.js hivatkozásokat, ha az szükséges. A drupal_add_js függvénnyel tudjuk jelezni a Drupal-nak, hogy szeretnénk azokat használni.

probaform_form

<?php function formproba_form(){

$form[‘select1’] = array( ‘#type’ => ‘select’, ‘#title’ => ‘Első választás’, ‘#default_value’ => 1, ‘#options’ => array(1 => ‘gyümölcs’,2 => ‘növény’,3 => ‘állat’,), );

$form[‘select2’] = array( ‘#type’ => ‘select’, ‘#title’ => ‘Második választás’, ‘#options’ => isset($_POST[‘select1’])?formproba_get_select2($_POST[‘select1’]):formproba_get_select2(1), );

$form[‘submit’] = array( ‘#type’ => ‘submit’, ‘#value’ => ‘Elküld’, );

return $form; }

?>

A formot leíró kódot tartalmazza. Látható, hogy két select mezőnk van valamit egy submit gombunk. Igazából a második lista (select2) options része szorul magyarázatra és az, hogy miért nem kell használnunk a #DANGEROUS_SKIP_CHECK direktívát. A magyarázat előtt tisztázzunk pár dolgot!

Mi is az a DANGEROUS_SKIP_CHECK nem dokumentált direktíva?

Biztonsági megfontolásból a Drupal csak olyan választásokat fogad el a klienstől, mely a kiküldött, vagyis a szerver oldalon generált lehetőségek között szerepel. Abban az esetben, ha egy választó lista tartalmát nem a szerveren, hanem a kliensen építjük fel akkor a Drupal hibaüzenetet fog adni, ha olyan elemet választottunk ki, ami nem szerepel a lehetőségek között. Nem lehet tudni ugyanis, hogy ez a szabályos működés vagy egy támadási kísérlet eredménye. Ezt a direktívát csak megfelelő körültekintés mellet javasolt használni!

Hogyan működik a Drupal form feldolgozása?

Megnézzük, hogy jött-e adat? Nem jött, akkor kirajzoljuk a formot. Jött adat, akkor ellenőrizzük, hogy helyes-e. Nem helyes adatok esetén újra kirajzoljuk a formot, de a helyes adatokat már megjelenítjük, hogy a felhasználónak ne kelljen azokat újra megadni. Helyes adatok esetén feldolgozzuk a kapott adatokat.

A select2 beviteli mező értékeinek előállításakor megnézzük, hogy jött-e adat, ha jött, akkor a választásnak megfelelő listát töltjük be, ha nem jött akkor az elsőt. Mivel ekkor ugyan az a lista a kliens oldalon és az ellenőrzésnél a Drupal nem fog szólni a nem megfelelő adatok miatt.

formproba_form_submit

<?php function formproba_form_submit($form_id, $form_values){ drupal_set_message(''.print_r($form_values,true).''); } ?>

Ez a függvény végzi a form feldolgozását. Jelen esetben csak annyit csinál, hogy kiírja az adatokat.

formproba_data

<?php function formproba_data(){ echo drupal_to_js(formproba_get_select2(arg(2))); } ?>

Ez a függvény végzi a kérések kiszolgálását. Semmi mást nem csinál, mint kiírja a kimenetre a lehetőségeket tartalmazó tömb JSON reprezentációját. Tesztelni úgy lehet, hogy a címsorba beírjuk, hogy ?q=formproba/data/1

formproba_get_select2

<?php function formproba_get_select2($id){ switch($id){ case 1: return array(‘1’=>‘alma’,‘2’=>‘körte’,‘3’=>‘barack’); case 2: return array(‘4’=>‘fa’,‘5’=>‘bokor’,‘6’=>‘virág’); case 3: return array(‘7’=>‘nyuszi’,‘8’=>‘róka’,‘9’=>‘malac’); default: return false; } } ?>

Mivel a lehetőségeket tartalmazó tömbre két helyen is szükségünk van ezért azt egy függvénybe burkoltam.

formproba.js függvényei

if(Drupal.jsEnabled){ $(document).ready(formproba_init); }

function formproba_init(){ $('#edit-select1').change(function(){ $.getJSON("/",{q: ‘formproba/data/’ + $(this).val()},formproba_feldolg); }); }

function formproba_feldolg(j){ options = ‘'; for(i in j){ options += '’ + j[i] + ‘'; } $("#edit-select2").html(options); }

formproba_init

Ez a függvény az oldal betöltődésekor fut le. Beállítja, hogy a select1 mező megváltozásakor egy AJAJ kérés fusson le. Az adatok feldolgozását, azok megérkezésekor a formproba_feldolg függvény fogja végzi.

formproba_feldolg

A megkapott adatokból elkészítjük a megfelelő HTML kódot és lecseréljük a select2 listáját erre.