ajax_example_graceful_degradation.inc

  1. examples
    1. 7 ajax_example/ajax_example_graceful_degradation.inc
    2. 8 ajax_example/ajax_example_graceful_degradation.inc

Demonstrations of AJAX with graceful degradation.

Functions & methods

NameDescription
ajax_example_add_moreThis example shows a button to "add more" - add another textfield, and the corresponding "remove" button.
ajax_example_add_more_add_oneSubmit handler for the "add-one-more" button.
ajax_example_add_more_callbackCallback for both ajax-enabled buttons.
ajax_example_add_more_remove_oneSubmit handler for the "remove one" button.
ajax_example_add_more_submitFinal submit handler.
ajax_example_dependent_dropdown_degradesA form with a dropdown whose options are dependent on a choice made in a previous dropdown.
ajax_example_dependent_dropdown_degrades_first_callbackSelects just the second dropdown to be returned for re-rendering.
ajax_example_dependent_dropdown_degrades_submitSubmit function for ajax_example_dependent_dropdown_degrades().
ajax_example_dynamic_sectionsExample of a form with portions dynamically enabled or disabled, but with graceful degradation in the case of no javascript.
ajax_example_dynamic_sections_select_callbackCallback for the select element.
ajax_example_dynamic_sections_submitSubmit function for ajax_example_dynamic_sections().
ajax_example_dynamic_sections_validateValidation function for ajax_example_dynamic_sections().
ajax_example_wizardThis example is a classic wizard, where a different and sequential form is presented on each step of the form.
ajax_example_wizard_callback
ajax_example_wizard_submitSubmit function for ajax_example_wizard.

File

