Views AJAX Dynamic Dependent Exposed Filters

What will this article tell you ?

  • how to populate Views exposed filters' values with dynamic values. For example, values coming from another view !
  • make an exposed filter update its values 'on change' of another filter (based on the selected value) using AJAX (i.e. no page reload).

NB: please note that the AJAX part of the following solution only works for single-select exposed filters for now, not multiple-selects. However, for clarity purpose, I'll be using multiple-selects in some of my screenshots. EDIT : looks like it is possible, see comments below if you need it, I haven't had the chance to try it yet, will update the article when I can.

A concrete example of what we want to do

1) Populate exposed filters with dynamic values

Say you have a search page of Products that you want your visitors to be able to filter by Color and Shape.

You have a lot of possible colors and shapes registered on your website and for some reasons some of them may not return any results yet. For example there could be no 'green' product on your site yet. So if a visitor tried to look for 'green' products he or she would get a no-results-found message.

 

Because we are great web designers, we want to avoid that. Right ? Available colors on the search page should only be those that could actually bring some results back. In our example: red, black and blue only.

But, we still want to keep unused values registered into our website so that the day a webmaster needs to add a 'green' product the color would actually be there to be checked. Right ? That's why we need to find a way to tell our exposed filter to ONLY display values that interest us. Values that do have products refering to them. Values that will return results.

How do we do this with Views ? That's one of the two things this article is about.

2) Make one exposed filter update its values 'on change' of another filter using AJAX

Say you have some red & round Products and some black & square Products but NO black & round ones... This means that red and black are going to be available as filtering values on the search page, as for round and square. As a consequence, your visitors could actually try to look for black & round products and thus, get a no-results-found message !

Fortunately, thanks to AJAX we can make sure that when 'round' is checked, 'black' disappears from the available colors.

How can this be done ? That's the second part of the article.

Overview of the solution

1) Populate exposed filters with dynamic values coming from another view

So, we want to make sure the color filter only displays colors that would return products. This implies two things:

  1. being able to list those used-only colors
  2. being able to tell the exposed filter to use this list for its values

For our list of used-only colors we won't have to hesitate much as Views is THE easiest and most powerful solution we have. So we'll simply have to create a view for that.

Now, regarding the 'telling the exposed filter to use our view' part, this is not part of the UI right now so we'll have to do some custom code there. Nothing fancy though.

2) Make one exposed filter update its values 'on change' of another filter using AJAX

Now, how do we make sure ONLY the colors that are used by at least one Product of the currently selected Shape are displayed ? Gathering the correct colors won't be too hard. We'll just have to modify our view so that it can accept and deal with an input parameter. Basically, we'll just have to add a contextual filter.

The tricky part is updating the available colors 'on change' of the shape filter via AJAX. It would be great if we could just tell an exposed filter to update its values based on another one via AJAX through the UI. Unfortunately, this is not possible yet. Actually this is kind of logical considering that is it not possible to provide dynamic values to an exposed filter yet. Why would it need to refresh itself via AJAX when it cannot even change ?

Fortunately this still can be achiveved through custom coding. Futhermore, Drupal has a great AJAX Forms framework that will make it a real piece of cake !

The solution in detail

1) Populate exposed filters with dynamic values coming from another view

a) Creating the vi​ew

First of all, even though colors and shapes are Taxonomy Terms, we want to make sure we configure our View as one showing 'Content' of type 'Product', not 'Taxonomy Terms' of type 'Color'.

Why ? Because we only want to show colors that do have Products refering to them. Thereby, even though we want to display colors, we actually need to gather all products first. Only then can we see which colors are in use.

Basically, instead of displaying regular info about the product such as its title, description, etc... we will only display its color and then we'll just have to tell Views to remove duplicate rows and we'll have our list of used-only colors !

We could simply add the field color of the Product node, but by doing so we wouldn't be able to make sure that each color only appears once (even using the pure disctinct option). Try it and you'll see.

To make sure we only get distinct colors, we need to bring the Color as a Views Relationship and actually display the name of Taxonomy Term, using the Color Relationship.

The Relationship needs to be based on the 'color' Taxonomy Term Reference field of our 'Product' Content Type.

The 'Require this relationship' option should be checked. Indeed, some products may not have any color assigned to them yet if the field is not required. Thus, checking this option will prevent products with no color from being brought as a result row. Remember: we are only looking for colors here...

