One Exposed Filter to Feed Two Views Displays

Submitted by allan on Sat, 12/28/2013 - 21:10

Recently I had the pleasure of working on a project that required some finesse when it came to working with a search powered by Views. The use-case was this:

As a User, I would like to be able to search for doctors near me from the same search form as a normal search so that making a proximity search would be easy and intuitive.

Alright, I already had First Name, Last Name, Clinical Specialty, and Gender. All I need now is Zip right?

It all started by First creating two view displays. I had one show all the information about the doctor and the other show the exact same information, but added the proximity in Miles per the [Basic Dealer Locator, User Locator, Store Locator proximity search]https://drupal.org/node/1944648) Tutorial.

Set up both displays to have the exact same exposed forms minus the bit you are adding to one or the other via the form alter. Alternatively, if there is no differences you need to make between the two view display exposed filters, don't worry where I say "form alter". You won't be doing any of that.

Regular

Regular

Proximity

Proximity

Next, I had a pane showing the exposed filter. I modified the exposed filter using the Drupal Bits Tutorial on altering an exposed form. There is a trick to it where the elements of a Views Exposed Form do not render like a normal Drupal form does. This requires you to do a little tinkering with a special #info array key that isn't normally in a Drupal form.

Lastly, Now the idea is that you have two displays that are almost exactly alike and two exposed forms that you can post to, but only one of which you will actually use. What I then do is add code that does something like this:

function alter_forms_form_alter(&$form, &$form_state, $form_id)
{
  if ($form_id == 'views_exposed_form' && (arg(1) ==  183 || arg(1) == 6074)) {
  // Throw Zip Code into the mix

    // Taken from the Geocode Options Exposed Filter.
    //  6371 Kilometers
    //  6371000 Meters
    //  3959 Miles
    //  6975175 Yards
    //  20925525 Feet
    //  3444 Nautical Miles
    $form['zipcode'] = array(
      '#type' => 'geofield_proximity',
      '#default_value' => array(
        'distance' => 25,
        'unit' => 3959, // Miles
        'origin' => '',
      ),
      '#origin_options' => array(
        '#attributes' => array(
          'class' => array(
            'geofield-proximity-origin',
          ),
        ),
      ),
    );

    // You have to add your field into #info, otherwise the field will show up
    // next to the submit button.
    $insert = array(
      'filter-zipcode' => array(
        'value' => 'zipcode',
        'label' => 'Zip',
        'description' => '',
      )
    );
    array_splice($form['#info'],2,0,$insert);
  }
}
function alter_forms_views_pre_view(&$view) {
  if ($view->name == 'doctor_finder') {
    $zipcode = !empty($_GET['zipcode']['origin']) ? trim($_GET['zipcode']['origin']) : '';
    if ($view->current_display == 'panel_pane_1') {
      if (!empty($zipcode)) {
        $view->set_display('panel_pane_2');
      }
    }
    if ($view->current_display == 'panel_pane_2') {
      if (empty($zipcode)) {
        $view->set_display('panel_pane_1');
      }
    }
  }
}

Note: An alternative approach to all of this is to check to see when zipcode[origin] was empty and switch to display pane_panel_1 and use the built out form built by the exposed filter of pane_panel_2 instead. But I took the harder approach of doing the form alter and what not... but I really only needed the zipcode[origin] field... And it wasn't till after I found out that I was using the wrong hook that I could actually make the other two hidden still.

The trick here was actually to find out exactly what hook you could set the display at that would allow views to take over all the rest of building the view. This includes things like setting up the right handlers, and applying the right exposed filters and what not. hook_views_pre_view was what I needed.

Final Thoughts

In the end, changing the display proved to take a lot of exploration to figure out, but the results are an excellent user-friendly form that will allow me to either do proximity search or regular search based on the values passed into the exposed filter form. It's only right that I pass this forward.

Resources

I'll add more as I remember where I found scraps. There was one blog in particular that lead me down nearly the right path, but I can't find it in my browser history and my Googlefu is failing me.