1

Is there a clean way to alter a View exposed filter field, but only on page reload and not each time you submit the exposed filters form ?


Example

I have a View with exposed filters. When a user is loading this View, I want to change the value of an exposed filter field, depending on a cookie value.

I've managed to make it work with the hook_form_views_exposed_form_alter function.

function HOOK_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    if ($form['#id'] == 'views-exposed-form-MY-VIEW') {
        $cookies = \Drupal::request()->cookies->all();
        if (isset($cookies['MY_COOKIE'])) {
            $form['MY_FIELD']['#value'] = $cookies['MY_COOKIE'];
        }
    }
}

Problem is : if the user manually change the exposed filter and submit the form, the value is getting back to the first one because the hook_form_alter is getting called again.

Here is a video : https://imgur.com/EmVha6e


Poor solution

I've found a solution, but it doesn't looks like a good one. I've found out that when the hook_form_alter is getting called by a submit, there is a new entry ('a' => '') in the UserInput array that you can find by calling $form_state->getUserInput().

First load :

[
    'MY_FIELD' => 'All',
    '...' => '...'
]

After submit :

[
    'MY_FIELD' => 'New value',
    'a' => '',
    '...' => '...'
]

So now I can use the following to change the field value only on the page load :

if (isset($cookies['MY_COOKIE']) && !array_key_exists('a', $form_state->getUserInput())) {
    $form['MY_FIELD']['#value'] = $cookies['MY_COOKIE'];
}

But I'm not even sure it is fully functional, is there a better way to do it ?


Clean solution

Thank's to @NoSssweat, here's a cleaner solution :

function MODULE_views_pre_build(ViewExecutable $view) {
    $request = \Drupal::request();
    $is_ajax = $request->isXmlHttpRequest();
    if (!$is_ajax) {
        $cookies = \Drupal::request()->cookies->all();
        if (isset($cookies['MY_COOKIE'])) {
            $view->setExposedInput(['MY_FIELD' => [$cookies['MY_COOKIE'] => $cookies['MY_COOKIE']]]);
        }
    }
}
  • @NoSssweat The hook_views_pre_build is working but I've the same problem : each time I submit the exposed filter form, the field value is getting back to the previous value. – Corentin Le Fur Nov 18 '19 at 12:56
  • @NoSssweat Just added a video link to show you : imgur.com/EmVha6e – Corentin Le Fur Nov 18 '19 at 13:02
1

Just added a video link to show you : imgur.com/EmVha6e

You just need to add a conditional to check if it's not ajax

   $request = \Drupal::request();
   $is_ajax = $request->isXmlHttpRequest();
   if (!$is_ajax) {
     // code that sets the filter initial value
   }

Credit: How can I detect AJAX request inside Drupal?

  • That's it ! I've finally used the hook_views_pre_build function. With the request check, it seems the best solution, a lot cleaner than the one I was using. Thank you ! – Corentin Le Fur Nov 19 '19 at 8:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.