Once the relationship is created, we can now remove the default 'title of the node' field and replace it with the field 'Taxonomy term: name' that we will be able to bind to our Color relationship.

Now when we check Distinct + Pure Distinct on the query settings, each color is displayed only once.

Great! We now have a list of all the colors that do have at least one product "wearing" them. We're almost done with the view, but there is one last thing that needs to be done. Since we plan on using this list to populate an exposed filter - which can be a select, radio-buttons or checkboxes - we actually need to provide a 'value' for each option. This value has to be the term id for the mechanism to work. This won't be a problem as we'll just need to add a second field to display: the 'Taxonomy Term: Term ID' field, binding it to the color relationship again.

That's it! Our view is now ready to be used to populate our colors exposed filter.

2) Telling the exposed filters to use the view

As I told you earlier, it is not possible to tell our colors exposed filter to use our freshly created view to populate itself through the UI. Fortunately, it is very easy to do it using custom coding. Basically we're gonna alter the exposed filters form using a hook() and because we want to do it right, we're gonna do that in a custom module of our own.

If you don't know how to create a module already, I suggest you shoud learn how to create a module here. Creating a basic custom module is the right way to add custom code because that way you can be sure it won't be erased by a module or core update one day. Since it isn't complicated at all, my advice is read it now :-)

From what I know, the easiest way to alter our exposed filters is to access the exposed form via hook_form_views_exposed_form_alter and imediately checking the id of the form is ours :

<?php

function vaddef_form_views_exposed_form_alter(&$form, &$form_state){
 
  if (
$form['#id'] == 'views-exposed-form-products-page') {
   
dpm($form);
  }
}
?>

 

Remember to clear your Drupal site caches the first time you install your module or add a new function to it. (Configuration > Development > Performances > Clear all the caches ; even easier with the Administration Menu module)

By the way, if you don't know how to get your form's #id simply use a tool like firebug on the form element :

Now that we know we're altering the right form, let's modify the values of the colors exposed filter. For that we're gonna need to know its id too. The Drupal Print Message function dpm($form) provided by the Devel module will allow us to get it. Mine is $form['colors'] and its values are stored in $form['colors']['#options']. Now that we know that, let's try a little test :

<?php

function vaddef_form_views_exposed_form_alter(&$form, &$form_state){
 
  if (
$form['#id'] == 'views-exposed-form-products-page') {
   
$form['colors']['#options'] = array(
     
'1' => 'Red',
     
'2' => 'Blue',
     
'4' => 'Black',
    );
  }
}
?>

 

Here I manually restricted the availables colors to red, blue and black. This ain't dynamic yet, but it is a good test to see if things are working as expected before mooving on. Note that 1, 2 and 4 are the term ids of the respective colors I listed. You can see those ids when editing a term, the id is at the end of the url.

Now only those three colors should be available. Provided you gave the correct term ids, the filtering should also still work.

Ok but what we want is to use the values returned by our other view to populate the exposed filter. Well, that's what the following code does:

<?php

function vaddef_form_views_exposed_form_alter(&$form, &$form_state){
 
  if (
$form['#id'] == 'views-exposed-form-products-page') {
  
   
$form['colors']['#options'] = _get_associative_array_from_view(
     
'colors_with_products', // view id
     
'default', // view display id
     
'taxonomy_term_data_field_data_field_color_tid', // key field id
     
'taxonomy_term_data_field_data_field_color_name' // value field id
   
);
  }
}

?>
<?php

function _get_associative_array_from_view($viewID, $viewDisplayID, $keyFieldID, $valueFieldID){
 
 
$associativeArray = array();
 
$associativeArray['All'] = t('- Any -');

 
$viewResults = views_get_view_result($viewID, $viewDisplayID);
 
  foreach(
$viewResults as $viewRow) {
   
$associativeArray[$viewRow->$keyFieldID] = $viewRow->$valueFieldID;
  }
 
  return
$associativeArray;
}
?>

 

Instead of setting the values manually, this time we call a custom function _get_associative_array_from_view that returns the expected associative array. This function uses the views_get_view_result() API function of Views to get an array of results. That's why we need to provide the id of the view and of its display we want to target. The id of the view is the one you gave it when creating it but you can also read it at the end of the url when editing the view. The id of the display is default for the master display and for the other kind of displays (page, block, etc) you can find it in the advanced fieldset under "OTHER".

