0

In a view showing commerce products, with exposed filters, I need to make a slider filter for commerce_price field. This is easy with exposed filters (is between operator) and BEF module, but ...

commerce_price field is retrieved in the view by its relationship to Product variation type, and I've got 2 different Product variation types for the same product display :

enter image description here

And

enter image description here

This means you can make a slider for each one, but this makes no sense for end-user to have 2 prices slider !

And by default Views 3.x Global: Combine fields filter doesn’t provide "is between" operator, it only works with strings and operators like equal to, begins...

How can I filter the values of both relationships in a single slider for that Price field ? Is there a Views setup way or a module to do that? If not, how can I add a custom filter to my view using API ?

  • 1
    If you're using Views to filter by price, be aware that you can't filter by calculated price out of the box, see drupal.org/node/1020050. – Andy Jul 11 '14 at 10:36
1
+50

This is a "smoke and mirrors" situation, in which you want the end user to experience one thing when the code is doing something completely different.

I would do a little bit of jQuery trickery. First, I would expose all 4 fields (the high and low for each of the 2 fields) as text boxes. Then, I would use the jQuery UI slider (which ships with Drupal Core) to update the high and low values as the user changes them. Of course, the jQuery should hide the actual text boxes as well. This will give you the effect that you are looking for.

Finally, if you wanted this to be ultra simple in the event that Javascript fails, you can use a form alter to hide one of the pairs of text boxes and then, when the form is submitted or the view loaded, populate the values for the other filter programmatically.

function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'THE-FORM-YOU-WANT-TO-TARGET') {
    // you'll have to look through the $form array for the field you want
    // I suggest installing Devel and running dsm($form);

    $form['YOUR-FORM-ELEMENT']['#default_value'] = isset($_SESSION['max']) ? $_SESSION['max'] : 1000;
    // Do this for all the applicable form elements...

    // Finally, tell Drupal that you want to see the form when it is submitted.
    array_unshift($form['#submit'], 'MYMODULE_filter_submit');
  }
}

function MYMODULE_filter_submit($form, &$form_state) {
  $_SESSION['max'] = $form_state['values']['YOUR-FORM-ELEMENT'];
}

You'll have to double-check to see what the variables actually look like. I suggest installing the Devel module and putting dsm($form); and dsm($form_state); at the beginning of the functions.

Lastly, any time that you add a hook, don't forget to clear your cache or Drupal won't find it.

  • I can't give you exact code, because so much of it depends on your installation, field names, view names, etc. There are plenty of examples for this type of action, however. In the link I provided to the jQuery UI slider, click the "View Source" link and see how they provide a function for the slide event that updates values on the page. Yours will do the same, except with form elements. The form itself can be intercepted using a hook_form_alter(), which can also provide a "remember last setting" by storing values in the PHP $_SESSION variable. – coreyp_1 Jul 10 '14 at 18:26
  • I didn't mean exact code of course :) just a snippet to illustrate your answer. And what about "Remember the last setting the user gave this filter." ? – Kojo Jul 10 '14 at 18:32
  • hook_form_alter() is your friend here. You can, for example, add a #submit hook (you probably want to put it first in the list using the PHP unshift() function) that reads the submitted values and stores them in $_SESSION['min'] and $_SESSION['max'] variable. Then, in the hook_form_alter(), if the min and max values are set, then make them the default for the form values. In other words, hook_form_alter() is your starting point to setting initial form values and for telling Drupal that you want to see the form when it is submitted. – coreyp_1 Jul 10 '14 at 18:40
  • 1
    I added code in my original answer, since the comments don't seem to support it. – coreyp_1 Jul 10 '14 at 18:55
1

I had a similar problem and my solution was to write a custom query that fetches distinct values from the desired tables in ascending order & populating the slider with the query's result. Here are the steps:

1. In the .module file of your custom module,

function <module_name>_preprocess_views_view(&$vars)
{
    $view = $vars['view'];
    $query = $view->query;

    //Use this to find out the machine name of view
    //drupal_set_message('<pre>' .print_r($view->name,TRUE). '</pre>');

    switch($view->name)
    {
        case '<view_name>':

        //Fetch distinct price values from the price table(s) & sort in ascending order since a slider ranges from min to max!
        $arr = db_query("SELECT DISTINCT column1_value FROM {price_table1},{price_table2} ORDER BY column1_value ASC")->fetchCol();

        //Convert associative arrays to normal arrays
        foreach($arr as $key=>$value)
            $normal_arr[] = (float)$value;

        //Pass variables from .module to .js file
        drupal_add_js(
            array(
                'views_slider' => array(
                    'arr_values' => $normal_arr
                    )
                ),
                array('type' => 'setting')
            );

         //Include appropriate .js file
         drupal_add_js(drupal_get_path('module', '<module_name>') . '<path_to_js_file_within_module>/<js_file>.js');

         break;
     }
}

2. In the .js file, populate the jQuery slider using the result of the query as reference. Cookies are used to retrieve values on the slider & its textboxes even after page load/views exposed form submit.

    function ($) {
    Drupal.behaviors.views_slider = {
        attach: function (context, settings) {
            var arr_val = Drupal.settings.views_slider.arr_values;

            var min = getCookie("price-min");
            var max = getCookie("price-max");

            //Here 'edit-field-price-value-wrapper' is the id of the BEF slider wrapper.
            //You can find this by using Firebug or similar element-inspecting browser apps.
            $("div#edit-field-price-value-wrapper div.ui-slider").slider({
                min: 0,
                max: arr_val.length-1,
                values:[min, max],
                slide: function(event, ui) {
                    if (ui.values[0] > ui.values[1])
                    {
                        return false;
                    }
                    $("#edit-field-price-slider-value-min").val(arr_val[ui.values[0]]); //Id of min textbox in BEF slider
                    $("#edit-field-price-slider-value-max").val(arr_val[ui.values[1]]); //Id of max textbox in BEF slider
                    setCookie("price-min", ui.values[0], 1);
                    setCookie("price-max", ui.values[1], 1);          
                },
                //When incorrect values are entered,this event updates the textboxes to their closest value
                change: function (event, ui) {
                    if (ui.values[0] > ui.values[1])
                    {
                        return false;
                    }
                    $("#edit-field-price-slider-value-min").val(arr_val[ui.values[0]]); //Id of min textbox in BEF slider
                    $("#edit-field-price-slider-value-max").val(arr_val[ui.values[1]]); //Id of max textbox in BEF slider
                    setCookie("price-min", ui.values[0], 1);
                    setCookie("price-max", ui.values[1], 1);
                }
            });
        }
    }
})(jQuery);

Hope this helps.

  • Thanks Supriya for your answer. This does not solves the question. I would need to mix your answer with coreyp's one in order to populate not 2 but 4 min/max textboxes. Also theme_preprocess_views_view(&$vars) should go into template.php, not custom module. And I implemented your code but despite all my adjustments (testing if min an max are null & so on), could not make it work. There's always sthing wrong with min max values and slider behavior ... tks anyway – Kojo Jul 11 '14 at 18:28
  • Hello, Did you manage to solve this problem?If yes, please post your answer here. I would like to find out the optimal solution for our problem! Thank you. – Supriya Rajgopal Aug 8 '14 at 5:45
  • Currently on holydays ;) I'll try to remember to post something when back. I used smoke and mirrors solution. .. – Kojo Aug 9 '14 at 18:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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