Drupal

How to Pass Multiple Values through an Exposed Filter in Drupal Views

I regularly work with Views and recently I have had a few odd needs. One of which was when a user selects an item, that item then disappears from the view. The view has exposed filters with AJAX turned on. Since I don’t know how many items I’ll need to filter, I’ll need...


Filed under:

This article is one of Metal Toad's Top 20 Drupal Tips. Enjoy!

I regularly work with Views and recently I have had a few odd needs. One of which was when a user selects an item, that item then disappears from the view. The view has exposed filters with AJAX turned on. Since I don’t know how many items I’ll need to filter, I’ll need a way to pass multiple values through an exposed filter. Views apparently does not do this out of the box. If I was filtering on a content field setup for multiple values this may be easier. But no, I am filtering on nids. Since nids are a system field, Views sets the filter handler to 'views_handler_field_numeric'. Which gives me a textbox for input and numeric operators.

We can overcome this limitation. First we create a filter for ‘Content: Nid’ and set it to exposed. The comparision operator isn’t important here, but feel free to set it.

With the filter created we then can alter it:

function my_module_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
  if($form['#id'] == 'views-exposed-form-id'){
    $form['nid'] = array(
    '#type' => 'hidden',  //you can leave this for now and change it when everything works
     '#attributes' => array(
        'id'=>'filter-nid',  //set an id for jQuery
      ),
    );
  }
 
}

I don’t want to see this form field so I'll set it to ‘hidden’. I’m going to use jQuery to insert my values, so I want to make sure I have an ID.

Next we’re going to write some jQuery to insert our values into the field. You can use any event trigger you want (.click or .change for example). What needs to be accomplished is to insert a delimited string of values.


$(".selectedElement").click(function(){
currentValue = $(this).val();
}

$('#filter-nid').val( $('#filter-nid').val() + currentValue + ",");

There may be a more elegant way of writing this but essentially I’m grabbing the current value from the exposed form field and appending the new value. I’m using commas to delimit the list but you can use any character.

Now we have an exposed filter and jQuery inserting multiple values into the filter as a string, we can make our magic happen by calling hook_views_query_alter. If you do not have Devel installed, do it now. We are going to take a look at the $query object.

function my_module_views_query_alter(&$view, &$query) {
  dpm($query,'query');

This is the query object your view is constructing. And you will notice a few familiar terms (tables, relationships, where, fields, groupby). Our filter that we are creating is going to live in the ‘where’ array. If you set multiple filter groups in your view, you will have a couple of arrays directly inside 'where'. What we really care about is knowing which of these arrays our filter is living. If you just have one array then you are set.

If you are unfamiliar to the $query object, my advice is to go back into the view, change the exposed filter we working on and set it to ‘not exposed’ and add a value like ‘FIND ME’ or ’1234’. Save the view and head back into the dpm. Dig into the ‘conditions’ until you see the ‘value’ you set for the filter. That is the filter we are going to change. With our filter set back to exposed, we’ll move forward.

To make everything work, we are going to add to the hook_views_query_alter:

function my_module_views_query_alter(&$view, &$query) {
  // remove the dpm
  // we only want to alter this view, so we check against the machine name
  // and we make sure our exposed filter is set
  if ($view->current_display == 'my_current_display' && $view->exposed_raw_input['nid']) {
    // first we grab the value from our filter and convert it into an array
    // make sure you use the same character you used to delimit the string
    $nids = explode(',',$view->exposed_raw_input['nid']);
 
    // now we loop over the array of values we created from our exposed filter field
    foreach ($nids as $nid){
      // Be conscience of the ‘where[1]’
      // In the $query object you noticed the conditions array had multiple arrays.
      // Each filter in your view will be placed in a conditions array.
      // It is important to include the empty brackets [] after ['conditions']. This will append the new conditions instead of overwriting them.
      $query->where[1]['conditions'][] = array(
        'field' => 'node.nid', // this is ‘table.field’ from your database. If you used another filter than ‘Content: nid’ this will change. i.e ‘users.uid’
        'value' => $nid,  // looped value from our values array
        'operator' => '!=',  // condition operator. I want to filter out nids, so I am using ‘not equal’
      );
    }
  }
}

There you have it. One way to pass multiple values into an exposed filter. I’m sure there are others. Post your ideas below.

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.