To build the associative array from the view results, we also need the ids of the two fields that will be used as key and value. To find out what are the ids of the fields you need, just make a dpm() of the $viewResults variable that way you can inspect the structure:

So, I guess this finishes the "how to populate an exposed filter with dynamic values coming from another view" section! Let's head to the AJAX magic updating stuff...

2) Make one exposed filter update its values 'on change' of another filter using AJAX

a) Add a contextual filter to the populating view

For our view to be able to return different values according to one input parameter, we need to add a Contextual Filter. For the list of available colors, let's add a contextual filter based on the 'shape' field. 'When the filter value is not available', the view should 'display all results for the specified field'.

We should also 'specify a validation criteria'. Making sure that the input value is the id of a Taxonomy Term belonging to the Shape vocabulary. If the validation fails, Views should display all results again.

NB: even though I've been using multiple-selects in my screenshots for clarity purpose, as mentionned earlier my solution will only work for single-selects. Indeed, it seems to me that Views can handle only one value by contextual filter. Even if we choose 'Filter value type' to be 'Term IDs separated by , or +' it seems that Views will then only be able to correctly parse the url but will still use only the first token and thus use only one value for the filter. For this reason I haven't been able to apply my solution to multiple-selects that can accept multiple selected values.

Ok, let's try it on. Enter the term id of different shapes in the preview bar. The available colors should filter correctly. In this example, 14 is the id of the "Round" shape and we can see there are only blue and red round shapes.

You can find the id of any taxonomy term such as a shape at the end of the url when editing the term.

 

b) Add an input parameter to be used as the contextual filter

Before we deal with the AJAX aspect of the solution (updating the values on the fly with no page reload), let's make sure this actually works when the page DOES reload... For example, if "Round" is selected and we click "Apply", available colors on page reload should not be "blue, red and black" anymore but only "blue and red".

That's what the following updated code does:

<?php

function vaddef_form_views_exposed_form_alter(&$form, &$form_state){
 
  if (
$form['#id'] == 'views-exposed-form-products-page') {
   
   
$selectedShape = $form_state['input']['shapes'];
      
   
$form['colors']['#options'] = _get_associative_array_from_view(
     
'colors_with_products', // view id
     
'default', // view display id
     
'taxonomy_term_data_field_data_field_color_tid', // key field id
     
'taxonomy_term_data_field_data_field_color_name', // value field id
     
$selectedShape // term id of the selected shape
   
);
  }
}
?>
<?php

function _get_associative_array_from_view($viewID, $viewDisplayID, $keyFieldID, $valueFieldID, $contextualFilter){
 
 
$associativeArray = array();
 
$associativeArray['All'] = t('- Any -');

 
$viewResults = views_get_view_result($viewID, $viewDisplayID, $contextualFilter);

  foreach(
$viewResults as $viewRow) {
   
$associativeArray[$viewRow->$keyFieldID] = $viewRow->$valueFieldID;
  }

  return
$associativeArray;
}
?>

 

First of all, we need to get the selected value of the shape exposed filter. In my case using $form_state['input']['shapes']. If you need to inspect your structure, just use dpm() on the $form_state. We then need to provide this selected shape to Views. For that we need to add another parameter to our call to views_get_view_result() and as a consequence also to our custom _get_associative_array_from_view() function. Views will understand this final argument is a contextual filter. 

That's it. Try to select as shape and submit your form. When the page reloads available colors should only be those of the products that have the currently selected shape.

c) Update the filter values 'on change' of another filter with AJAX

Ok, we now want the available colors to be updated instantly when choosing a shape without reloading the page. This requires to use the Drupal AJAX Form API. Basically, what the framework is gonna do is recreate ONLY the field colors, 'on change' of the field shape. That's what the following code does:

<?php
$form
['shapes']['#ajax'] = array(
 
'callback' => '_update_colors_callback',
 
'wrapper' => 'colors_wrapper',
);

$form['colors']['#prefix'] = '<div id="colors_wrapper">';
$form['colors']['#suffix'] = '</div>';

?>
<?php

function _update_colors_callback($form, $form_state) {
  return
$form['colors'];
}

