diff --git a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php index d986a97d0574c77344722e1eaaa211c7720317d7..8384c975895ae86671913705048336bc19556296 100644 --- a/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php +++ b/core/modules/views/src/Plugin/views/exposed_form/ExposedFormPluginBase.php @@ -246,6 +246,31 @@ public function exposedFormAlter(&$form, FormStateInterface $form_state) { } } + // Check if there are exposed filters for this view + $exposed_filters = []; + $exposed_required_filters = []; + foreach ($this->view->filter as $id => $handler) { + if ($handler->canExpose() && $handler->isExposed() && !empty($handler->options['expose']['identifier'])) { + if ($handler->options['expose']['required'] && $handler->options['plugin_id'] !== 'boolean') { + $exposed_required_filters[$handler->options['expose']['identifier']] = $id; + } + $exposed_filters[$handler->options['expose']['identifier']] = $id; + } + } + + // If any required exposed filters loop through them to see if they + // have any input. If not don't auto process the form to prevent validation. + if (!empty($exposed_required_filters)) { + $form_values = $form_state->getUserInput(); + foreach ($exposed_required_filters as $key => $required_filter) { + if (!$form_values || empty($form_values[$key])) { + $form_state->setAlwaysProcess(FALSE); + break; + } + } + } + $all_exposed = array_merge($exposed_sorts, $exposed_filters); + if (!empty($this->options['reset_button'])) { $form['actions']['reset'] = [ '#value' => $this->options['reset_button_label'], @@ -253,15 +278,6 @@ public function exposedFormAlter(&$form, FormStateInterface $form_state) { '#weight' => 10, ]; - // Get an array of exposed filters, keyed by identifier option. - $exposed_filters = []; - foreach ($this->view->filter as $id => $handler) { - if ($handler->canExpose() && $handler->isExposed() && !empty($handler->options['expose']['identifier'])) { - $exposed_filters[$handler->options['expose']['identifier']] = $id; - } - } - $all_exposed = array_merge($exposed_sorts, $exposed_filters); - // Set the access to FALSE if there is no exposed input. if (!array_intersect_key($all_exposed, $this->view->getExposedInput())) { $form['actions']['reset']['#access'] = FALSE; diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_form_required_text_filter.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_form_required_text_filter.yml new file mode 100644 index 0000000000000000000000000000000000000000..dc1cf42793fdb82cc4d4124d26f29427930d51c9 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_exposed_form_required_text_filter.yml @@ -0,0 +1,90 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - node.type.article + - node.type.page + module: + - node +id: test_exposed_form_required_text_filter +label: '' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + id: default + display_title: Default + display_plugin: default + position: 0 + display_options: + pager: + type: full + exposed_form: + type: input_required + options: + submit_button: Apply + reset_button: true + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + text_input_required: 'Select any filter and click on Apply to see results' + text_input_required_format: basic_html + access: + type: none + cache: + type: tag + filters: + title: + id: title + table: node_field_data + field: title + relationship: none + group_type: group + admin_label: '' + entity_type: node + entity_field: title + plugin_id: string + operator: '=' + value: '' + group: 1 + exposed: true + expose: + operator_id: title_op + label: Title + description: '' + use_operator: false + operator: title_op + operator_limit_selection: false + operator_list: { } + identifier: title + required: true + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + content_editor: '0' + administrator: '0' + placeholder: '' + is_grouped: false + style: + type: default + row: + type: 'entity:node' + query: + type: views_query + options: + query_comment: '' + page_1: + id: page_1 + display_title: Page + display_plugin: page + position: 0 + display_options: + path: test_exposed_form_required_text_filter diff --git a/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php b/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php index b653c352795cb133ae0f32573060d60f04ab1ebd..6a28d030995cf52c774d4b2087cb43c8841bb500 100644 --- a/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php +++ b/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php @@ -6,9 +6,9 @@ use Drupal\entity_test\Entity\EntityTest; use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; use Drupal\Tests\views\Functional\ViewTestBase; +use Drupal\views\Entity\View; use Drupal\views\ViewExecutable; use Drupal\views\Views; -use Drupal\views\Entity\View; /** * Tests exposed forms functionality. @@ -24,7 +24,7 @@ class ExposedFormTest extends ViewTestBase { * * @var array */ - public static $testViews = ['test_exposed_form_buttons', 'test_exposed_block', 'test_exposed_form_sort_items_per_page', 'test_exposed_form_pager', 'test_remember_selected']; + public static $testViews = ['test_exposed_form_buttons', 'test_exposed_form_required_text_filter', 'test_exposed_block', 'test_exposed_form_sort_items_per_page', 'test_exposed_form_pager', 'test_remember_selected']; /** * Modules to enable. @@ -344,6 +344,23 @@ public function testTextInputRequired() { $this->assertSession()->pageTextNotContains($on_demand_text); } + /** + * Tests the input required exposed form type with a text type filter. + */ + public function testInputRequiredTextFilter() { + $this->drupalGet('test_exposed_form_required_text_filter'); + $this->assertSession()->statusCodeEquals(200); + $this->helperButtonHasLabel('edit-submit-test-exposed-form-required-text-filter', 'Apply'); + + // Ensure that no results are displayed by default when no input is + // provided. + $this->assertSession()->elementNotExists('xpath', "//div[contains(@class, 'views-row')]"); + + // Ensure that no error element is shown. + $this->assertSession()->elementNotExists('css', '.messages--error'); + $this->assertFalse($this->getSession()->getPage()->findField('title')->hasClass('error')); + } + /** * Tests exposed forms with exposed sort and items per page. */