diff -u b/ajax_example/ajax_example.links.menu.yml b/ajax_example/ajax_example.links.menu.yml --- b/ajax_example/ajax_example.links.menu.yml +++ b/ajax_example/ajax_example.links.menu.yml @@ -4,60 +4,70 @@ - parent: '' - + weight: 10 ajax_example.simplest: title: 'Simplest AJAX Example' route_name: 'ajax_example.simplest' - parent: '' + parent: ajax_example.description ajax_example.autocheckboxes: title: 'Generate checkboxes' route_name: 'ajax_example.autocheckboxes' + parent: ajax_example.description ajax_example.autotextfeilds: title: 'Generate textfields' route_name: 'ajax_example.autotextfields' + parent: ajax_example.description ajax_example.submit-driven: title: 'Submit-driven AJAX' route_name: 'ajax_example.submit-driven-ajax' + parent: ajax_example.description ajax_example.dependent-dropdown: title: 'Dependent dropdown' route_name: 'ajax_example.dependent_dropdown' + parent: ajax_example.description ajax_example.dependent-dropdown-degardes: title: 'Dependent dropdown degardes' route_name: 'ajax_example.dependent_dropdown_degardes' + parent: ajax_example.description ajax_example.dependent-dropdown-degardes-nojava: title: 'Dependent dropdown degardes w/JS turned off ' route_name: 'ajax_example.dependent_dropdown_degardes_nojava' + parent: ajax_example.description ajax_example.dynamic-dropdown: title: 'Dynamic Sections (with graceful degradation)' route_name: 'ajax_example.dynamic_sections' + parent: ajax_example.description ajax_example.dynamic-dropdown-degardes-nojava-example: title: 'Dynamic Sections (with graceful degradation) w/js turned off' route_name: 'ajax_example.dynamic_sections_nojava' + parent: ajax_example.description ajax_example.wizard-example: - title: 'Ajax Wizard Example' + title: 'AJAX Wizard Example' route_name: 'ajax_example.Wizard' + parent: ajax_example.description ajax_example.wizard-examplenojs: - title: 'Ajax Wizard Example w/JS turned off' + title: 'AJAX Wizard Example w/JS turned off' route_name: 'ajax_example.Wizardnojs' + parent: ajax_example.description ajax_example.addmorenojs: title: 'Add more button (with graceful degradation) w/JS turned off' route_name: 'ajax_example.Addmorenojs' + parent: ajax_example.description ajax_example.addmore: - title: 'Ajax Add more button' + title: 'AJAX Add more button' route_name: 'ajax_example.Addmore' + parent: ajax_example.description ajax_example.Advanced: title: 'AJAX framework commands' route_name: 'ajax_example.Advanced' - - + parent: ajax_example.description reverted: --- b/ajax_example/config/install/ajaxexample.settings.yml +++ /dev/null @@ -1 +0,0 @@ -variable_name : 0 diff -u b/ajax_example/css/ajax_example.css b/ajax_example/css/ajax_example.css --- b/ajax_example/css/ajax_example.css +++ b/ajax_example/css/ajax_example.css @@ -2,7 +2,6 @@ * @file * CSS for ajax_example. * - * See @link ajax_example_dependent_dropdown_degrades @endlink for * details on what this file does. It is not used in any other example. */ /* Hides the next button when not degrading to non-javascript browser */ diff -u b/ajax_example/js/ajax_example.js b/ajax_example/js/ajax_example.js --- b/ajax_example/js/ajax_example.js +++ b/ajax_example/js/ajax_example.js @@ -2,8 +2,6 @@ * @file * JavaScript for ajax_example. * - * See @link ajax_example_dependent_dropdown_degrades @endlink for - * details on what this file does. It is not used in any other example. */ (function($) { diff -u b/ajax_example/src/Controller/AjaxExampleController.php b/ajax_example/src/Controller/AjaxExampleController.php --- b/ajax_example/src/Controller/AjaxExampleController.php +++ b/ajax_example/src/Controller/AjaxExampleController.php @@ -9,15 +9,15 @@ use Drupal\Core\Url; use Drupal\Core\Ajax\AppendCommand; use Drupal\Core\Database\Database; -use Drupal\Core\Database\Query\Condition; +use Drupal\Core\Database\Connection; use Drupal\Component\Utility\SafeMarkup; - /** - * Controller routines for block example routes. + * Controller routines for AJAX example routes. */ class AjaxExampleController extends ControllerBase { use DescriptionTemplateTrait; + protected $connection; /** * {@inheritdoc} @@ -27,6 +27,17 @@ } /** + * + */ + + public function basicInstructions() { + return [ + $this->description(), + ]; + } + + + /** * Get the progress bar execution status, as JSON. * * This is the menu handler for @@ -81,7 +92,8 @@ public function ajaxExampleRenderLinkRa() { $build['my_div'] = [ - '#markup' => $this->t('The link below has been rendered as an element with the #ajax property, so if + '#markup' => $this->t(' +The link below has been rendered as an element with the #ajax property, so if javascript is enabled, ajax.js will try to submit it via an AJAX call instead of a normal page load. The URL also contains the "/nojs/" magic string, which is stripped if javascript is enabled, allowing the server code to tell by the @@ -138,7 +150,6 @@ * If $type == 'ajax', returns an array of AJAX Commands. * Otherwise, just returns the content, which will end up being a page. * - * @ingroup ajax_example */ public function ajaxlinkresponse($type = 'ajax') { if ($type == 'ajax') { @@ -159,77 +170,104 @@ } - public function ajax_example_simple_user_autocomplete_callback($string = "") { - - $matches = array(); - - if ($string) { - $db = \Drupal::database(); - $result = $db->select('users') - ->fields('users', array('name', 'uid')) - ->condition('name', $db->like($string) . '%', 'LIKE') - ->range(0, 10) - ->execute(); - foreach ($result as $user) { - // In the simplest case (see user_autocomplete), the key and the value are - // the same. Here we'll display the uid along with the username in the - // dropdown. - $matches[] = array('value' => $user->name, 'label' => $user->uid); - $matches[$user->name] = SafeMarkup::check_plain($user->name) . " (uid=$user->uid)"; +/** + * It works simply by searching usernames (and of course in Drupal usernames + * are unique, so can be used for identifying a record.) + * + * The returned $matches array has + * * key: string which will be displayed once the autocomplete is selected + * * value: the value which will is displayed in the autocomplete pulldown. + * + * In the simplest cases (see drupal/ajax_example/form/AjaxExampleAutocomplete.php) + * these are the same, andnothing needs to be done. However, more complicated + * autocompletes require more work. Here we demonstrate the difference by + * displaying the UID along with the username in the dropdown. + * + * In the end, though, we'll be doing something with the value that ends up in + * the textfield, so it needs to uniquely identify the record we want to access. + * This is demonstrated in ajax_example_unique_autocomplete(). + * + * @param string $string + * The string that will be searched. + */ + public function ajax_example_simple_user_autocomplete_callback(Connection $connection, $string = "") { + $this->connection = Connection::$connection; + $matches = []; + + if ($string) { + + $result = $this->connection->select('users') + ->fields('users', ['name', 'uid']) + ->condition('name', $this->connection->like($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $user) { + // In the simplest case (see user_autocomplete), the key and the value are + // the same. Here we'll display the uid along with the username in the + // dropdown. + $matches[] = ['value' => $user->name, 'label' => $user->uid]; + $matches[$user->name] = SafeMarkup::check_plain($user->name) . " (uid=$user->uid)"; + } } + + return new JsonResponse($matches); } - return new JsonResponse($matches); -} -/** - * Autocomplete callback for nodes by title. - * - * Searches for a node by title, but then identifies it by nid, so the actual - * returned value can be used later by the form. - * - * The returned $matches array has - * - key: The title, with the identifying nid in brackets, like "Some node - * title [3325]" - * - value: the title which will is displayed in the autocomplete pulldown. - * - * Note that we must use a key style that can be parsed successfully and - * unambiguously. For example, if we might have node titles that could have - * [3325] in them, then we'd have to use a more restrictive token. - * - * @param string $string - * The string that will be searched. - */ -public function ajax_example_unique_node_autocomplete_callback($string = "") { - $matches = array(); - if ($string) { - $db = Database::getConnection(); - $result = $db->select('node') - ->fields('node', array('nid', 'title')) - ->condition('title', $db->escapeLike($string) . '%', 'LIKE') - ->range(0, 10) - ->execute(); - foreach ($result as $node) { - $matches[$node->title . " [$node->nid]"] = SafeMarkup::check_plain($node->title); + /** + * Autocomplete callback for nodes by title. + * + * Searches for a node by title, but then identifies it by nid, so the actual + * returned value can be used later by the form. + * + * The returned $matches array has + * - key: The title, with the identifying nid in brackets, like "Some node + * title [3325]" + * - value: the title which will is displayed in the autocomplete pulldown. + * + * Note that we must use a key style that can be parsed successfully and + * unambiguously. For example, if we might have node titles that could have + * [3325] in them, then we'd have to use a more restrictive token. + * + * @param string $string + * The string that will be searched. + */ + public function ajax_example_unique_node_autocomplete_callback($string = "") { + $this->connection = Connection::$connection; + $matches = []; + if ($string) { + + $result = $this->connection->select('node') + ->fields('node', ['nid', 'title']) + ->condition('title', $this->connection->escapeLike($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $node) { + $matches[$node->title . " [$node->nid]"] = SafeMarkup::check_plain($node->title); + } } + + return new JsonResponse($matches); } - return new JsonResponse($matches); -} -public function ajax_example_node_by_author_node_autocomplete_callback($author_uid, $string = "") { - $matches = array(); - if ($author_uid > 0 && trim($string)) { - $db = Database::getConnection(); - $result = $db->select('node') - ->fields('node', array('nid', 'title')) - ->condition('uid', $author_uid) - ->condition('title', $db->escapeLike($string) . '%', 'LIKE') - ->range(0, 10) - ->execute(); - foreach ($result as $node) { - $matches[$node->title . " [$node->nid]"] = SafeMarkup::check_plain($node->title); + /** + * + */ + public function ajax_example_node_by_author_node_autocomplete_callback($author_uid, $string = "") { + $this->connection = Connection::$connection; + $matches = []; + if ($author_uid > 0 && trim($string)) { + $db = Database::getConnection(); + $result = $db->select('node') + ->fields('node', ['nid', 'title']) + ->condition('uid', $author_uid) + ->condition('title', $db->escapeLike($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $node) { + $matches[$node->title . " [$node->nid]"] = SafeMarkup::check_plain($node->title); + } } - } - return new JsonResponse($matches); -} + return new JsonResponse($matches); + } } diff -u b/ajax_example/src/Form/AjaxExampleAddMore.php b/ajax_example/src/Form/AjaxExampleAddMore.php --- b/ajax_example/src/Form/AjaxExampleAddMore.php +++ b/ajax_example/src/Form/AjaxExampleAddMore.php @@ -20,7 +20,8 @@ } /** - * {@inheritdoc} + * This example shows a button to "add more" - add another textfield, and + * the corresponding "remove" button. */ public function buildForm(array $form, FormStateInterface $form_state, $no_js_use = FALSE) { $url = Url::fromUri('internal:/examples/ajax-example/add-more-nojs/'); @@ -30,7 +31,7 @@ $urltwo = Url::fromUri('internal:/examples/ajax_example/add-more'); $linktwo = Link::fromTextAndUrl($this->t('AJAX version'), $urltwo)->toString(); $form['description'] = [ - '#markup' =>t('This example shows an add-more and a remove-last button. The @link does it without page reloads; the @link2 is the same code but simulates a non-javascript environment, showing it with page reloads.', + '#markup' => t('This example shows an add-more and a remove-last button. The @link does it without page reloads; the @link2 is the same code but simulates a non-javascript environment, showing it with page reloads.', ['@link' => $linktwo, '@link2' => $link]), ]; @@ -62,8 +63,6 @@ '#type' => 'submit', '#value' => t('Add one more'), '#submit' => ['::ajax_example_add_more_add_one'], - // See the examples in ajax_example.module for more details on the - // properties of #ajax. '#ajax' => [ 'callback' => '::prompt', 'wrapper' => 'names-fieldset-wrapper', @@ -149,7 +148,6 @@ ); + // Sets a message to display to the user. drupal_set_message($output); } - - } diff -u b/ajax_example/src/Form/AjaxExampleAdvancedCommands.php b/ajax_example/src/Form/AjaxExampleAdvancedCommands.php --- b/ajax_example/src/Form/AjaxExampleAdvancedCommands.php +++ b/ajax_example/src/Form/AjaxExampleAdvancedCommands.php @@ -4,19 +4,29 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Ajax; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Ajax\HtmlCommand; use Drupal\Core\Ajax\AlertCommand; use Drupal\Core\Ajax\AppendCommand; use Drupal\Core\Ajax\BeforeCommand; +use Drupal\Core\Ajax\AddCssCommand; use Drupal\Core\Ajax\AfterCommand; use Drupal\Core\Ajax\ChangedCommand; use Drupal\Core\Ajax\DataCommand; use Drupal\Core\Ajax\PrependCommand; use Drupal\Core\Ajax\RemoveCommand; use Drupal\Core\Ajax\RestripeCommand; + +/** + * @file + * AJAX Commands examples. + * + * This demonstrates each of the + * new AJAX commands. This is consolidated into a dense page because + * it's advanced material and because it would spread itself all over creation + * otherwise. + */ /** * */ @@ -30,7 +40,7 @@ } /** - * {@inheritdoc} + * Form to display the AJAX Commands. */ public function buildForm(array $form, FormStateInterface $form_state) { $form = []; @@ -213,7 +223,7 @@ $form['restripe_command_example_fieldset']['restripe_num_rows'] = [ '#type' => 'select', '#default_value' => !empty($form_state->getValue('restripe_num_rows')) ? $form_state->getValue('restripe_num_rows') : 1, - '#options' => [1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10], + '#options' => [1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7, 8 => 8, 9 => 9, 10 => 10], '#ajax' => [ 'callback' => '::ajax_example_advanced_commands_restripe_num_rows', 'method' => 'replace', @@ -246,187 +256,184 @@ + /** + * Callback for 'after'. + * + * @see Drupal\Core\Ajax\AfterCommand; + */ + public function ajax_example_advanced_commands_after_callback($form, $form_state) { + $selector = '#after_div'; + $response = new AjaxResponse(); + $response->addCommand(new AfterCommand($selector, "New 'after'...")); + $response->addCommand(new ReplaceCommand("#after_status", "Updated after_command_example" . date('r') . "")); + return $response; + } + /** + * Callback for 'alert'. + * + * @see Drupal\Core\Ajax\AlertCommand; + */ + public function ajax_example_advanced_commands_alert_callback($form, $form_state) { + $response = new AjaxResponse(); + $response->addCommand(new AlertCommand("Alert requested at " . date('r'))); + return $response; + } -/** - * Callback for 'after'. - * - * @see ajax_command_after() - */ -public function ajax_example_advanced_commands_after_callback($form, $form_state) { - $selector = '#after_div'; - $response = new AjaxResponse(); - $response->addCommand( new AfterCommand($selector, "New 'after'...")); - $response->addCommand( new ReplaceCommand("#after_status", "Updated after_command_example".date('r')."")); - return $response; -} - -/** - * Callback for 'alert'. - * - * @see ajax_command_alert() - */ -public function ajax_example_advanced_commands_alert_callback($form, $form_state) { - $response = new AjaxResponse(); - $response->addCommand( new AlertCommand("Alert requested at " . date('r'))); - return $response; -} - -/** - * Callback for 'append'. - * - * @see ajax_command_append() - */ -public function ajax_example_advanced_commands_append_callback($form, $form_state) { - $selector = '#append_div'; - $response = new AjaxResponse(); - $response->addCommand( new AppendCommand($selector, "Stuff...")); - $response->addCommand( new ReplaceCommand("#append_status", "
Updated append_command_example " . date('r') . "
")); - return $response; -} - -/** - * Callback for 'before'. - * - * @see ajax_command_before() - */ -public function ajax_example_advanced_commands_before_callback($form, $form_state) { - $selector = '#before_div'; - $response = new AjaxResponse(); - $response->addCommand( new BeforeCommand($selector, "New 'before'...")); - $response->addCommand( new ReplaceCommand("#before_status", "
Updated before_command_example " . date('r') . "
")); + /** + * Callback for 'append'. + * + * @see Drupal\Core\Ajax\AppendCommand; + */ + public function ajax_example_advanced_commands_append_callback($form, $form_state) { + $selector = '#append_div'; + $response = new AjaxResponse(); + $response->addCommand(new AppendCommand($selector, "Stuff...")); + $response->addCommand(new ReplaceCommand("#append_status", "
Updated append_command_example " . date('r') . "
")); + return $response; + } - return $response; -} + /** + * Callback for 'before'. + * + * @see Drupal\Core\Ajax\BeforeCommand; + */ + public function ajax_example_advanced_commands_before_callback($form, $form_state) { + $selector = '#before_div'; + $response = new AjaxResponse(); + $response->addCommand(new BeforeCommand($selector, "New 'before'...")); + $response->addCommand(new ReplaceCommand("#before_status", "
Updated before_command_example " . date('r') . "
")); -/** - * Callback for 'changed'. - * - * @see ajax_command_changed() - */ -public function ajax_example_advanced_commands_changed_callback($form, $form_state) { - $checkbox_value = $form_state->getValue('changed_command_example'); - $checkbox_value_string = $checkbox_value ? "TRUE" : "FALSE"; - $response = new AjaxResponse(); - if ($checkbox_value) { - $response->addCommand( new ChangedCommand('#changed_div', '#changed_div_mark_this')); - } - else { - $response->addCommand(new ReplaceCommand('#changed_div', "
This div can be marked as changed or not.
")); + return $response; } - $response->addCommand( new ReplaceCommand("#changed_status", "
Updated changed_command_example to $checkbox_value_string: " . date('r') . "
")); + + /** + * Callback for 'changed'. + * + * @see Drupal\Core\Ajax\ChangedCommand; + */ + public function ajax_example_advanced_commands_changed_callback($form, $form_state) { + $checkbox_value = $form_state->getValue('changed_command_example'); + $checkbox_value_string = $checkbox_value ? "TRUE" : "FALSE"; + $response = new AjaxResponse(); + if ($checkbox_value) { + $response->addCommand(new ChangedCommand('#changed_div', '#changed_div_mark_this')); + } + else { + $response->addCommand(new ReplaceCommand('#changed_div', "
This div can be marked as changed or not.
")); + } + $response->addCommand(new ReplaceCommand("#changed_status", "
Updated changed_command_example to $checkbox_value_string: " . date('r') . "
")); return $response; -} + } -/** - * Callback for 'css'. - * - * @see ajax_command_css() - */ -public function ajax_example_advanced_commands_css_callback($form, $form_state) { - $selector = '#css_div'; - $color = $form_state->getValue('css_command_example'); - $response = new AjaxResponse(); - $response->addCommand(new CssCommand($selector, ['background-color' => $color])); - $response->addCommand(new ReplaceCommand("#css_status", "
Updated css_command_example to '{$color}' " . date('r') . "
")); - return $response; -} + /** + * Callback for 'css'. + * + * @see Drupal\Core\Ajax\AddCssCommand; + */ + public function ajax_example_advanced_commands_css_callback($form, $form_state) { + $selector = '#css_div'; + $color = $form_state->getValue('css_command_example'); + $response = new AjaxResponse(); + $response->addCommand(new AddCssCommand($selector, ['background-color' => $color])); + $response->addCommand(new ReplaceCommand("#css_status", "
Updated css_command_example to '{$color}' " . date('r') . "
")); + return $response; + } -/** - * Callback for 'data'. - * - * @see ajax_command_data() - */ -public function ajax_example_advanced_commands_data_callback($form, $form_state) { - $selector = '#data_div'; - $text = $form_state->getValue('data_command_example'); - list($key, $value) = preg_split('/=/', $text); - - $response = new AjaxResponse(); - $response->addCommand(new DataCommand($selector, $key, $value)); - $response->addCommand(new ReplaceCommand("#data_status", "
Updated data_command_example with key=$key, value=$value; " . date('r') . "
")); - return $response; -} + /** + * Callback for 'data'. + * + * @see Drupal\Core\Ajax\DataCommand + */ + public function ajax_example_advanced_commands_data_callback($form, $form_state) { + $selector = '#data_div'; + $text = $form_state->getValue('data_command_example'); + list($key, $value) = preg_split('/=/', $text); + + $response = new AjaxResponse(); + $response->addCommand(new DataCommand($selector, $key, $value)); + $response->addCommand(new ReplaceCommand("#data_status", "
Updated data_command_example with key=$key, value=$value; " . date('r') . "
")); + return $response; + } -/** - * Callback for 'html'. - * - * @see ajax_command_html() - */ -public function ajax_example_advanced_commands_html_callback($form, $form_state) { - $text = $form_state->getValue('html_command_example'); - $response = new AjaxResponse(); - $response->addCommand(new HtmlCommand('#html_div', $text)); - $response->addCommand(new ReplaceCommand("#html_status", "
Updated html_command_example with text=$text; " . date('r') . "
")); - return $response; -} + /** + * Callback for 'html'. + * + * @see Drupal\Core\Ajax\HtmlCommand + */ + public function ajax_example_advanced_commands_html_callback($form, $form_state) { + $text = $form_state->getValue('html_command_example'); + $response = new AjaxResponse(); + $response->addCommand(new HtmlCommand('#html_div', $text)); + $response->addCommand(new ReplaceCommand("#html_status", "
Updated html_command_example with text=$text; " . date('r') . "
")); + return $response; + } -/** - * Callback for 'prepend'. - * - * @see ajax_command_prepend() - */ -public function ajax_example_advanced_commands_prepend_callback($form, $form_state) { - $response = new AjaxResponse(); - $response->addCommand(new PrependCommand('#prepend_div', "Prepended Stuff...")); - $response->addCommand(new ReplaceCommand("#prepend_status", "
Updated prepend_command_example " . date('r') . "
")); + /** + * Callback for 'prepend'. + * + * @see Drupal\Core\Ajax\PrependCommand + */ + public function ajax_example_advanced_commands_prepend_callback($form, $form_state) { + $response = new AjaxResponse(); + $response->addCommand(new PrependCommand('#prepend_div', "Prepended Stuff...")); + $response->addCommand(new ReplaceCommand("#prepend_status", "
Updated prepend_command_example " . date('r') . "
")); - return $response; -} + return $response; + } -/** - * Callback for 'remove'. - * - * @see ajax_command_remove() - */ -public function ajax_example_advanced_commands_remove_callback($form, $form_state) { - $response = new AjaxResponse(); - $should_remove = $form_state->getValue('remove_command_example'); - $should_remove_string = $should_remove ? 'TRUE' : 'FALSE'; - if ($should_remove) { - $response->addCommand(new RemoveCommand('#remove_text')); + /** + * Callback for 'remove'. + * + * @see Drupal\Core\Ajax\RemoveCommand + */ + public function ajax_example_advanced_commands_remove_callback($form, $form_state) { + $response = new AjaxResponse(); + $should_remove = $form_state->getValue('remove_command_example'); + $should_remove_string = $should_remove ? 'TRUE' : 'FALSE'; + if ($should_remove) { + $response->addCommand(new RemoveCommand('#remove_text')); - } - else { - $response->addCommand(new HtmlCommand('#remove_div', "
text to be removed
")); } - $response->addCommand(new ReplaceCommand("#remove_status", "
Updated remove_command_example (value={$should_remove_string} " . date('r') . "
")); + else { + $response->addCommand(new HtmlCommand('#remove_div', "
text to be removed
")); + } + $response->addCommand(new ReplaceCommand("#remove_status", "
Updated remove_command_example (value={$should_remove_string} " . date('r') . "
")); return $response; -} + } -/** - * Callback for 'restripe'. - * - * Rebuilds the table with the selected number of rows. - */ -public function ajax_example_advanced_commands_restripe_num_rows($form, $form_state) { - $num_rows = $form_state->getValue('restripe_num_rows'); - $output = ""; - for ($i = 1; $i <= $num_rows; $i++) { - $output .= ""; + /** + * Callback for 'restripe'. + * + * Rebuilds the table with the selected number of rows. + */ + public function ajax_example_advanced_commands_restripe_num_rows($form, $form_state) { + $num_rows = $form_state->getValue('restripe_num_rows'); + $output = "
Row $i
"; + for ($i = 1; $i <= $num_rows; $i++) { + $output .= ""; + } + $output .= "
Row $i
"; + return $output; } - $output .= ""; - return $output; -} -/** - * Callback for 'restripe'. - * - * @see ajax_command_restripe() - */ -public function ajax_example_advanced_commands_restripe_callback($form, $form_state) { - $response = new AjaxResponse(); - $response->addCommand(new RestripeCommand('#restripe_table')); - $response->addCommand(new ReplaceCommand("#restripe_status", "
Restriped table " . date('r') . "
")); + /** + * Callback for 'restripe'. + * + * @see Drupal\Core\Ajax\RestripeCommand + */ + public function ajax_example_advanced_commands_restripe_callback($form, $form_state) { + $response = new AjaxResponse(); + $response->addCommand(new RestripeCommand('#restripe_table')); + $response->addCommand(new ReplaceCommand("#restripe_status", "
Restriped table " . date('r') . "
")); - return $response; + return $response; -} + } -/** - * - */ -public function submitForm(array &$form, FormStateInterface $form_state) { -} + /** + * + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + } } - diff -u b/ajax_example/src/Form/AjaxExampleAutocheckboxes.php b/ajax_example/src/Form/AjaxExampleAutocheckboxes.php --- b/ajax_example/src/Form/AjaxExampleAutocheckboxes.php +++ b/ajax_example/src/Form/AjaxExampleAutocheckboxes.php @@ -6,7 +6,7 @@ use Drupal\Core\Form\FormStateInterface; /** - * + * Generate a changing number of checkboxes. */ class AjaxExampleAutocheckboxes extends FormBase { @@ -76,8 +76,17 @@ } /** - * Handles switching the available regions based on the selected theme. - */ + * Callback for autocheckboxes. + * + * Callback element needs only select the portion of the form to be updated. + * Since #ajax['callback'] return can be HTML or a renderable array (or an + * array of commands), we can just return a piece of the form. + * See @link examples/ajax-example/advanced-commands for more details + * on AJAX framework commands. + * + * @return array + * Renderable array (the checkboxes fieldset) + */ public function prompt($form, FormStateInterface $form_state) { return $form['checkboxes_fieldset']; } diff -u b/ajax_example/src/Form/AjaxExampleAutocomplete.php b/ajax_example/src/Form/AjaxExampleAutocomplete.php --- b/ajax_example/src/Form/AjaxExampleAutocomplete.php +++ b/ajax_example/src/Form/AjaxExampleAutocomplete.php @@ -6,7 +6,7 @@ use Drupal\Core\Form\FormStateInterface; /** - * + * A simple autocomplete form which just looks up usernames in the user table. */ class AjaxExampleAutocomplete extends FormBase { @@ -36,7 +36,7 @@ } /** - * + * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { } diff -u b/ajax_example/src/Form/AjaxExampleAutocompleteAuthor.php b/ajax_example/src/Form/AjaxExampleAutocompleteAuthor.php --- b/ajax_example/src/Form/AjaxExampleAutocompleteAuthor.php +++ b/ajax_example/src/Form/AjaxExampleAutocompleteAuthor.php @@ -14,44 +14,44 @@ */ class AjaxExampleAutocompleteAuthor extends FormBase { - /** - * {@inheritdoc} - */ - public function getFormID() { - return 'ajax_example_autocompleteauthor'; - } +/** + * {@inheritdoc} + */ +public function getFormID() { + return 'ajax_example_autocompleteauthor'; +} - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - $form['intro'] = array( +/** + * {@inheritdoc} + */ +public function buildForm(array $form, FormStateInterface $form_state) { + $form['intro'] = [ '#markup' => '
' . t("This example uses a user autocomplete to dynamically change a node title autocomplete using #ajax. This is a way to get past the fact that we have no other way to provide context to the autocomplete function. It won't work very well unless you have a few users who have created some content that you can search for.") . '
', - ); + ]; - $form['author'] = array( + $form['author'] = [ '#type' => 'textfield', '#title' => t('Choose the username that authored nodes you are interested in'), - // Since we just need simple user lookup, we can use the simplest function - // of them all, user_autocomplete(). + // Since we just need simple user lookup, we can use the simplest function + // of them all, user_autocomplete(). '#autocomplete_path' => 'user/autocomplete', - '#ajax' => array( + '#ajax' => [ 'callback' => '::ajax_example_node_by_author_ajax_callback', 'wrapper' => 'autocomplete-by-node-ajax-replace', - ), - ); + ], + ]; // This form element with autocomplete will be replaced by #ajax whenever the // author changes, allowing the search to be limited by user. - $form['node'] = array( + $form['node'] = [ '#type' => 'textfield', '#title' => t('Choose a node by title'), '#prefix' => '
', '#suffix' => '
', '#disabled' => TRUE, - ); + ]; // When the author changes in the author field, we'll change the // autocomplete_path to match. @@ -60,26 +60,30 @@ if (!empty($author)) { $autocomplete_path = 'examples/ajax_example/node_by_author_autocomplete/' . $author->uid; $form['node']['#autocomplete_path'] = $autocomplete_path; - $form['node']['#title'] = t('Choose a node title authored by %author', array('%author' => $author->name)); + $form['node']['#title'] = t('Choose a node title authored by %author', ['%author' => $author->name]); $form['node']['#disabled'] = FALSE; } } - $form['actions'] = array( + $form['actions'] = [ '#type' => 'actions', - ); + ]; - $form['actions']['submit'] = array( + $form['actions']['submit'] = [ '#type' => 'submit', '#value' => t('Submit'), - ); + ]; return $form; - } - public function validateForm(array &$form, FormStateInterface $form_state) { +} + +/** + * {@inheritdoc} + */ +public function validateForm(array &$form, FormStateInterface $form_state) { $title = $form_state['values']['node']; $author = $form_state['values']['author']; - $matches = array(); + $matches = []; // We must have a valid user. $account = user_load_by_name($author); @@ -99,46 +103,54 @@ if (empty($node)) { - $form_state->setErrorByName($form['node'], t('Sorry, no node with nid %nid can be found', array('%nid' => $nid))); + $form_state->setErrorByName($form['node'], t('Sorry, no node with nid %nid can be found', ['%nid' => $nid])); return; } // BUT: Not everybody will have javascript turned on, or they might hit ESC - // and not use the autocomplete values offered. In that case, we can attempt - // to come up with a useful value. This is not absolutely necessary, and we - // *could* just emit a form_error() as below. Here we'll find the *first* - // matching title and assume that is adequate. - else { - $db = Database::getConnection(); - $nid = $db->select('node') - ->fields('node', array('nid')) - ->condition('uid', $account->uid) - ->condition('title', $db->escapeLike($title) . '%', 'LIKE') - ->range(0, 1) - ->execute() - ->fetchField(); - } + // and not use the autocomplete values offered. In that case, we can attempt + // to come up with a useful value. This is not absolutely necessary, and we + // *could* just emit a form_error() as below. Here we'll find the *first* + // matching title and assume that is adequate. + else { + $db = Database::getConnection(); + $nid = $db->select('node') + ->fields('node', ['nid']) + ->condition('uid', $account->uid) + ->condition('title', $db->escapeLike($title) . '%', 'LIKE') + ->range(0, 1) + ->execute() + ->fetchField(); + } - // Now, if we somehow found a nid, assign it to the node. If we failed, emit - // an error. - if (!empty($nid)) { - $form_state->setValue('node', $nid); - } - else { - $form_state->setErrorByName($form['node'], t('Sorry, no node starting with %title can be found', array('%title' => $title))); - } + // Now, if we somehow found a nid, assign it to the node. If we failed, emit + // an error. + if (!empty($nid)) { + $form_state->setValue('node', $nid); + } + else { + $form_state->setErrorByName($form['node'], t('Sorry, no node starting with %title can be found', ['%title' => $title])); + } } + /** + * AJAX callback for author form element. + */ public function ajax_example_node_by_author_ajax_callback($form, $form_state) { - return $form['node']; -} + return $form['node']; + } + + /** + * {@inheritdoc} + */ public function submitForm(array &$form, FormStateInterface $form_state) { $node = Node::load($form_state->getValue('node')); - $account = User::load($node->uid); - drupal_set_message(t('You found node %nid with title !title_link, authored by !user_link', - array( + $account = User::load($node->uid); + drupal_set_message(t('You found node %nid with title !title_link, authored by !user_link', + [ '%nid' => $node->nid, '!title_link' => l($node->title, 'node/' . $node->nid), - '!user_link' => theme('username', array('account' => $account)), - ) - )); + '!user_link' => theme('username', ['account' => $account]), + ] + )); } + } diff -u b/ajax_example/src/Form/AjaxExampleAutotextfields.php b/ajax_example/src/Form/AjaxExampleAutotextfields.php --- b/ajax_example/src/Form/AjaxExampleAutotextfields.php +++ b/ajax_example/src/Form/AjaxExampleAutotextfields.php @@ -6,7 +6,7 @@ use Drupal\Core\Form\FormStateInterface; /** - * + * Show/hide textfields based on AJAX-enabled checkbox clicks. */ class AjaxExampleAutotextfields extends FormBase { @@ -78,8 +78,12 @@ } /** - * Handles switching the available regions based on the selected theme. - */ + * Callback for autotextfields. + * + * Selects the piece of the form we want to use as replacement text and returns + * it as a form (renderable array). + * + */ public function prompt($form, FormStateInterface $form_state) { return $form['textfields']; } diff -u b/ajax_example/src/Form/AjaxExampleDependentDropdown.php b/ajax_example/src/Form/AjaxExampleDependentDropdown.php --- b/ajax_example/src/Form/AjaxExampleDependentDropdown.php +++ b/ajax_example/src/Form/AjaxExampleDependentDropdown.php @@ -6,7 +6,7 @@ use Drupal\Core\Form\FormStateInterface; /** - * + * Repopulate a dropdown based on form state. */ class AjaxExampleDependentDropdown extends FormBase { @@ -18,7 +18,13 @@ } /** - * {@inheritdoc} + * AJAX-based dropdown example form. + * + * A form with a dropdown whose options are dependent on a + * choice made in a previous dropdown. + * + * On changing the first dropdown, the options in the second + * are updated. */ public function buildForm(array $form, FormStateInterface $form_state) { $options_first = _ajax_example_get_first_dropdown_options(); @@ -70,19 +76,19 @@ * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - $trigger = (string)$form_state->getTriggeringElement()['#value']; - switch ($trigger) { + $trigger = (string) $form_state->getTriggeringElement()['#value']; + switch ($trigger) { case 'Submit': - // Submit: We're done. - drupal_set_message($this->t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', [ - '@first' => $form_state->getValue('dropdown_first'), - '@second' => $form_state->getValue('dropdown_second'), - ])); - return; - } - // 'Choose' or anything else will cause rebuild of the form and present - // it again. - $form_state->setRebuild(); + // Submit: We're done. + drupal_set_message($this->t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', [ + '@first' => $form_state->getValue('dropdown_first'), + '@second' => $form_state->getValue('dropdown_second'), + ])); + return; + } + // 'Choose' or anything else will cause rebuild of the form and present + // it again. + $form_state->setRebuild(); } /** diff -u b/ajax_example/src/Form/AjaxExampleDependentDropdownDegardes.php b/ajax_example/src/Form/AjaxExampleDependentDropdownDegardes.php --- b/ajax_example/src/Form/AjaxExampleDependentDropdownDegardes.php +++ b/ajax_example/src/Form/AjaxExampleDependentDropdownDegardes.php @@ -6,7 +6,24 @@ use Drupal\Core\Form\FormStateInterface; /** + *Dropdown form based on previous choices. * + * A form with a dropdown whose options are dependent on a choice made in a + * previous dropdown. + * + * On changing the first dropdown, the options in the second + * are updated. Gracefully degrades if no javascript. + * + * A bit of CSS and javascript is required. The CSS hides the "add more" button + * if javascript is not enabled. The Javascript snippet is really only used + * to enable us to present the form in degraded mode without forcing the user + * to turn off Javascript. Both of these are loaded by using the + * #attached FAPI property, so it is a good example of how to use that. + * + * The extra argument $no_js_use is here only to allow presentation of this + * form as if Javascript were not enabled. ajax_example_menu() provides two + * ways to call this form, one normal ($no_js_use = FALSE) and one simulating + * Javascript disabled ($no_js_use = TRUE). */ class AjaxExampleDependentDropdownDegardes extends FormBase { @@ -120,38 +137,15 @@ // case t('OK'): // Submit: We're done. $trigger = $form_state->getTriggeringElement()['#value']; - switch($trigger){ - case 'Choose': - $form_state->setRebuild(); - break; - case 'OK': - drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', ['@first' => $form_state->getValue('dropdown_first'), '@second' => $form_state->getValue('dropdown_second')])); - break; - - - } - - - - - /*if ($form_state->getValue('continue_to_second') == 'Choose') { - // print_r("Why is this");. - $form_state->setRebuild(); - if ($form_state->getValue('dropdown_second') == '') { - return; - } - + switch ($trigger) { + case 'Choose': + $form_state->setRebuild(); + break; + + case 'OK': + drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', ['@first' => $form_state->getValue('dropdown_first'), '@second' => $form_state->getValue('dropdown_second')])); + break; } - - if ($form_state->getValue('submit') == 'OK') { - drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', ['@first' => $form_state->getValue('dropdown_first'), '@second' => $form_state->getValue('dropdown_second')])); - return; - }*/ - // default: - // drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', ['@first' => $form_state->getValue('dropdown_first'), '@second' => $form_state->getValue('dropdown_second')])); - // return; - // 'Choose' or anything else will cause rebuild of the form and present - // it again. $form_state->setRebuild(); } diff -u b/ajax_example/src/Form/AjaxExampleDynamicSectionsDegardes.php b/ajax_example/src/Form/AjaxExampleDynamicSectionsDegardes.php --- b/ajax_example/src/Form/AjaxExampleDynamicSectionsDegardes.php +++ b/ajax_example/src/Form/AjaxExampleDynamicSectionsDegardes.php @@ -8,7 +8,17 @@ use Drupal\Core\Url; /** + * Dynamically-enabled form with graceful no-JS degradation. * + * Example of a form with portions dynamically enabled or disabled, but + * with graceful degradation in the case of no javascript. + * + * The idea here is that certain parts of the form don't need to be displayed + * unless a given option is selected, but then they should be displayed and + * configured. + * + * The third $no_js_use argument is strictly for demonstrating operation + * without javascript, without making the user/developer turn off javascript. */ class AjaxExampleDynamicSectionsDegardes extends FormBase { @@ -20,7 +30,7 @@ } /** - * {@inheritdoc} + * */ public function buildForm(array $form, FormStateInterface $form_state, $no_js_use = FALSE) { $url = Url::fromUri('internal:/examples/ajax-example/dynamic-sections-no_js'); @@ -29,7 +39,9 @@ // Prepare link for multiple arguments. $urltwo = Url::fromUri('internal:/examples/ajax-example/dynamic-sections'); $linktwo = Link::fromTextAndUrl($this->t('examples/ajax-example/dynamic-sections'), $urltwo)->toString(); - + // Attach the CSS and JS we need to show this with and without javascript. + // Without javascript we need an extra "Choose" button, and this is + // hidden when we have javascript enabled. $form['#attached']['library'][] = 'ajax_example/ajax_eample.dropdown'; $form['description'] = [ @@ -99,11 +111,11 @@ '#type' => 'radios', '#title' => t('Who was the first president of the United States'), '#options' => [ - 'George Bush' => 'George Bush', - 'Adam McGuire' => 'Adam McGuire', - 'Abraham Lincoln' =>'Abraham Lincoln', - 'George Washington' =>'George Washington', - ], + 'George Bush' => 'George Bush', + 'Adam McGuire' => 'Adam McGuire', + 'Abraham Lincoln' => 'Abraham Lincoln', + 'George Washington' => 'George Washington', + ], ]; break; @@ -113,8 +125,8 @@ '#type' => 'radios', '#title' => $this->t('Was George Washington the first president of the United States?'), '#options' => [ - 'George Washington' => 'True', - 0 => 'False', + 'George Washington' => 'True', + 0 => 'False', ], '#description' => $this->t('Click "True" if you think George Washington was the first president of the United States.'), ]; @@ -138,42 +150,40 @@ } /** - * Submit function for ajax_example_dynamic_sections(). + * Final submit handler. + * + * Reports what values were finally set. */ public function submitForm(array &$form, FormStateInterface $form_state) { - // This is only executed when a button is pressed, not when the AJAXified + // This is only executed when a button is pressed, not when the AJAXfield // select is changed. // Now handle the case of the next, previous, and submit buttons. // Only submit will result in actual submission, all others rebuild. - if($form_state->getValue('question_type_submit') == 'Choose'){ - //print_r("Why is this"); - $form_state->setValue('question_type_select', $form_state->getUserInput()['question_type_select']); - $form_state->setRebuild(); -} - - if($form_state->getValue('submit') == 'Submit your answer'){ - $form_state->setRebuild(FALSE); - - $answer = $form_state->getValue('question'); - print_r($answers); - // Special handling for the checkbox. - if ($answer == 1 && $form['questions_fieldset']['question']['#type'] == 'checkbox') { - $answer = $form['questions_fieldset']['question']['#title']; - } - if ($answer == $this->t('George Washington')) { - drupal_set_message($this->t('You got the right answer: @answer', ['@answer' => $answer])); - } - else { - drupal_set_message($this->t('Sorry, your answer (@answer) is wrong', ['@answer' => $answer])); - } - return; + if ($form_state->getValue('question_type_submit') == 'Choose') { + $form_state->setValue('question_type_select', $form_state->getUserInput()['question_type_select']); + $form_state->setRebuild(); + } + if ($form_state->getValue('submit') == 'Submit your answer') { + $form_state->setRebuild(FALSE); + $answer = $form_state->getValue('question'); + print_r($answers); + // Special handling for the checkbox. + if ($answer == 1 && $form['questions_fieldset']['question']['#type'] == 'checkbox') { + $answer = $form['questions_fieldset']['question']['#title']; } - + if ($answer == $this->t('George Washington')) { + drupal_set_message($this->t('You got the right answer: @answer', ['@answer' => $answer])); + } + else { + drupal_set_message($this->t('Sorry, your answer (@answer) is wrong', ['@answer' => $answer])); + } + return; + } + // Sets the form to be rebuilt after processing. $form_state->setRebuild(); } - /** * Callback for the select element. * diff -u b/ajax_example/src/Form/AjaxExampleNodeFormAlter.php b/ajax_example/src/Form/AjaxExampleNodeFormAlter.php --- b/ajax_example/src/Form/AjaxExampleNodeFormAlter.php +++ b/ajax_example/src/Form/AjaxExampleNodeFormAlter.php @@ -4,15 +4,22 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Database\Database; -use Drupal\Core\Database\Query\Condition; -use Drupal\node\Entity\Node; +use Drupal\Core\Database\Connection; /** * */ class AjaxExampleNodeFormAlter extends FormBase { + protected $connection; + + /** + * + */ + public function __construct(Connection $connection) { + $this->connection = $connection; + } + /** * {@inheritdoc} */ @@ -27,119 +34,129 @@ $node = $form['#node']; - $form['ajax_example_1'] = array( - '#type' => 'checkbox', - '#title' => t('AJAX Example 1'), - '#description' => t('Enable to show second field.'), - '#default_value' => $node->ajax_example['example_1'], - '#ajax' => array( - 'callback' => '::ajax_example_form_node_callback', - 'wrapper' => 'ajax-example-form-node', - 'effect' => 'fade', - ), - ); - $form['container'] = array( - '#prefix' => '
', - '#suffix' => '
', - ); - - // If the state values exist and 'ajax_example_1' state value is 1 or - // if the state values don't exist and 'example1' variable is 1 then - // display the ajax_example_2 field. - if (!empty($form_state->getValue('ajax_example_1')) && $form_state->getValue('ajax_example_1') == 1 + $form['ajax_example_1'] = [ + '#type' => 'checkbox', + '#title' => t('AJAX Example 1'), + '#description' => t('Enable to show second field.'), + '#default_value' => $node->ajax_example['example_1'], + '#ajax' => [ + 'callback' => '::ajax_example_form_node_callback', + 'wrapper' => 'ajax-example-form-node', + 'effect' => 'fade', + ], + ]; + $form['container'] = [ + '#prefix' => '
', + '#suffix' => '
', + ]; + + // If the state values exist and 'ajax_example_1' state value is 1 or + // if the state values don't exist and 'example1' variable is 1 then + // display the ajax_example_2 field. + if (!empty($form_state->getValue('ajax_example_1')) && $form_state->getValue('ajax_example_1') == 1 || empty($form_state->getValue()) && $node->ajax_example['example_1']) { - $form['container']['ajax_example_2'] = array( - '#type' => 'textfield', - '#title' => t('AJAX Example 2'), - '#description' => t('AJAX Example 2'), - '#default_value' => empty($form_state->getValue('ajax_example_2')) ? $node->ajax_example['example_2'] : $form_state->getValue('ajax_example_2'), - ); + $form['container']['ajax_example_2'] = [ + '#type' => 'textfield', + '#title' => t('AJAX Example 2'), + '#description' => t('AJAX Example 2'), + '#default_value' => empty($form_state->getValue('ajax_example_2')) ? $node->ajax_example['example_2'] : $form_state->getValue('ajax_example_2'), + ]; + } } -} - //callback of ajax - function ajax_example_form_node_callback($form, $form_state) { - return $form['container']; -} - /** + + /** + * Callback of ajax. + */ + public function ajax_example_form_node_callback($form, $form_state) { + return $form['container']; + } + + /** * */ public function submitForm(array &$form, FormStateInterface $form_state) { $values = $form_state->getValue(); - // Move the new data into the node object. - $node->ajax_example['example_1'] = $values['ajax_example_1']; - // Depending on the state of ajax_example_1; it may not exist. - $node->ajax_example['example_2'] = isset($values['ajax_example_2']) ? $values['ajax_example_2'] : ''; + // Move the new data into the node object. + $node->ajax_example['example_1'] = $values['ajax_example_1']; + // Depending on the state of ajax_example_1; it may not exist. + $node->ajax_example['example_2'] = isset($values['ajax_example_2']) ? $values['ajax_example_2'] : ''; } + /** + * + */ public function ajax_example_node_prepare($node) { - if (empty($node->ajax_example)) { - // Set default values, since this only runs when adding a new node. - $node->ajax_example['example_1'] = 0; - $node->ajax_example['example_2'] = ''; + if (empty($node->ajax_example)) { + // Set default values, since this only runs when adding a new node. + $node->ajax_example['example_1'] = 0; + $node->ajax_example['example_2'] = ''; + } } -} -/** - * Implements hook_node_load(). - * - * @see ajax_example_form_node_form_alter() - */ -public function ajax_example_node_load($nodes, $types) { - $result = db_query('SELECT * FROM {ajax_example_node_form_alter} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)))->fetchAllAssoc('nid'); + /** + * Implements hook_node_load(). + * + * @see ajax_example_form_node_form_alter() + */ + public function ajax_example_node_load($nodes, $types) { + $result = $this->connection->query('SELECT * FROM {ajax_example_node_form_alter} WHERE nid IN(:nids)', [':nids' => array_keys($nodes)])->fetchAllAssoc('nid'); - foreach ($nodes as &$node) { - $node->ajax_example['example_1'] + foreach ($nodes as &$node) { + $node->ajax_example['example_1'] = isset($result[$node->nid]->example_1) ? $result[$node->nid]->example_1 : 0; - $node->ajax_example['example_2'] + $node->ajax_example['example_2'] = isset($result[$node->nid]->example_2) ? $result[$node->nid]->example_2 : ''; + } } -} -/** - * Implements hook_node_insert(). - * - * @see ajax_example_form_node_form_alter() - */ -public function ajax_example_node_insert($node) { - if (isset($node->ajax_example)) { - db_insert('ajax_example_node_form_alter') - ->fields(array( - 'nid' => $node->nid, - 'example_1' => $node->ajax_example['example_1'], - 'example_2' => $node->ajax_example['example_2'], - )) - ->execute(); + /** + * Implements hook_node_insert(). + * + * @see ajax_example_form_node_form_alter() + */ + public function ajax_example_node_insert($node) { + if (isset($node->ajax_example)) { + $this->connection->insert('ajax_example_node_form_alter') + ->fields([ + 'nid' => $node->nid, + 'example_1' => $node->ajax_example['example_1'], + 'example_2' => $node->ajax_example['example_2'], + ]) + ->execute(); + } } -} -/** - * Implements hook_node_update(). - * @see ajax_example_form_node_form_alter() - */ -public function ajax_example_node_update($node) { - if (db_select('ajax_example_node_form_alter', 'a')->fields('a')->condition('nid', $node->nid, '=')->execute()->fetchAssoc()) { - db_update('ajax_example_node_form_alter') - ->fields(array( - 'example_1' => $node->ajax_example['example_1'], - 'example_2' => $node->ajax_example['example_2'], - )) + /** + * Implements hook_node_update(). + * + * @see ajax_example_form_node_form_alter() + */ + public function ajax_example_node_update($node) { + if ($this->connection->select('ajax_example_node_form_alter', 'a')->fields('a')->condition('nid', $node->nid, '=')->execute()->fetchAssoc()) { + $this->connection->update('ajax_example_node_form_alter') + ->fields([ + 'example_1' => $node->ajax_example['example_1'], + 'example_2' => $node->ajax_example['example_2'], + ]) + ->condition('nid', $node->nid) + ->execute(); + } + else { + // Cleaner than doing it again. + ajax_example_node_insert($node); + } + } + + /** + * Implements hook_node_delete(). + * + * @see ajax_example_form_node_form_alter() + */ + public function ajax_example_node_delete($node) { + $this->connection->delete('ajax_example_node_form_alter') ->condition('nid', $node->nid) ->execute(); } - else { - // Cleaner than doing it again. - ajax_example_node_insert($node); - } -} -/** - * Implements hook_node_delete(). - * @see ajax_example_form_node_form_alter() - */ -public function ajax_example_node_delete($node) { - db_delete('ajax_example_node_form_alter') - ->condition('nid', $node->nid) - ->execute(); -} } diff -u b/ajax_example/src/Form/AjaxExampleProgressBar.php b/ajax_example/src/Form/AjaxExampleProgressBar.php --- b/ajax_example/src/Form/AjaxExampleProgressBar.php +++ b/ajax_example/src/Form/AjaxExampleProgressBar.php @@ -8,7 +8,7 @@ use Drupal\Core\Url; /** - * + *Progress bar example. */ class AjaxExampleProgressBar extends FormBase { @@ -20,7 +20,7 @@ } /** - * {@inheritdoc} + * Build a landing-page form for the progress bar example. */ public function buildForm(array $form, FormStateInterface $form_state) { $form['time'] = \Drupal::time()->getRequestTime(); diff -u b/ajax_example/src/Form/AjaxExampleSubmitDriven.php b/ajax_example/src/Form/AjaxExampleSubmitDriven.php --- b/ajax_example/src/Form/AjaxExampleSubmitDriven.php +++ b/ajax_example/src/Form/AjaxExampleSubmitDriven.php @@ -6,7 +6,7 @@ use Drupal\Core\Form\FormStateInterface; /** - * + * Submit a form without a page reload. */ class AjaxExampleSubmitDriven extends FormBase { diff -u b/ajax_example/src/Form/AjaxExampleUniquecomplete.php b/ajax_example/src/Form/AjaxExampleUniquecomplete.php --- b/ajax_example/src/Form/AjaxExampleUniquecomplete.php +++ b/ajax_example/src/Form/AjaxExampleUniquecomplete.php @@ -9,7 +9,11 @@ use Drupal\node\Entity\Node; /** + *An autocomplete form to look up nodes by title. * + * An autocomplete form which looks up nodes by title in the node table, + * but must keep track of the nid, because titles are certainly not guaranteed + * to be unique. */ class AjaxExampleUniquecomplete extends FormBase { @@ -48,7 +52,7 @@ } /** - * + * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { $title = $form_state->getValue('node'); @@ -94,7 +98,7 @@ } /** - * + * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $node = Node::load($form_state->getValue(['values', 'node'])); diff -u b/ajax_example/src/Form/AjaxExampleWizard.php b/ajax_example/src/Form/AjaxExampleWizard.php --- b/ajax_example/src/Form/AjaxExampleWizard.php +++ b/ajax_example/src/Form/AjaxExampleWizard.php @@ -2,13 +2,11 @@ namespace Drupal\ajax_example\Form; -use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; use Drupal\Core\Link; use Drupal\Core\Ajax\AjaxResponse; -use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Ajax\HtmlCommand; /** @@ -36,8 +34,8 @@ $linktwo = Link::fromTextAndUrl($this->t('examples/ajax-example/wizard'), $urltwo) ->toString(); -// $form['#prefix'] = '
'; -// $form['#suffix'] = '
'; + // $form['#prefix'] = '
'; + // $form['#suffix'] = '
'; // We want to deal with hierarchical form values. $form['#tree'] = TRUE; $form['description'] = [ @@ -78,7 +76,6 @@ ]; } - // This simply allows us to demonstrate no-javascript use without // actually turning off javascript in the browser. Removing the #ajax // element turns off AJAX behaviors on that element and as a result only in patch2: unchanged: --- /dev/null +++ b/ajax_example/src/Form/AjaxExampleWizard_mine_with_error.php @@ -0,0 +1,203 @@ +t('examples/ajax-example/wizard-nojs'), $url)->toString(); + + // Prepare link for multiple arguments. + $urltwo = Url::fromUri('internal:/examples/ajax-example/wizard'); + $linktwo = Link::fromTextAndUrl($this->t('examples/ajax-example/wizard'), $urltwo)->toString(); + + $form['#prefix'] = '
'; + $form['#suffix'] = '
'; + // We want to deal with hierarchical form values. + $form['#tree'] = TRUE; + $form['description'] = [ + '#markup' =>t('This example is a step-by-step wizard. The @link does it without page reloads; the @link1 is the same code but simulates a non-javascript environment, showing it with page reloads.', ['@link' => $linktwo, '@link1' => $link]), + ]; + + // $form_state['storage'] has no specific drupal meaning, but it is + // traditional to keep variables for multistep forms there. + //$step['step'] = !empty($form_state->getStorage()) ? $form_state->getStorage() : 1 ; + + //$form_state->setStorage($step); + $form['step'] = [ + '#type' => 'hidden', + '#value' => !empty($form_state->getValue('step')) ? $form_state->getValue('step') : 1, + ]; + if(empty($form_state->getValue('step'))) + $form_state->setValue('step', 1); + $step_name = $form_state->getValue('step'); + switch ($step_name) { + case 1: + $form['step1'] = [ + '#type' => 'fieldset', + '#title' => t('Step 1: Personal details'), + ]; + $form['step1']['name'] = [ + '#type' => 'textfield', + '#title' => t('Your name'), + '#default_value' => empty($form_state->getValue(['step1', 'name']) ? '' : $form_state->getValue(['step1', 'name'])), + '#required' => TRUE, + ]; + break; + + case 2: + $form['step2'] = [ + '#type' => 'fieldset', + '#title' => t('Step 2: Street address info'), + ]; + $form['step2']['address'] = [ + '#type' => 'textfield', + '#title' => t('Your street address'), + '#default_value' => empty($form_state->getValue(['step1', 'address']) ? '' : $form_state->getValue(['step1', 'address'])), + '#required' => TRUE, + ]; + break; + + case 3: + $form['step3'] = [ + '#type' => 'fieldset', + '#title' => t('Step 3: City info'), + ]; + $form['step3']['city'] = [ + '#type' => 'textfield', + '#title' => t('Your city'), + '#default_value' => empty($form_state->getValue(['step1', 'city']) ? '' : $form_state->getValue(['step1', 'city'])), + '#required' => TRUE, + ]; + break; + } + if ($step_name == 3) { + $form['submit'] = [ + '#type' => 'submit', + '#value' => t("Submit your information"), + ]; + } + if ($step_name < 3) { + $form['next'] = [ + '#type' => 'submit', + '#value' => t('Next step'), + '#ajax' => [ + 'wrapper' => 'wizard-form-wrapper', + 'callback' => '::functionajax', + ], + ]; + } + if ($step_name > 1) { + $form['prev'] = [ + '#type' => 'submit', + '#value' => t("Previous step"), + + // Since all info will be discarded, don't validate on 'prev'. + '#limit_validation_errors' => [], + // #submit is required to use #limit_validation_errors. + '#submit' => ['::submitForm'], + '#ajax' => [ + 'wrapper' => 'wizard-form-wrapper', + 'callback' => '::fuctionajax', + ], + ]; + } + + // This simply allows us to demonstrate no-javascript use without + // actually turning off javascript in the browser. Removing the #ajax + // element turns off AJAX behaviors on that element and as a result + // ajax.js doesn't get loaded. + // For demonstration only! You don't need this. + if ($no_js_use) { + // Remove the #ajax from the above, so ajax.js won't be loaded. + // For demonstration only. + unset($form['next']['#ajax']); + unset($form['prev']['#ajax']); + } + + return $form; + } + + /** + * Wizard callback function. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form. + * + * @return array + * Form array. + */ + public function functionajax($form, $form_state) { + if ($form_state->getTriggeringElement()['#value'] == $this->t('Next step')) { + $inc = $form_state->getValue('step'); + $inc++; + $form_state->setValue('step', $inc); + } + elseif ($form_state->getTriggeringElement()['#value']->__toString() == $this->t('Previous step')) { + $dec = $form_state->getValue('step'); + $dec--; + $form_state->setValue('step', $dec); + } + return $form; + } + + /** + * Submit function for ajax_example_wizard. + * + * In AJAX this is only submitted when the final submit button is clicked, + * but in the non-javascript situation, it is submitted with every + * button click. + */ + + + // Save away the current information. + +public function submitForm(array &$form, FormStateInterface $form_state) { + /*if ($form_state->getTriggeringElement()['#value'] == $this->t('Next step')) { + $inc = $form_state->getValue('step'); + $inc++; + $form_state->setValue('step', $inc); + } + elseif ($form_state->getTriggeringElement()['#value']->__toString() == $this->t('Previous step')) { + $dec = $form_state->getValue('step'); + $dec--; + $form_state->setValue('step', $dec); + }*/ + if ($form_state->getTriggeringElement()['#value'] == $this->t('Submit your information')) { + $value_message = $this->t('Your information has been submitted:') . ' '; + foreach ($form_state->getValue('value') as $step => $values) { + $value_message .= "$step: "; + foreach ($values as $key => $value) { + $value_message .= "$key=$value, "; + } + } + drupal_set_message($value_message); + $form_state->setRebuild(FALSE); + // Redirect to #action, else return. + return; + } + + } + +}