?>

 

First, we add the #ajax attribute to the shapes field. The ajax will trigger on the default 'change' event of the select and it will replace the given 'wrapper' with the value returned by the given 'callback'. Since we want the colors field to be recreated, we called our wrapper 'colors_wrapper'. The framework will look for a container with the css ID 'colors_wrapper'. This one does not exist yet so we need to set the #prefix and #suffix of the colors field in order to wrap it with our 'colors_wrapper' div. Finally, we need to create our callback function which simply returns ONLY the colors field from the form. Note that when this field is recreated, hook_form_views_exposed_form_alter functions will be called, as expected.

At the time of this writing, this code won't work with Views (currently version 3.5) because Views does not integrate correctly with the Drupal Ajax Form API as explained in this thread: http://drupal.org/node/1183418. Good news however, the patch provided on post #33 does the magic. (There might be even better patches now, or it might even already been commited)

One problem mentioned in this thread remains unsolved by the patch: the fact that Views stores the input filters selected values in the form attribute called 'input' where Drupal Form API stores the submitted values in the attribute 'values'. So when the ajax event is triggered, the selected shape is stored in the 'values' attribute but our code looks inside the 'input' attribute.

The solution I used was one suggested earlier in the thread: merge the to arrays. Which you can do by adding this code at the beginning of your hook_form_views_exposed_form_alter function

<?php

if(!empty($form_state['values'])) {
 
$form_state['input'] = array_merge($form_state['input'], $form_state['values']);
}

?>

 

Now it should all be working! Next step is to do the same work for the field shape and make sure it updates dynamically on change of the color filter.

I hope this article is complete, understandable and optimized! Please leave a comment if you have any suggestion regarding how to improve it or if you find any correction that should be done.

Cheers,

Nick.

Comments

Hello,

Thanks, I had not found a clear titurial on this subject on the net!

I only managed to reach the part when we add the _get_associative_array_from_view.
Here I get a blank page with memory problem and my server get stuck for 5 minutes.

What I had to change before that is using $form_id instead of $form['#id'].
And also add $form_id parameter to the function:

