ajax_example.module 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. <?php
  2. /**
  3. * @file
  4. * AJAX Examples module file with basic examples.
  5. */
  6. /**
  7. * @defgroup ajax_example Example: AJAX
  8. * @ingroup examples
  9. * @{
  10. * These examples show basic AJAX concepts.
  11. *
  12. * General documentation is available at
  13. * @link ajax AJAX Framework documentation @endlink and at the
  14. * @link http://drupal.org/node/752056 AJAX Forms handbook page @endlink.
  15. *
  16. * The several examples here demonstrate basic AJAX usage.
  17. */
  18. // The Node Form Alter example needs to be in another file.
  19. module_load_include('inc', 'ajax_example', 'ajax_example_node_form_alter');
  20. /**
  21. * Implements hook_menu().
  22. *
  23. * Sets up calls to drupal_get_form() for all our example cases.
  24. *
  25. * @see menu_example.module
  26. * @see menu_example_menu()
  27. */
  28. function ajax_example_menu() {
  29. $items = array();
  30. $items['examples/ajax_example'] = array(
  31. 'title' => 'AJAX Example',
  32. 'page callback' => 'ajax_example_intro',
  33. 'access callback' => TRUE,
  34. 'expanded' => TRUE,
  35. );
  36. // Change the description of a form element.
  37. $items['examples/ajax_example/simplest'] = array(
  38. 'title' => 'Simplest AJAX Example',
  39. 'page callback' => 'drupal_get_form',
  40. 'page arguments' => array('ajax_example_simplest'),
  41. 'access callback' => TRUE,
  42. 'weight' => 0,
  43. );
  44. // Generate a changing number of checkboxes.
  45. $items['examples/ajax_example/autocheckboxes'] = array(
  46. 'title' => 'Generate checkboxes',
  47. 'page callback' => 'drupal_get_form',
  48. 'page arguments' => array('ajax_example_autocheckboxes'),
  49. 'access callback' => TRUE,
  50. 'weight' => 1,
  51. );
  52. // Generate different textfields based on form state.
  53. $items['examples/ajax_example/autotextfields'] = array(
  54. 'title' => 'Generate textfields',
  55. 'page callback' => 'drupal_get_form',
  56. 'page arguments' => array('ajax_example_autotextfields'),
  57. 'access callback' => TRUE,
  58. 'weight' => 2,
  59. );
  60. // Submit a form without a page reload.
  61. $items['examples/ajax_example/submit_driven_ajax'] = array(
  62. 'title' => 'Submit-driven AJAX',
  63. 'page callback' => 'drupal_get_form',
  64. 'page arguments' => array('ajax_example_submit_driven_ajax'),
  65. 'access callback' => TRUE,
  66. 'weight' => 3,
  67. );
  68. // Repopulate a dropdown based on form state.
  69. $items['examples/ajax_example/dependent_dropdown'] = array(
  70. 'title' => 'Dependent dropdown',
  71. 'page callback' => 'drupal_get_form',
  72. 'page arguments' => array('ajax_example_dependent_dropdown'),
  73. 'access callback' => TRUE,
  74. 'weight' => 4,
  75. );
  76. // Repopulate a dropdown, but this time with graceful degredation.
  77. // See ajax_example_graceful_degradation.inc.
  78. $items['examples/ajax_example/dependent_dropdown_degrades'] = array(
  79. 'title' => 'Dependent dropdown (with graceful degradation)',
  80. 'page callback' => 'drupal_get_form',
  81. 'page arguments' => array('ajax_example_dependent_dropdown_degrades'),
  82. 'access callback' => TRUE,
  83. 'weight' => 5,
  84. 'file' => 'ajax_example_graceful_degradation.inc',
  85. );
  86. // The above example as it appears to users with no javascript.
  87. $items['examples/ajax_example/dependent_dropdown_degrades_no_js'] = array(
  88. 'title' => 'Dependent dropdown with javascript off',
  89. 'page callback' => 'drupal_get_form',
  90. 'page arguments' => array('ajax_example_dependent_dropdown_degrades', TRUE),
  91. 'access callback' => TRUE,
  92. 'file' => 'ajax_example_graceful_degradation.inc',
  93. 'weight' => 5,
  94. );
  95. // Populate a form section based on input in another element.
  96. $items['examples/ajax_example/dynamic_sections'] = array(
  97. 'title' => 'Dynamic Sections (with graceful degradation)',
  98. 'page callback' => 'drupal_get_form',
  99. 'page arguments' => array('ajax_example_dynamic_sections'),
  100. 'access callback' => TRUE,
  101. 'weight' => 6,
  102. 'file' => 'ajax_example_graceful_degradation.inc',
  103. );
  104. // The above example as it appears to users with no javascript.
  105. $items['examples/ajax_example/dynamic_sections_no_js'] = array(
  106. 'title' => 'Dynamic Sections w/JS turned off',
  107. 'page callback' => 'drupal_get_form',
  108. 'page arguments' => array('ajax_example_dynamic_sections', TRUE),
  109. 'access callback' => TRUE,
  110. 'weight' => 6,
  111. 'file' => 'ajax_example_graceful_degradation.inc',
  112. );
  113. // A classic multi-step wizard, but with no page reloads.
  114. // See ajax_example_graceful_degradation.inc.
  115. $items['examples/ajax_example/wizard'] = array(
  116. 'title' => 'Wizard (with graceful degradation)',
  117. 'page callback' => 'drupal_get_form',
  118. 'page arguments' => array('ajax_example_wizard'),
  119. 'access callback' => TRUE,
  120. 'file' => 'ajax_example_graceful_degradation.inc',
  121. 'weight' => 7,
  122. );
  123. // The above example as it appears to users with no javascript.
  124. $items['examples/ajax_example/wizard_no_js'] = array(
  125. 'title' => 'Wizard w/JS turned off',
  126. 'page callback' => 'drupal_get_form',
  127. 'page arguments' => array('ajax_example_wizard', TRUE),
  128. 'access callback' => TRUE,
  129. 'file' => 'ajax_example_graceful_degradation.inc',
  130. 'weight' => 7,
  131. );
  132. // Add-more button that creates additional form elements.
  133. // See ajax_example_graceful_degradation.inc.
  134. $items['examples/ajax_example/add_more'] = array(
  135. 'title' => 'Add-more button (with graceful degradation)',
  136. 'page callback' => 'drupal_get_form',
  137. 'page arguments' => array('ajax_example_add_more'),
  138. 'access callback' => TRUE,
  139. 'file' => 'ajax_example_graceful_degradation.inc',
  140. 'weight' => 8,
  141. );
  142. // The above example as it appears to users with no javascript.
  143. $items['examples/ajax_example/add_more_no_js'] = array(
  144. 'title' => 'Add-more button w/JS turned off',
  145. 'page callback' => 'drupal_get_form',
  146. 'page arguments' => array('ajax_example_add_more', TRUE),
  147. 'access callback' => TRUE,
  148. 'file' => 'ajax_example_graceful_degradation.inc',
  149. 'weight' => 8,
  150. );
  151. // Use the AJAX framework outside the context of a form using the use-ajax
  152. // class. See ajax_example_misc.inc.
  153. $items['examples/ajax_example/ajax_link'] = array(
  154. 'title' => 'Ajax Link ("use-ajax" class)',
  155. 'page callback' => 'ajax_example_render_link',
  156. 'access callback' => TRUE,
  157. 'file' => 'ajax_example_misc.inc',
  158. 'weight' => 9,
  159. );
  160. // Use the AJAX framework outside the context of a form using a renderable
  161. // array of type link with the #ajax property. See ajax_example_misc.inc.
  162. $items['examples/ajax_example/ajax_link_renderable'] = array(
  163. 'title' => 'Ajax Link (Renderable Array)',
  164. 'page callback' => 'ajax_example_render_link_ra',
  165. 'access callback' => TRUE,
  166. 'file' => 'ajax_example_misc.inc',
  167. 'weight' => 9,
  168. );
  169. // A menu callback is required when using ajax outside of the Form API.
  170. $items['ajax_link_callback'] = array(
  171. 'page callback' => 'ajax_link_response',
  172. 'access callback' => 'user_access',
  173. 'access arguments' => array('access content'),
  174. 'type' => MENU_CALLBACK,
  175. 'file' => 'ajax_example_misc.inc',
  176. );
  177. // Use AJAX framework commands outside of the #ajax form property.
  178. // See ajax_example_advanced.inc.
  179. $items['examples/ajax_example/advanced_commands'] = array(
  180. 'title' => 'AJAX framework commands',
  181. 'page callback' => 'drupal_get_form',
  182. 'page arguments' => array('ajax_example_advanced_commands'),
  183. 'access callback' => TRUE,
  184. 'file' => 'ajax_example_advanced.inc',
  185. 'weight' => 100,
  186. );
  187. // Autocomplete examples.
  188. $items['examples/ajax_example/simple_autocomplete'] = array(
  189. 'title' => 'Autocomplete (simple)',
  190. 'page callback' => 'drupal_get_form',
  191. 'page arguments' => array('ajax_example_simple_autocomplete'),
  192. 'access arguments' => array('access user profiles'),
  193. 'file' => 'ajax_example_autocomplete.inc',
  194. 'weight' => 10,
  195. );
  196. $items['examples/ajax_example/simple_user_autocomplete_callback'] = array(
  197. 'page callback' => 'ajax_example_simple_user_autocomplete_callback',
  198. 'file' => 'ajax_example_autocomplete.inc',
  199. 'type' => MENU_CALLBACK,
  200. 'access arguments' => array('access user profiles'),
  201. );
  202. $items['examples/ajax_example/node_autocomplete'] = array(
  203. 'title' => 'Autocomplete (node with nid)',
  204. 'page callback' => 'drupal_get_form',
  205. 'page arguments' => array('ajax_example_unique_autocomplete'),
  206. 'access arguments' => array('access content'),
  207. 'file' => 'ajax_example_autocomplete.inc',
  208. 'weight' => 11,
  209. );
  210. $items['examples/ajax_example/unique_node_autocomplete_callback'] = array(
  211. 'page callback' => 'ajax_example_unique_node_autocomplete_callback',
  212. 'file' => 'ajax_example_autocomplete.inc',
  213. 'type' => MENU_CALLBACK,
  214. 'access arguments' => array('access content'),
  215. );
  216. $items['examples/ajax_example/node_by_author'] = array(
  217. 'title' => 'Autocomplete (node limited by author)',
  218. 'page callback' => 'drupal_get_form',
  219. 'page arguments' => array('ajax_example_node_by_author_autocomplete'),
  220. 'access callback' => TRUE,
  221. 'file' => 'ajax_example_autocomplete.inc',
  222. 'weight' => 12,
  223. );
  224. $items['examples/ajax_example/node_by_author_autocomplete'] = array(
  225. 'page callback' => 'ajax_example_node_by_author_node_autocomplete_callback',
  226. 'file' => 'ajax_example_autocomplete.inc',
  227. 'type' => MENU_CALLBACK,
  228. 'access arguments' => array('access content'),
  229. );
  230. // This is the landing page for the progress bar example. It uses
  231. // drupal_get_form() in order to build the form.
  232. $items['examples/ajax_example/progressbar'] = array(
  233. 'title' => 'Progress bar example',
  234. 'page callback' => 'drupal_get_form',
  235. 'page arguments' => array('ajax_example_progressbar_form'),
  236. 'access arguments' => array('access content'),
  237. 'file' => 'ajax_example_progressbar.inc',
  238. );
  239. // This is the callback route for the AJAX-based progress bar.
  240. $items['examples/ajax_example/progressbar/progress/%'] = array(
  241. 'title' => 'Progress bar progress',
  242. 'page callback' => 'ajax_example_progressbar_progress',
  243. 'page arguments' => array(4),
  244. 'type' => MENU_CALLBACK,
  245. 'access arguments' => array('access content'),
  246. 'file' => 'ajax_example_progressbar.inc',
  247. );
  248. return $items;
  249. }
  250. /**
  251. * A basic introduction page for the ajax_example module.
  252. */
  253. function ajax_example_intro() {
  254. $markup = t('The AJAX example module provides many examples of AJAX including forms, links, and AJAX commands.');
  255. $list[] = l(t('Simplest AJAX Example'), 'examples/ajax_example/simplest');
  256. $list[] = l(t('Generate checkboxes'), 'examples/ajax_example/autocheckboxes');
  257. $list[] = l(t('Generate textfields'), 'examples/ajax_example/autotextfields');
  258. $list[] = l(t('Submit-driven AJAX'), 'examples/ajax_example/submit_driven_ajax');
  259. $list[] = l(t('Dependent dropdown'), 'examples/ajax_example/dependent_dropdown');
  260. $list[] = l(t('Dependent dropdown (with graceful degradation)'), 'examples/ajax_example/dependent_dropdown_degrades');
  261. $list[] = l(t('Dynamic Sections w/JS turned off'), 'examples/ajax_example/dependent_dropdown_degrades_no_js');
  262. $list[] = l(t('Wizard (with graceful degradation)'), 'examples/ajax_example/wizard');
  263. $list[] = l(t('Wizard w/JS turned off'), 'examples/ajax_example/wizard_no_js');
  264. $list[] = l(t('Add-more button (with graceful degradation)'), 'examples/ajax_example/add_more');
  265. $list[] = l(t('Add-more button w/JS turned off'), 'examples/ajax_example/add_more_no_js');
  266. $list[] = l(t('Ajax Link ("use-ajax" class)'), 'examples/ajax_example/ajax_link');
  267. $list[] = l(t('Ajax Link (Renderable Array)'), 'examples/ajax_example/ajax_link_renderable');
  268. $list[] = l(t('AJAX framework commands'), 'examples/ajax_example/advanced_commands');
  269. $list[] = l(t('Autocomplete (simple)'), 'examples/ajax_example/simple_autocomplete');
  270. $list[] = l(t('Autocomplete (node with nid)'), 'examples/ajax_example/node_autocomplete');
  271. $list[] = l(t('Autocomplete (node limited by author)'), 'examples/ajax_example/node_by_author');
  272. $variables['items'] = $list;
  273. $variables['type'] = 'ul';
  274. $markup .= theme('item_list', $variables);
  275. return $markup;
  276. }
  277. /**
  278. * Basic AJAX callback example.
  279. *
  280. * Simple form whose ajax-enabled 'changethis' member causes a text change
  281. * in the description of the 'replace_textfield' member.
  282. *
  283. * See @link http://drupal.org/node/262422 Form API Tutorial @endlink
  284. */
  285. function ajax_example_simplest($form, &$form_state) {
  286. $form = array();
  287. $form['changethis'] = array(
  288. '#title' => t("Choose something and explain why"),
  289. '#type' => 'select',
  290. '#options' => array(
  291. 'one' => 'one',
  292. 'two' => 'two',
  293. 'three' => 'three',
  294. ),
  295. '#ajax' => array(
  296. // #ajax has two required keys: callback and wrapper.
  297. // 'callback' is a function that will be called when this element changes.
  298. 'callback' => 'ajax_example_simplest_callback',
  299. // 'wrapper' is the HTML id of the page element that will be replaced.
  300. 'wrapper' => 'replace_textfield_div',
  301. // There are also several optional keys - see ajax_example_autocheckboxes
  302. // below for details on 'method', 'effect' and 'speed' and
  303. // ajax_example_dependent_dropdown for 'event'.
  304. ),
  305. );
  306. // This entire form element will be replaced whenever 'changethis' is updated.
  307. $form['replace_textfield'] = array(
  308. '#type' => 'textfield',
  309. '#title' => t("Why"),
  310. // The prefix/suffix provide the div that we're replacing, named by
  311. // #ajax['wrapper'] above.
  312. '#prefix' => '<div id="replace_textfield_div">',
  313. '#suffix' => '</div>',
  314. );
  315. // An AJAX request calls the form builder function for every change.
  316. // We can change how we build the form based on $form_state.
  317. if (!empty($form_state['values']['changethis'])) {
  318. $form['replace_textfield']['#description'] = t("Say why you chose '@value'", array('@value' => $form_state['values']['changethis']));
  319. }
  320. return $form;
  321. }
  322. /**
  323. * Callback for ajax_example_simplest.
  324. *
  325. * On an ajax submit, the form builder function is called again, then the $form
  326. * and $form_state are passed to this callback function so it can select which
  327. * portion of the form to send on to the client.
  328. *
  329. * @return array
  330. * Renderable array (the textfield element)
  331. */
  332. function ajax_example_simplest_callback($form, $form_state) {
  333. // The form has already been submitted and updated. We can return the replaced
  334. // item as it is.
  335. return $form['replace_textfield'];
  336. }
  337. /**
  338. * Form manipulation through AJAX.
  339. *
  340. * AJAX-enabled select element causes replacement of a set of checkboxes
  341. * based on the selection.
  342. */
  343. function ajax_example_autocheckboxes($form, &$form_state) {
  344. // Since the form builder is called after every AJAX request, we rebuild
  345. // the form based on $form_state.
  346. $num_checkboxes = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
  347. $form['howmany_select'] = array(
  348. '#title' => t('How many checkboxes do you want?'),
  349. '#type' => 'select',
  350. '#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4),
  351. '#default_value' => $num_checkboxes,
  352. '#ajax' => array(
  353. 'callback' => 'ajax_example_autocheckboxes_callback',
  354. 'wrapper' => 'checkboxes-div',
  355. // 'method' defaults to replaceWith, but valid values also include
  356. // append, prepend, before and after.
  357. // 'method' => 'replaceWith',
  358. // 'effect' defaults to none. Other valid values are 'fade' and 'slide'.
  359. // See ajax_example_autotextfields for an example of 'fade'.
  360. 'effect' => 'slide',
  361. // 'speed' defaults to 'slow'. You can also use 'fast'
  362. // or a number of milliseconds for the animation to last.
  363. // 'speed' => 'slow',
  364. // Don't show any throbber...
  365. 'progress' => array('type' => 'none'),
  366. ),
  367. );
  368. $form['checkboxes_fieldset'] = array(
  369. '#title' => t("Generated Checkboxes"),
  370. // The prefix/suffix provide the div that we're replacing, named by
  371. // #ajax['wrapper'] above.
  372. '#prefix' => '<div id="checkboxes-div">',
  373. '#suffix' => '</div>',
  374. '#type' => 'fieldset',
  375. '#description' => t('This is where we get automatically generated checkboxes'),
  376. );
  377. for ($i = 1; $i <= $num_checkboxes; $i++) {
  378. $form['checkboxes_fieldset']["checkbox$i"] = array(
  379. '#type' => 'checkbox',
  380. '#title' => "Checkbox $i",
  381. );
  382. }
  383. $form['submit'] = array(
  384. '#type' => 'submit',
  385. '#value' => t('Submit'),
  386. );
  387. return $form;
  388. }
  389. /**
  390. * Callback for autocheckboxes.
  391. *
  392. * Callback element needs only select the portion of the form to be updated.
  393. * Since #ajax['callback'] return can be HTML or a renderable array (or an
  394. * array of commands), we can just return a piece of the form.
  395. * See @link ajax_example_advanced.inc AJAX Advanced Commands for more details
  396. * on AJAX framework commands.
  397. *
  398. * @return array
  399. * Renderable array (the checkboxes fieldset)
  400. */
  401. function ajax_example_autocheckboxes_callback($form, $form_state) {
  402. return $form['checkboxes_fieldset'];
  403. }
  404. /**
  405. * Show/hide textfields based on AJAX-enabled checkbox clicks.
  406. */
  407. function ajax_example_autotextfields($form, &$form_state) {
  408. $form['ask_first_name'] = array(
  409. '#type' => 'checkbox',
  410. '#title' => t('Ask me my first name'),
  411. '#ajax' => array(
  412. 'callback' => 'ajax_example_autotextfields_callback',
  413. 'wrapper' => 'textfields',
  414. 'effect' => 'fade',
  415. ),
  416. );
  417. $form['ask_last_name'] = array(
  418. '#type' => 'checkbox',
  419. '#title' => t('Ask me my last name'),
  420. '#ajax' => array(
  421. 'callback' => 'ajax_example_autotextfields_callback',
  422. 'wrapper' => 'textfields',
  423. 'effect' => 'fade',
  424. ),
  425. );
  426. $form['textfields'] = array(
  427. '#title' => t("Generated text fields for first and last name"),
  428. '#prefix' => '<div id="textfields">',
  429. '#suffix' => '</div>',
  430. '#type' => 'fieldset',
  431. '#description' => t('This is where we put automatically generated textfields'),
  432. );
  433. // Since checkboxes return TRUE or FALSE, we have to check that
  434. // $form_state has been filled as well as what it contains.
  435. if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) {
  436. $form['textfields']['first_name'] = array(
  437. '#type' => 'textfield',
  438. '#title' => t('First Name'),
  439. );
  440. }
  441. if (!empty($form_state['values']['ask_last_name']) && $form_state['values']['ask_last_name']) {
  442. $form['textfields']['last_name'] = array(
  443. '#type' => 'textfield',
  444. '#title' => t('Last Name'),
  445. );
  446. }
  447. $form['submit'] = array(
  448. '#type' => 'submit',
  449. '#value' => t('Click Me'),
  450. );
  451. return $form;
  452. }
  453. /**
  454. * Callback for autotextfields.
  455. *
  456. * Selects the piece of the form we want to use as replacement text and returns
  457. * it as a form (renderable array).
  458. *
  459. * @return array
  460. * Renderable array (the textfields element)
  461. */
  462. function ajax_example_autotextfields_callback($form, $form_state) {
  463. return $form['textfields'];
  464. }
  465. /**
  466. * A very basic form which with an AJAX-enabled submit.
  467. *
  468. * On submit, the markup in the #markup element is updated.
  469. */
  470. function ajax_example_submit_driven_ajax($form, &$form_state) {
  471. $form['box'] = array(
  472. '#type' => 'markup',
  473. '#prefix' => '<div id="box">',
  474. '#suffix' => '</div>',
  475. '#markup' => '<h1>Initial markup for box</h1>',
  476. );
  477. $form['submit'] = array(
  478. '#type' => 'submit',
  479. '#ajax' => array(
  480. 'callback' => 'ajax_example_submit_driven_callback',
  481. 'wrapper' => 'box',
  482. ),
  483. '#value' => t('Submit'),
  484. );
  485. return $form;
  486. }
  487. /**
  488. * Callback for submit_driven example.
  489. *
  490. * Select the 'box' element, change the markup in it, and return it as a
  491. * renderable array.
  492. *
  493. * @return array
  494. * Renderable array (the box element)
  495. */
  496. function ajax_example_submit_driven_callback($form, $form_state) {
  497. // In most cases, it is recommended that you put this logic in form generation
  498. // rather than the callback. Submit driven forms are an exception, because
  499. // you may not want to return the form at all.
  500. $element = $form['box'];
  501. $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
  502. return $element;
  503. }
  504. /**
  505. * AJAX-based dropdown example form.
  506. *
  507. * A form with a dropdown whose options are dependent on a
  508. * choice made in a previous dropdown.
  509. *
  510. * On changing the first dropdown, the options in the second
  511. * are updated.
  512. */
  513. function ajax_example_dependent_dropdown($form, &$form_state) {
  514. // Get the list of options to populate the first dropdown.
  515. $options_first = _ajax_example_get_first_dropdown_options();
  516. // If we have a value for the first dropdown from $form_state['values'] we use
  517. // this both as the default value for the first dropdown and also as a
  518. // parameter to pass to the function that retrieves the options for the
  519. // second dropdown.
  520. $selected = isset($form_state['values']['dropdown_first']) ? $form_state['values']['dropdown_first'] : key($options_first);
  521. $form['dropdown_first'] = array(
  522. '#type' => 'select',
  523. '#title' => 'Instrument Type',
  524. '#options' => $options_first,
  525. '#default_value' => $selected,
  526. // Bind an ajax callback to the change event (which is the default for the
  527. // select form type) of the first dropdown. It will replace the second
  528. // dropdown when rebuilt.
  529. '#ajax' => array(
  530. // When 'event' occurs, Drupal will perform an ajax request in the
  531. // background. Usually the default value is sufficient (eg. change for
  532. // select elements), but valid values include any jQuery event,
  533. // most notably 'mousedown', 'blur', and 'submit'.
  534. // 'event' => 'change',
  535. 'callback' => 'ajax_example_dependent_dropdown_callback',
  536. 'wrapper' => 'dropdown-second-replace',
  537. ),
  538. );
  539. $form['dropdown_second'] = array(
  540. '#type' => 'select',
  541. '#title' => $options_first[$selected] . ' ' . t('Instruments'),
  542. // The entire enclosing div created here gets replaced when dropdown_first
  543. // is changed.
  544. '#prefix' => '<div id="dropdown-second-replace">',
  545. '#suffix' => '</div>',
  546. // When the form is rebuilt during ajax processing, the $selected variable
  547. // will now have the new value and so the options will change.
  548. '#options' => _ajax_example_get_second_dropdown_options($selected),
  549. '#default_value' => isset($form_state['values']['dropdown_second']) ? $form_state['values']['dropdown_second'] : '',
  550. );
  551. $form['submit'] = array(
  552. '#type' => 'submit',
  553. '#value' => t('Submit'),
  554. );
  555. return $form;
  556. }
  557. /**
  558. * Selects just the second dropdown to be returned for re-rendering.
  559. *
  560. * Since the controlling logic for populating the form is in the form builder
  561. * function, all we do here is select the element and return it to be updated.
  562. *
  563. * @return array
  564. * Renderable array (the second dropdown)
  565. */
  566. function ajax_example_dependent_dropdown_callback($form, $form_state) {
  567. return $form['dropdown_second'];
  568. }
  569. /**
  570. * Helper function to populate the first dropdown.
  571. *
  572. * This would normally be pulling data from the database.
  573. *
  574. * @return array
  575. * Dropdown options.
  576. */
  577. function _ajax_example_get_first_dropdown_options() {
  578. // drupal_map_assoc() just makes an array('String' => 'String'...).
  579. return drupal_map_assoc(
  580. array(
  581. t('String'),
  582. t('Woodwind'),
  583. t('Brass'),
  584. t('Percussion'),
  585. )
  586. );
  587. }
  588. /**
  589. * Helper function to populate the second dropdown.
  590. *
  591. * This would normally be pulling data from the database.
  592. *
  593. * @param string $key
  594. * This will determine which set of options is returned.
  595. *
  596. * @return array
  597. * Dropdown options
  598. */
  599. function _ajax_example_get_second_dropdown_options($key = '') {
  600. $options = array(
  601. t('String') => drupal_map_assoc(
  602. array(
  603. t('Violin'),
  604. t('Viola'),
  605. t('Cello'),
  606. t('Double Bass'),
  607. )
  608. ),
  609. t('Woodwind') => drupal_map_assoc(
  610. array(
  611. t('Flute'),
  612. t('Clarinet'),
  613. t('Oboe'),
  614. t('Bassoon'),
  615. )
  616. ),
  617. t('Brass') => drupal_map_assoc(
  618. array(
  619. t('Trumpet'),
  620. t('Trombone'),
  621. t('French Horn'),
  622. t('Euphonium'),
  623. )
  624. ),
  625. t('Percussion') => drupal_map_assoc(
  626. array(
  627. t('Bass Drum'),
  628. t('Timpani'),
  629. t('Snare Drum'),
  630. t('Tambourine'),
  631. )
  632. ),
  633. );
  634. if (isset($options[$key])) {
  635. return $options[$key];
  636. }
  637. else {
  638. return array();
  639. }
  640. }
  641. /**
  642. * @} End of "defgroup ajax_example".
  643. */