ajax_example/ajax_example_graceful_degradation.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Demonstrations of AJAX with graceful degradation.
  5. */
  6. /**
  7. * @defgroup ajax_degradation_example Example: AJAX Graceful Degradation
  8. * @ingroup examples
  9. * @{
  10. * These examples show AJAX with graceful degradation when Javascript is not
  11. * available.
  12. *
  13. * In each of these the key idea is that the form is rebuilt different ways
  14. * depending on form input. In order to accomplish that, the formbuilder function
  15. * is in charge of almost all logic.
  16. */
  17. /**
  18. * A form with a dropdown whose options are dependent on a
  19. * choice made in a previous dropdown.
  20. *
  21. * On changing the first dropdown, the options in the second
  22. * are updated. Gracefully degrades if no javascript.
  23. *
  24. * A bit of CSS and javascript is required. The CSS hides the "add more" button
  25. * if javascript is not enabled. The Javascript snippet is really only used
  26. * to enable us to present the form in degraded mode without forcing the user
  27. * to turn off Javascript. Both of these are loaded by using the
  28. * #attached FAPI property, so it is a good example of how to use that.
  29. *
  30. * The extra argument $no_js_use is here only to allow presentation of this
  31. * form as if Javascript were not enabled. ajax_example_menu() provides two
  32. * ways to call this form, one normal ($no_js_use = FALSE) and one simulating
  33. * Javascript disabled ($no_js_use = TRUE).
  34. */
  35. function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_use = FALSE) {
  36. // Get the list of options to populate the first dropdown.
  37. $options_first = _ajax_example_get_first_dropdown_options();
  38. // If we have a value for the first dropdown from $form_state['values'] we use
  39. // this both as the default value for the first dropdown and also as a
  40. // parameter to pass to the function that retrieves the options for the
  41. // second dropdown.
  42. $selected = isset($form_state['values']['dropdown_first']) ? $form_state['values']['dropdown_first'] : key($options_first);
  43. // Attach the CSS and JS we need to show this with and without javascript.
  44. // Without javascript we need an extra "Choose" button, and this is
  45. // hidden when we have javascript enabled.
  46. $form['#attached']['css'] = array(
  47. drupal_get_path('module', 'ajax_example') . '/ajax_example.css',
  48. );
  49. $form['#attached']['js'] = array(
  50. drupal_get_path('module', 'ajax_example') . '/ajax_example.js',
  51. );
  52. $form['dropdown_first_fieldset'] = array(
  53. '#type' => 'fieldset',
  54. );
  55. $form['dropdown_first_fieldset']['dropdown_first'] = array(
  56. '#type' => 'select',
  57. '#title' => 'Instrument Type',
  58. '#options' => $options_first,
  59. '#attributes' => array('class' => array('enabled-for-ajax')),
  60. // The '#ajax' property allows us to bind a callback to the server whenever this
  61. // form element changes. See ajax_example_autocheckboxes and
  62. // ajax_example_dependent_dropdown in ajax_example.module for more details.
  63. '#ajax' => array(
  64. 'callback' => 'ajax_example_dependent_dropdown_degrades_first_callback',
  65. 'wrapper' => 'dropdown-second-replace',
  66. ),
  67. );
  68. // This simply allows us to demonstrate no-javascript use without
  69. // actually turning off javascript in the browser. Removing the #ajax
  70. // element turns off AJAX behaviors on that element and as a result
  71. // ajax.js doesn't get loaded. This is for demonstration purposes only.
  72. if ($no_js_use) {
  73. unset($form['dropdown_first_fieldset']['dropdown_first']['#ajax']);
  74. }
  75. // Since we don't know if the user has js or not, we always need to output
  76. // this element, then hide it with with css if javascript is enabled.
  77. $form['dropdown_first_fieldset']['continue_to_second'] = array(
  78. '#type' => 'submit',
  79. '#value' => t('Choose'),
  80. '#attributes' => array('class' => array('next-button')),
  81. );
  82. $form['dropdown_second_fieldset'] = array(
  83. '#type' => 'fieldset',
  84. );
  85. $form['dropdown_second_fieldset']['dropdown_second'] = array(
  86. '#type' => 'select',
  87. '#title' => $options_first[$selected] . ' ' . t('Instruments'),
  88. '#prefix' => '<div id="dropdown-second-replace">',
  89. '#suffix' => '</div>',
  90. '#attributes' => array('class' => array('enabled-for-ajax')),
  91. // When the form is rebuilt during processing (either AJAX or multistep),
  92. // the $selected variable will now have the new value and so the options
  93. // will change.
  94. '#options' => _ajax_example_get_second_dropdown_options($selected),
  95. );
  96. $form['dropdown_second_fieldset']['submit'] = array(
  97. '#type' => 'submit',
  98. '#value' => t('OK'),
  99. // This class allows attached js file to override the disabled attribute,
  100. // since it's not necessary in ajax-enabled form.
  101. '#attributes' => array('class' => array('enabled-for-ajax')),
  102. );
  103. // Disable dropdown_second if a selection has not been made on dropdown_first.
  104. if (empty($form_state['values']['dropdown_first'])) {
  105. $form['dropdown_second_fieldset']['dropdown_second']['#disabled'] = TRUE;
  106. $form['dropdown_second_fieldset']['dropdown_second']['#description'] = t('You must make your choice on the first dropdown before changing this second one.');
  107. $form['dropdown_second_fieldset']['submit']['#disabled'] = TRUE;
  108. }
  109. return $form;
  110. }
  111. /**
  112. * Submit function for ajax_example_dependent_dropdown_degrades().
  113. */
  114. function ajax_example_dependent_dropdown_degrades_submit($form, &$form_state) {
  115. // Now handle the case of the next, previous, and submit buttons.
  116. // only submit will result in actual submission, all others rebuild.
  117. switch ($form_state['triggering_element']['#value']) {
  118. case t('OK'): // Submit: We're done.
  119. drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', array('@first' => $form_state['values']['dropdown_first'], '@second' => $form_state['values']['dropdown_second'])));
  120. return;
  121. }
  122. // 'Choose' or anything else will cause rebuild of the form and present
  123. // it again.
  124. $form_state['rebuild'] = TRUE;
  125. }
  126. /**
  127. * Selects just the second dropdown to be returned for re-rendering.
  128. *
  129. * @return
  130. * Renderable array (the second dropdown).
  131. */
  132. function ajax_example_dependent_dropdown_degrades_first_callback($form, $form_state) {
  133. return $form['dropdown_second_fieldset']['dropdown_second'];
  134. }
  135. /**
  136. * Example of a form with portions dynamically enabled or disabled, but
  137. * with graceful degradation in the case of no javascript.
  138. *
  139. * The idea here is that certain parts of the form don't need to be displayed
  140. * unless a given option is selected, but then they should be displayed and
  141. * configured.
  142. *
  143. * The third $no_js_use argument is strictly for demonstrating operation
  144. * without javascript, without making the user/developer turn off javascript.
  145. */
  146. function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE) {
  147. // Attach the CSS and JS we need to show this with and without javascript.
  148. // Without javascript we need an extra "Choose" button, and this is
  149. // hidden when we have javascript enabled.
  150. $form['#attached']['css'] = array(
  151. drupal_get_path('module', 'ajax_example') . '/ajax_example.css',
  152. );
  153. $form['#attached']['js'] = array(
  154. drupal_get_path('module', 'ajax_example') . '/ajax_example.js',
  155. );
  156. $form['description'] = array(
  157. '#type' => 'markup',
  158. '#markup' => '<div>' . t('This example demonstrates a form which dynamically creates various sections based on the configuration in the form.
  159. It deliberately allows graceful degradation to a non-javascript environment.
  160. In a javascript environment, the "Choose" button next to the select control
  161. if displayed; in a non-js environment it is hidden by the module CSS.
  162. <br/><br/>The basic idea here is that the form is built up based on
  163. the selection in the question_type_select field, and it is built the same
  164. whether we are in a javascript/AJAX environment or not.
  165. <br/><br/>
  166. Try the <a href="!ajax_link">AJAX version</a> and the <a href="!non_ajax_link">simulated-non-AJAX version</a>.
  167. ', array('!ajax_link' => url('examples/ajax_example/dynamic_sections'), '!non_ajax_link' => url('examples/ajax_example/dynamic_sections_no_js') )) . '</div>',
  168. );
  169. $form['question_type_select'] = array(
  170. '#type' => 'select',
  171. '#title' => t('Question style'),
  172. '#options' => drupal_map_assoc(array(t('Choose question style'), t('Multiple Choice'), t('True/False'), t('Fill-in-the-blanks'))),
  173. '#ajax' => array(
  174. 'wrapper' => 'questions-fieldset-wrapper',
  175. 'callback' => 'ajax_example_dynamic_sections_select_callback',
  176. ),
  177. );
  178. // The CSS for this module hides this next button if JS is enabled.
  179. $form['question_type_submit'] = array(
  180. '#type' => 'submit',
  181. '#value' => t('Choose'),
  182. '#attributes' => array('class' => array('next-button')),
  183. '#limit_validation_errors' => array(), // No need to validate when submitting this.
  184. '#validate' => array(),
  185. );
  186. // This simply allows us to demonstrate no-javascript use without
  187. // actually turning off javascript in the browser. Removing the #ajax
  188. // element turns off AJAX behaviors on that element and as a result
  189. // ajax.js doesn't get loaded.
  190. if ($no_js_use) {
  191. // Remove the #ajax from the above, so ajax.js won't be loaded.
  192. unset($form['question_type_select']['#ajax']);
  193. }
  194. // This fieldset just serves as a container for the part of the form
  195. // that gets rebuilt.
  196. $form['questions_fieldset'] = array(
  197. '#type' => 'fieldset',
  198. // These provide the wrapper referred to in #ajax['wrapper'] above.
  199. '#prefix' => '<div id="questions-fieldset-wrapper">',
  200. '#suffix' => '</div>',
  201. );
  202. if (!empty($form_state['values']['question_type_select'])) {
  203. $form['questions_fieldset']['question'] = array(
  204. '#markup' => t('Who was the first president of the U.S.?'),
  205. );
  206. $question_type = $form_state['values']['question_type_select'];
  207. switch ($question_type) {
  208. case t('Multiple Choice'):
  209. $form['questions_fieldset']['question'] = array(
  210. '#type' => 'radios',
  211. '#title' => t('Who was the first president of the United States'),
  212. '#options' => drupal_map_assoc(array(t('George Bush'), t('Adam McGuire'), t('Abraham Lincoln'), t('George Washington'))),
  213. );
  214. break;
  215. case t('True/False'):
  216. $form['questions_fieldset']['question'] = array(
  217. '#type' => 'radios',
  218. '#title' => t('Was George Washington the first president of the United States?'),
  219. '#options' => array(t('George Washington') => t("True"), 0 => t("False")),
  220. '#description' => t('Click "True" if you think George Washington was the first president of the United States.'),
  221. );
  222. break;
  223. case t('Fill-in-the-blanks'):
  224. $form['questions_fieldset']['question'] = array(
  225. '#type' => 'textfield',
  226. '#title' => t('Who was the first president of the United States'),
  227. '#description' => t('Please type the correct answer to the question.'),
  228. );
  229. break;
  230. }
  231. $form['questions_fieldset']['submit'] = array(
  232. '#type' => 'submit',
  233. '#value' => t('Submit your answer'),
  234. );
  235. }
  236. return $form;
  237. }
  238. /**
  239. * Validation function for ajax_example_dynamic_sections().
  240. */
  241. function ajax_example_dynamic_sections_validate($form, &$form_state) {
  242. $answer = $form_state['values']['question'];
  243. if ($answer !== t('George Washington')) {
  244. form_set_error('question', t('Wrong answer. Try again. (Hint: The right answer is "George Washington".)'));
  245. }
  246. }
  247. /**
  248. * Submit function for ajax_example_dynamic_sections().
  249. */
  250. function ajax_example_dynamic_sections_submit($form, &$form_state) {
  251. // This is only executed when a button is pressed, not when the AJAXified
  252. // select is changed.
  253. // Now handle the case of the next, previous, and submit buttons.
  254. // Only submit will result in actual submission, all others rebuild.
  255. switch ($form_state['triggering_element']['#value']) {
  256. case t('Submit your answer'): // Submit: We're done.
  257. $form_state['rebuild'] = FALSE;
  258. $answer = $form_state['values']['question'];
  259. // Special handling for the checkbox.
  260. if ($answer == 1 && $form['questions_fieldset']['question']['#type'] == 'checkbox') {
  261. $answer = $form['questions_fieldset']['question']['#title'];
  262. }
  263. if ($answer === t('George Washington')) {
  264. drupal_set_message(t('You got the right answer: @answer', array('@answer' => $answer)));
  265. }
  266. else {
  267. drupal_set_message(t('Sorry, your answer (@answer) is wrong', array('@answer' => $answer)));
  268. }
  269. $form_state['rebuild'] = FALSE;
  270. return;
  271. // Any other form element will cause rebuild of the form and present
  272. // it again.
  273. case t('Choose'):
  274. $form_state['values']['question_type_select']
  275. = $form_state['input']['question_type_select'];
  276. // Fall through.
  277. default:
  278. $form_state['rebuild'] = TRUE;
  279. }
  280. }
  281. /**
  282. * Callback for the select element.
  283. *
  284. * This just selects and returns the questions_fieldset.
  285. */
  286. function ajax_example_dynamic_sections_select_callback($form, $form_state) {
  287. return $form['questions_fieldset'];
  288. }
  289. /**
  290. * This example is a classic wizard, where a different and sequential form
  291. * is presented on each step of the form.
  292. *
  293. * In the AJAX version, the form is replaced for each wizard section. In the
  294. * multistep version, it causes a new page load.
  295. *
  296. * @param $form
  297. * @param $form_state
  298. * @param $no_js_use
  299. * Used for this demonstration only. If true means that the form should be
  300. * built using a simulated no-javascript approach (ajax.js will not be
  301. * loaded.)
  302. */
  303. function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) {
  304. // Provide a wrapper around the entire form, since we'll replace the whole
  305. // thing with each submit.
  306. $form['#prefix'] = '<div id="wizard-form-wrapper">';
  307. $form['#suffix'] = '</div>';
  308. $form['#tree'] = TRUE; // We want to deal with hierarchical form values.
  309. $form['description'] = array(
  310. '#markup' => '<div>' . t('This example is a step-by-step wizard. The <a href="!ajax">AJAX version</a> does it without page reloads; the <a href="!multistep">multistep version</a> is the same code but simulates a non-javascript environment, showing it with page reloads.',
  311. array('!ajax' => url('examples/ajax_example/wizard'), '!multistep' => url('examples/ajax_example/wizard_no_js')))
  312. . '</div>',
  313. );
  314. // $form_state['storage'] has no specific drupal meaning, but it is
  315. // traditional to keep variables for multistep forms there.
  316. $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step'];
  317. $form_state['storage']['step'] = $step;
  318. switch ($step) {
  319. case 1:
  320. $form['step1'] = array(
  321. '#type' => 'fieldset',
  322. '#title' => t('Step 1: Personal details'),
  323. );
  324. $form['step1']['name'] = array(
  325. '#type' => 'textfield',
  326. '#title' => t('Your name'),
  327. '#default_value' => empty($form_state['values']['step1']['name']) ? '' : $form_state['values']['step1']['name'],
  328. '#required' => TRUE,
  329. );
  330. break;
  331. case 2:
  332. $form['step2'] = array(
  333. '#type' => 'fieldset',
  334. '#title' => t('Step 2: Street address info'),
  335. );
  336. $form['step2']['address'] = array(
  337. '#type' => 'textfield',
  338. '#title' => t('Your street address'),
  339. '#default_value' => empty($form_state['values']['step2']['address']) ? '' : $form_state['values']['step2']['address'],
  340. '#required' => TRUE,
  341. );
  342. break;
  343. case 3:
  344. $form['step3'] = array(
  345. '#type' => 'fieldset',
  346. '#title' => t('Step 3: City info'),
  347. );
  348. $form['step3']['city'] = array(
  349. '#type' => 'textfield',
  350. '#title' => t('Your city'),
  351. '#default_value' => empty($form_state['values']['step3']['city']) ? '' : $form_state['values']['step3']['city'],
  352. '#required' => TRUE,
  353. );
  354. break;
  355. }
  356. if ($step == 3) {
  357. $form['submit'] = array(
  358. '#type' => 'submit',
  359. '#value' => t("Submit your information"),
  360. );
  361. }
  362. if ($step < 3) {
  363. $form['next'] = array(
  364. '#type' => 'submit',
  365. '#value' => t('Next step'),
  366. '#ajax' => array(
  367. 'wrapper' => 'wizard-form-wrapper',
  368. 'callback' => 'ajax_example_wizard_callback',
  369. ),
  370. );
  371. }
  372. if ($step > 1) {
  373. $form['prev'] = array(
  374. '#type' => 'submit',
  375. '#value' => t("Previous step"),
  376. // Since all info will be discarded, don't validate on 'prev'.
  377. '#limit_validation_errors' => array(),
  378. // #submit is required to use #limit_validation_errors
  379. '#submit' => array('ajax_example_wizard_submit'),
  380. '#ajax' => array(
  381. 'wrapper' => 'wizard-form-wrapper',
  382. 'callback' => 'ajax_example_wizard_callback',
  383. ),
  384. );
  385. }
  386. // This simply allows us to demonstrate no-javascript use without
  387. // actually turning off javascript in the browser. Removing the #ajax
  388. // element turns off AJAX behaviors on that element and as a result
  389. // ajax.js doesn't get loaded.
  390. // For demonstration only! You don't need this.
  391. if ($no_js_use) {
  392. // Remove the #ajax from the above, so ajax.js won't be loaded.
  393. // For demonstration only.
  394. unset($form['next']['#ajax']);
  395. unset($form['prev']['#ajax']);
  396. }
  397. return $form;
  398. }
  399. function ajax_example_wizard_callback($form, $form_state) {
  400. return $form;
  401. }
  402. /**
  403. * Submit function for ajax_example_wizard.
  404. *
  405. * In AJAX this is only submitted when the final submit button is clicked,
  406. * but in the non-javascript situation, it is submitted with every
  407. * button click.
  408. */
  409. function ajax_example_wizard_submit($form, &$form_state) {
  410. // Save away the current information.
  411. $current_step = 'step' . $form_state['storage']['step'];
  412. if (!empty($form_state['values'][$current_step])) {
  413. $form_state['storage']['values'][$current_step] = $form_state['values'][$current_step];
  414. }
  415. // Increment or decrement the step as needed. Recover values if they exist.
  416. if ($form_state['triggering_element']['#value'] == t('Next step')) {
  417. $form_state['storage']['step']++;
  418. // If values have already been entered for this step, recover them from
  419. // $form_state['storage'] to pre-populate them.
  420. $step_name = 'step' . $form_state['storage']['step'];
  421. if (!empty($form_state['storage']['values'][$step_name])) {
  422. $form_state['values'][$step_name] = $form_state['storage']['values'][$step_name];
  423. }
  424. }
  425. if ($form_state['triggering_element']['#value'] == t('Previous step')) {
  426. $form_state['storage']['step']--;
  427. // Recover our values from $form_state['storage'] to pre-populate them.
  428. $step_name = 'step' . $form_state['storage']['step'];
  429. $form_state['values'][$step_name] = $form_state['storage']['values'][$step_name];
  430. }
  431. // If they're done, submit.
  432. if ($form_state['triggering_element']['#value'] == t('Submit your information')) {
  433. $value_message = t('Your information has been submitted:') . ' ';
  434. foreach ($form_state['storage']['values'] as $step => $values) {
  435. $value_message .= "$step: ";
  436. foreach ($values as $key => $value) {
  437. $value_message .= "$key=$value, ";
  438. }
  439. }
  440. drupal_set_message($value_message);
  441. $form_state['rebuild'] = FALSE;
  442. return;
  443. }
  444. // Otherwise, we still have work to do.
  445. $form_state['rebuild'] = TRUE;
  446. }
  447. /**
  448. * This example shows a button to "add more" - add another textfield, and
  449. * the corresponding "remove" button.
  450. *
  451. * It works equivalently with javascript or not, and does the same basic steps
  452. * either way.
  453. *
  454. * The basic idea is that we build the form based on the setting of
  455. * $form_state['num_names']. The custom submit functions for the "add-one"
  456. * and "remove-one" buttons increment and decrement $form_state['num_names']
  457. * and then force a rebuild of the form.
  458. *
  459. * The $no_js_use argument is simply for demonstration: When set, it prevents
  460. * '#ajax' from being set, thus making the example behave as if javascript
  461. * were disabled in the browser.
  462. */
  463. function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) {
  464. $form['description'] = array(
  465. '#markup' => '<div>' . t('This example shows an add-more and a remove-last button. The <a href="!ajax">AJAX version</a> does it without page reloads; the <a href="!multistep">non-js version</a> is the same code but simulates a non-javascript environment, showing it with page reloads.',
  466. array('!ajax' => url('examples/ajax_example/add_more'), '!multistep' => url('examples/ajax_example/add_more_no_js')))
  467. . '</div>',
  468. );
  469. // Because we have many fields with the same values, we have to set
  470. // #tree to be able to access them.
  471. $form['#tree'] = TRUE;
  472. $form['names_fieldset'] = array(
  473. '#type' => 'fieldset',
  474. '#title' => t('People coming to the picnic'),
  475. // Set up the wrapper so that AJAX will be able to replace the fieldset.
  476. '#prefix' => '<div id="names-fieldset-wrapper">',
  477. '#suffix' => '</div>',
  478. );
  479. // Build the fieldset with the proper number of names. We'll use
  480. // $form_state['num_names'] to determine the number of textfields to build.
  481. if (empty($form_state['num_names'])) {
  482. $form_state['num_names'] = 1;
  483. }
  484. for ($i = 0; $i < $form_state['num_names']; $i++) {
  485. $form['names_fieldset']['name'][$i] = array(
  486. '#type' => 'textfield',
  487. '#title' => t('Name'),
  488. );
  489. }
  490. $form['names_fieldset']['add_name'] = array(
  491. '#type' => 'submit',
  492. '#value' => t('Add one more'),
  493. '#submit' => array('ajax_example_add_more_add_one'),
  494. // See the examples in ajax_example.module for more details on the
  495. // properties of #ajax.
  496. '#ajax' => array(
  497. 'callback' => 'ajax_example_add_more_callback',
  498. 'wrapper' => 'names-fieldset-wrapper',
  499. ),
  500. );
  501. if ($form_state['num_names'] > 1) {
  502. $form['names_fieldset']['remove_name'] = array(
  503. '#type' => 'submit',
  504. '#value' => t('Remove one'),
  505. '#submit' => array('ajax_example_add_more_remove_one'),
  506. '#ajax' => array(
  507. 'callback' => 'ajax_example_add_more_callback',
  508. 'wrapper' => 'names-fieldset-wrapper',
  509. ),
  510. );
  511. }
  512. $form['submit'] = array(
  513. '#type' => 'submit',
  514. '#value' => t('Submit'),
  515. );
  516. // This simply allows us to demonstrate no-javascript use without
  517. // actually turning off javascript in the browser. Removing the #ajax
  518. // element turns off AJAX behaviors on that element and as a result
  519. // ajax.js doesn't get loaded.
  520. // For demonstration only! You don't need this.
  521. if ($no_js_use) {
  522. // Remove the #ajax from the above, so ajax.js won't be loaded.
  523. if (!empty($form['names_fieldset']['remove_name']['#ajax'])) {
  524. unset($form['names_fieldset']['remove_name']['#ajax']);
  525. }
  526. unset($form['names_fieldset']['add_name']['#ajax']);
  527. }
  528. return $form;
  529. }
  530. /**
  531. * Callback for both ajax-enabled buttons.
  532. *
  533. * Selects and returns the fieldset with the names in it.
  534. */
  535. function ajax_example_add_more_callback($form, $form_state) {
  536. return $form['names_fieldset'];
  537. }
  538. /**
  539. * Submit handler for the "add-one-more" button.
  540. *
  541. * Increments the max counter and causes a rebuild.
  542. */
  543. function ajax_example_add_more_add_one($form, &$form_state) {
  544. $form_state['num_names']++;
  545. $form_state['rebuild'] = TRUE;
  546. }
  547. /**
  548. * Submit handler for the "remove one" button.
  549. *
  550. * Decrements the max counter and causes a form rebuild.
  551. */
  552. function ajax_example_add_more_remove_one($form, &$form_state) {
  553. if ($form_state['num_names'] > 1) {
  554. $form_state['num_names']--;
  555. }
  556. $form_state['rebuild'] = TRUE;
  557. }
  558. /**
  559. * Final submit handler.
  560. *
  561. * Reports what values were finally set.
  562. */
  563. function ajax_example_add_more_submit($form, &$form_state) {
  564. $output = t('These people are coming to the picnic: @names',
  565. array('@names' => implode(', ', $form_state['values']['names_fieldset']['name'])) );
  566. drupal_set_message($output);
  567. }
  568. /**
  569. * @} End of "defgroup ajax_degradation_example".
  570. */
Login or register to post comments