<?php
function vaddef_form_views_exposed_form_alter(&$form, &$form_state, $form_id)  {
?>

I will carry on later. Let me know if you have some tips.
Thanks

Hi ! When you say 'blank page', I instantly think: "you have to enable error messages while developing" do you ? Here's how: http://drupal.org/node/1056468

Hi, Everything is working great !
I got lost with views and terms Ids the last time.

I went a little further with 3 exposed views lists :
lista_paises with contextual filter « tipo »
lista_tipo with contextual filter « pais »
lista_temas with contextual filter « pais »

So I have
lista_paises → (actualizes) lista_tipo
lista_paises → lista_temas
lista_tipo → lista_pais

I added another ajax fonction I found here http://drupal.stackexchange.com/questions/8529/is-it-possible-to-replace...

Here's is my code which is a mess. This is not my job, I just copy and paste, try a bit and stop when it works.

<?php

function views_advanced_custom_filter_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {

  if(!empty(
$form_state['values'])) {
   
$form_state['input'] = array_merge($form_state['input'], $form_state['values']);
  } 
 
 
$form['tema']['#prefix'] = '<div id="temas_wrapper">';
 
$form['tema']['#suffix'] = '</div>';
 
$form['pais']['#prefix'] = '<div id="paises_wrapper">';
 
$form['pais']['#suffix'] = '</div>';
 
$form['tipo']['#prefix'] = '<div id="tipos_wrapper">';
 
$form['tipo']['#suffix'] = '</div>';

  if (
$form['#id'] == 'views-exposed-form-proyectos-busqueda') {
   
$selectedTema = $form_state['input']['tema'];
   
$selectedPais = $form_state['input']['pais'];
   
$selectedTipo = $form_state['input']['tipo'];

   
$form['pais']['#options'] = _get_associative_array_from_view(
     
'intel_projects', // view id
     
'lista_paises', // view display id
     
'taxonomy_term_data_node_tid', // key field id
     
'taxonomy_term_data_node_name', // value field id
     
$selectedTipo // term id of the selected Tipo
   
);

   
$form['tema']['#options'] = _get_associative_array_from_view(
     
'intel_projects', // view id
     
'lista_temas', // view display id
     
'taxonomy_term_data_node_tid', // key field id
     
'taxonomy_term_data_node_name', // value field id
     
$selectedPais // term id of the selected Pais
   
);
   
$form['tipo']['#options'] = _get_associative_array_from_view(
     
'intel_projects', // view id
     
'lista_tipos', // view display id
     
'taxonomy_term_data_node_tid', // key field id
     
'taxonomy_term_data_node_name', // value field id
     
$selectedPais // term id of the selected Pais
   
);
  }

 
$form['pais']['#ajax'] = array(
   
'callback' => 'ajax_exposed_fields_update_callback',
  );

 
$form['tipo']['#ajax'] = array(
   
'callback' => 'ajax_exposed_fields_update_callback',
  );

}

?>


<?php

function ajax_exposed_fields_update_callback(&$form, $form_state) {
  return array(
   
'#type' => 'ajax',
   
'#commands' => array(
     
ajax_command_replace("#tipos_wrapper", render($form['tipo'])),
     
ajax_command_replace("#temas_wrapper", render($form['tema'])),
     
ajax_command_replace("#paises_wrapper", render($form['pais']))
    )
  );
}

?>


<?php

function _get_associative_array_from_view($viewID, $viewDisplayID, $keyFieldID, $valueFieldID, $contextualFilter) {
 
 
$associativeArray = array();
 
$associativeArray['All'] = t('- Any -');

 
$viewResults = views_get_view_result($viewID, $viewDisplayID, $contextualFilter);

  foreach(
$viewResults as $viewRow) {
   
$associativeArray[$viewRow->$keyFieldID] = $viewRow->$valueFieldID;
  }

  return
$associativeArray;
}

?>

You can see it working here :
http://www.natate.org/proyectos-de-voluntariado

Is it possible to have the list lista_temas actualizaing the other selects ? Or are we stuck because contextual filter is limited to one term?

Contextual filter is limited to one parameter which means you cannot provide many say colorIDs separated with « + » or « , ». But Views is not limited to one contextual filter which means you can create multiple contextual filter. In my example, say I want to add a third filter « price », in order to get my used-only colors I will now need two contextual filters : shape and price.

However, Drupal Ajax API's callback function will only « recreate » one item of the form. So if you want, say that both your color and shape filters to update on change of the price filter, you will not be able to recreate both.

I actually do have a workaround for that : recreate the whole form instead using return $form; instead of return $form['colors']; and change your ajax wrapper so that it actually is the whole form instead of one filter only.

Hope I answered your question.

That's great! I'll have another go next week end to see if I can update the whole exposed form.
Thanks Nick

It might not be related to your post which is great BTW. My ajax call gave me error. Location at http://.../system/ajax and error message is "Notice: Undefined index: form_build_id at ajax_get_form() (line 320 at /opt/www/nobo_iguide/includes/ajax.inc)." I guess it's related to other modules or settings that I used or applied. Just want to ask you in case you know.

Hi, first of all, this error you're talking about. Did you get it while trying to accomplish what is described in this article? Or were you doing something else and you landed on this article while trying to find a solution to your problem?

Ok the error here cannot really help you because the error is thrown by the core... (/includes/ajax.inc). The core works so you need to find the module that is causing the core to throw this error. If you were trying to accomplish what is described in this article I could think that maybe you haven't correctly applied the patches given in http://drupal.org/node/1183418 as suggested in the article.

Anyway, in order to help you I will need to understand better what you are trying to do and where you get stuck.

Cheers,

Nick

The problem is solved. I didn't apply the patch which is in the post. After I did (#33), it worked. But I had another error which is related to the 'date' module. I have to use 'pop-up' display for that field or I will have anther 502 error. Anyways, your reference is helpful.

Glad I could help!

This is an excellent article, which seemingly promises to solve all my problems in life.

Some of the dialogue looks like Drupal 6, is this solution definitely compatible with Drupal 7.x

I am looking forward to diving in !

Yes this is all written for Drupal 7. Please let me know if some of my stuff should be adapted to Drupal 7.

Nicolas

Thanks for this fantastic tutorial. It's exactly what I needed for a Estate Agent website I'm working on. I have it all working as per your tutorial but I'm have a problem when there are more than 10 items in the search result and a pager is used. The results are fine for the first page of the pager, but when you click on 'next' (or any pager number), the page loads with an error 'An illegal choice has been detected. Please contact the site administrator.' I've echo the variable $associativeArray and on the intial search results page, the array is populated with the correct data. On the second page, the array only has 'Array ( [All] => - Any - )', so it appears that it is not populating with the data from the View.

Have you any idea why this would happen?

Thanks

Frank

Indeed you need to dpm() several variables to find out where does the problem comes from. I would say that your view is correctly configured since it works on the first page. So maybe the $contextualFilter that you pass is wrong when loading page 2... Then maybe try dpm(form_state['input']) to understand what's going on.

I finally figured it out. The view I had set-up to populate the exposed filter had a Pager turned on. Once I swtiched that off and set to 'Display all items', it worked fine. Thanks again for a fab tutorial.

Thank you for this fantastic tutorial, Nicolas Bouteille! I want a very similar functionality on a website I am working on, but I am stuck! Can you help me?

What I'm trying to achieve, is that when a visitor makes a change in one of the exposed filters the submit button's label will change to something like this: "Submit (8 results)". So what I need to get, is the number of results of the view. That's where I am now... I can't seem to execute the view in the module_form_alter function (the whole page goes blank). If I'm right the view is in the form_alter isn't executed yet, so the count of the results doesn't exist yet.

Here is my code:

function magyarkerteszek_form_alter(&$form, &$form_state, $form_id) {
    $view_name = 'termelok';
if ($form_id == 'views_exposed_form') {
        $view = $form_state['view'];
        if ($view->name == $view_name) {
            /*
             * Modifying View results
             */
            $fields = array(
                'field_ter_let_value',
                'field_id_szak_tid',
                'field_termeszt_hely_tid',
                'field_technol_gia_tid',
            );

      
            foreach ($fields as $field) {
                if (isset($form[$field])) :
                    /*
                     * Create AJAX event
                     */    
                    $form[$field]['#ajax'] = array(
                      'callback' => '_update_submit_callback',
                      'wrapper' => 'submit_wrapper',
                    );   
                endif;
            }

            $count = count($view->result);
            $form['submit']['#value'] = 'Submit (' . $count . ' results)';          
           
            $form['submit']['#prefix'] = '<div id="submit_wrapper">';
            $form['submit']['#suffix'] = '</div>';

            if(!empty($form_state['values'])) {
                $form_state['input'] = array_merge($form_state['input'], $form_state['values']);
            }
        }
    }
}

function _update_submit_callback($form, $form_state) {
    return $form['submit'];
}

Hi Adam,
By reading your code it seems you've taken the good road already.
You say you get a blank page... do you have errors turned on? https://drupal.org/node/1056468
Regarding the call to view, you need to use views_get_view_result() to manually execute the view while in the form_alter. Then only you will be able to get the results count.
Hope that will help you.
Cheers!

Hi Nicolas,

Thank you for the fast reply! Now I have a clear error message. :) I get it only if I insert a line one of these:
$result = views_get_view_result($view_name, $view_display);

$view->execute();

The error message itself:
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 76 bytes) in .../includes/database/log.inc on line 145

I changed the memory size to 512MB, but if I do that the page will stuck at the loading phase... I've turned on all cache, but it didn't help.

I believe you've got an infinite loop. You don't need to call view->execute(); for the function views_get_results to do its job. Maybe it is what's causing the loop.

Sorry for the delayed answer, I couldn't work on this project until now. If I remove the $view->execute(); line I got the same "Fatal error: Allowed memory size" error message. On the other hand my module_form_alter hook runs twice. I know it, because when I use print_r the message appears twice every time.

Can you screenshot view from this example?

Yes, should I export my view too? Just because I've changed the language of the admin panel to English, but there are a few texts which stayed in Hungarian...

https://dl.dropboxusercontent.com/u/84138761/View.PNG

Well, I guess I have to write a DB Query to accomplish what I want to do... Thanks for the help anyway! :)

The AJAX only works for single-select exposed filters for now, not multi-selects solution.please add the details of multi selects solutions. Really love to read more about the AJAX topic. more here Keep on posting and thank you for sharing the details of the same.

Actually it works with multiple contextual filter too, you just need to check the "Allow multiple value" in the contextual filter settings (fieldset "More")
See : http://i.zeropi.net/files/1385652462_87979.png

Thanks for that tutorial by the way, works pretty well.

Thanks! It works well with drop-down selects.

But what if I want that first list to be radio buttons?
BEF module gives me that option.
However, after changing the first filter from "Default select list" to "Checkboxes/Radio buttons" - the AJAX thing does not react at all to radio changes.
Any ideas?

Thanks,

I actually encountered the same problem and posted an issue to BEF module
https://drupal.org/node/1883740
Looks like there's another Ajax-related issue about BEF here
https://drupal.org/node/1268150
Please let me know when you find the solution

Hello,

Thanks for your howto it seems to do all I'm looking for.
Unfortunately I encounter a problem when trying to use the dpm function to get the form id. I have installed the devel module and activated it. Then I have activated the Executing php code block. On the page my form is I tried to use the dpm function in the executing php code block but no result. In fact, no error message, but nothing else than a green ok message pic on the page's message area (the code I wrote in the block is "dpm($form)").
Do you have any idea of what I've done wrong? Note: I'm not a php developer at all, I'm just developing an association's website.

Thanks

Romain

Hello Romain,

Ok although it's difficult to help you when I don't have the possibility to see what you might be doing wrong, I'm just gonna take a guess here. Several actually :
1/ dpm() only displays for users who have permissions set. Make sure you view the page as user 1 or set permissions properly.
2/ make sur you are including php opening and ending tags if needed in your PHP block
3/ something seems not right: you are trying to display the variable $form with a dpm inside "PHP code block" ? Where does the variable $form comes from ? I apologize if you already know what I am about to tell you but since you describe yourself as "not a PHP developper at all" I will assume you know very little. You need to know that the $form variable is not a global variable that will be shared with any code block anywhere... in my example I used a Drupal hook function that allows to modify the $form variable the right way. If what I just told you is new for you maybe you are trying to do something to difficult for you current development level and you should consider hiring someone to do the job for you or find a simpler solution. For example, have you heard of Faceted Search ? http://envisioninteractive.com/drupal/drupal-7-views-with-faceted-filter...

Hello Nicolas,

I finally got the dpm function work including it in a custom module. So I got my form id. But I'm unable to get the first view field id using dpm. Could you detail which code you used to get those field id? I will then adapt it to my case.

Thanks

Have you tried to dpm() the $viewResults variable as I suggested in my article?

Yes I have but I get a blank page instead of my website page and the dpm result in the message area.

I used that code:

<?php
function perso (&$viewID, &$viewDisplayID){

$viewID='genre'
$viewDisplayID='default'
$viewResults = views_get_view_result($viewID, $viewDisplayID);
dpm($viewResults)

}
?>

The blank page is because you did not enable errors display on your website. Here's how you can do it:
https://drupal.org/node/1056468
you probably have a PHP error because of a missing semi-colon at the end of several lines in your code but the PHP errors should speak by themselves.
I don't mean to be rude but you clearly don't have the skills required — basic PHP — to do what you are trying to do right now. Please, at least take the time to read my article carefully and adapt the code correctly.

Dear Nicolas
Great tutorial for something I realy need for a site for my client.
I followed all the steps mentioned in you tutorial but I got stuck after step 1
I get the following message:
( ! ) Fatal error: Maximum function nesting level of '100' reached, aborting! in C:\wamp\www\power-eco-tuning.be\sites\all\modules\views\handlers\views_handler_field.inc on line 32
As you can see I am using a wamp server for development purpose.

Thanks for the quick respons. Sorry it does not solve the problem. I even increased memory to 512 and max execution time of my php.ini on wamp. Shall I send a export of my view and of my module with the function in it?? Many thanks for your support

Sorry but I don't think I'm gonna be able to help you on that... this seems to be linked to your development environment, not the feature you're trying to build in itself... I don't use wamp and I've never seen that error. I think you should re-open the issue above.

Thanks again for your reply, I will move the site to another testing envirement.

Hi - I would really love to use my feature for several pages on my volunteer site. For example, on the program pages like this one - https://www.volunteerglobal.com/program-type/Education.

But I need the volunteers to be able to search with multiple options - does the comment by opi allow this now?

Hi, if updating the results everytime a filter is modified is an option for you, I would suggest using faceted search instead.
Have a look at this article for example : http://envisioninteractive.com/drupal/drupal-7-views-with-faceted-filter...
If faceted search is not suited to your needs I would say that, yes, multi-options should work by now, but sorry I haven't tried it yet.
Please let me know what you'll have chosen in the end :)

This module allows to create dependent filters: https://www.drupal.org/project/entityreference_filter

Hi Nicolas
Thank you for the tutorial.
The AJAX part is not working for me. What can be the problem?
Please have a look in http://s1-dallas.accountservergroup.com/~liorfein/school/?q=prod&field_c...

Hello, thanks a lot for the tutorial, I really learned from it. What i need to achieve for another project, is to update the options of an exposed filter ''onChange" of another one, and looking for a solution, I came across your tutorial.
Until 2b), everything worked as advertised. When I tried to implement the 2c) part, it didn't. I get an error: Notice: Undefined index: field_shape_tid in customone_form_views_exposed_form_alter() (line 32, which is really strange, because I didn't modify this line in the 2c) step. This is the line where the $selectedShape gets its value. Strange thing, is that this error only appears when I open the page for the first time, when I apply a value to the "shape" filter, view filters work as expected, and error goes away. If I enable autosubmit, but not ajax, from the views' UI, having all of your code in my custom module, onsubmit the values on the color filter update as expected. When I enable ajax though, with no autosubmit, when I change the shape filter, I get no ajax response, which happens only when I click the apply button, in which case the filters normally apply to the results, but the color filter values do not update. Any help is welcome! Thanks again

In 2.c) I speak of an error. This might be the one troubling you. Is it ?
At the time of this writing, this code won't work with Views (currently version 3.5) because Views does not integrate correctly with the Drupal Ajax Form API as explained in this thread: http://drupal.org/node/1183418 (link is external). Good news however, the patch provided on post #33 does the magic. (There might be even better patches now, or it might even already been commited)

Great article. However I would like to highlight the fact that this wont work until the patch mentioned (or any latest patches in that thread) is applied.. But apart from that, a huge thanks to the author.

I have followed the tutorial and its really helpful. However i am receiving following error when i change the dropdown.
The form has become outdated. Copy any unsaved work in the form below and then reload this page.
Please help in to solve this

<?php
function alterfilter_form_views_exposed_form_alter(&$form, &$form_state){ 



  if (
$form['#id'] == 'views-exposed-form-bike-search-page') {
   
   
$selectedTerm = $form_state['input']['term_node_tid_depth'];
   
   
$form['nid']['#type'] = 'select';
$form['nid']['#size'] = null;
$form['nid']['#default_value'] = 0;
$form['nid']['#options'] = _get_associative_array_from_view(
     
'bike_search', // view id
     
'block_1', // view display id
     
'nid', // key field id
     
'node_title', // value field id
     
$selectedTerm // term id of the selected shape
   
);
$form['nid']['#validated'] = true;   
$form['term_node_tid_depth']['#ajax'] = array(
 
'callback' => '_update_colors_callback',
 
'wrapper' => 'colors_wrapper',
);
$form['nid']['#prefix'] = '<div id="colors_wrapper">';
$form['nid']['#suffix'] = '</div>';
  }
}
?>

<?php
function _get_associative_array_from_view($viewID, $viewDisplayID, $keyFieldID, $valueFieldID, $contextualFilter){
 
 
$associativeArray = array();
 
$associativeArray['All'] = t('- Any -');
 
$viewResults = views_get_view_result($viewID, $viewDisplayID, $contextualFilter);
  foreach(
$viewResults as $viewRow) {
   
$associativeArray[$viewRow->$keyFieldID] = $viewRow->$valueFieldID;
  }
  return
$associativeArray;

}

?>


<?php
function _update_colors_callback($form, $form_state) {
  return
$form['nid'];
}
?>

Hi Nicolas
Thanks for the tutorial, it seems to be the only option I can find online for my project. But, I'm having some issues following the steps. I can't seem to get the right form ID, where you have 'colors', I can't get dpm to print out the correct ID. Is there a possibility you have a more detailed tutorial, step by step that would help us newbies?

Thank you for the article, was very helpful. For anyone else using the Location module in this context, there is an issue with Ajax support that is addressed at https://www.drupal.org/node/1872776.

It was such a great post that really helpful for me.

great

Pages