Is there any way to Ajax facets be integrate with a range slider?

CommentFileSizeAuthor
#6 6BylMc6.png9.62 KBeugene.ilyin
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nickBumgarner’s picture

Subscribe

eugene.ilyin’s picture

Category: Feature request » Plan
eugene.ilyin’s picture

Btw, I've started work on it. It' will work like https://jqueryui.com/slider/#range
I'll try to implement it in 1-2 weeks.

  • eugene.ilyin committed 420af1b on 7.x-3.x
    Issue #2341081: Integrate Ajax facets and a range slider
    
  • eugene.ilyin committed c0a874f on 7.x-3.x
    Issue #2341081: Integrate Ajax facets and a range slider
    
  • eugene.ilyin committed d18e88b on 7.x-3.x
    Issue #2341081: Integrate Ajax facets and a range slider
    
  • eugene.ilyin committed d30513a on 7.x-3.x
    Issue #2341081: Integrate Ajax facets and a range slider
    
  • eugene.ilyin committed ea540ad on 7.x-3.x
    Issue #2341081: Integrate Ajax facets and a range slider
    
eugene.ilyin’s picture

Status: Active » Needs review

I've commited new widget "Ajax ranges". Can somebody check it out?

Example: ranges widget

eugene.ilyin’s picture

FileSize
9.62 KB
eugene.ilyin’s picture

Status: Needs review » Fixed

So, it will be included into the next release, which I'm going to prepare in few weeks.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

JamesDevware’s picture

Great module thanks.

I had some issues with this while using this for a commerce product price slider.
In Drupal.ajax_facets.processSlider the facet name was not encoded resulting in colons in the facet name meaning that the slider didn't work.

I also wasn't getting live updates in the fields so added a few lines to make the fields update as the user was moving the slider. (This may be something to do with my setup, I haven't tested on a simpler build).

Below is the resulting processSlider function that worked for me. Hopefully this can help you to make this more robust and work with fields that are built through relationships.

/**
   * Callback for slide event for widget ranges.
   */
  Drupal.ajax_facets.processSlider = function($sliderWrapper, min, max) {
    window.clearTimeout(Drupal.ajax_facets.timer);
    var $facet = $sliderWrapper.parent();
    $facet.find('.ajax-facets-slider-amount-min').val(min);
    $facet.find('.ajax-facets-slider-amount-max').val(max);
    Drupal.ajax_facets.timer = window.setTimeout(function() {
      var facetName = encodeURIComponent($sliderWrapper.data('facet'));
      if (Drupal.ajax_facets.queryState['f'] != undefined) {
        // Exclude all values for this facet from query.
        Drupal.ajax_facets.excludeCurrentFacet(facetName);
        Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length] = facetName + ':[' + min + ' TO ' + max + ']';
      }

      Drupal.ajax_facets.sendAjaxQuery($sliderWrapper);
    }, 600);
  }

Thanks again!

JamesDevware’s picture

Status: Closed (fixed) » Needs work
eugene.ilyin’s picture

Status: Needs work » Postponed (maintainer needs more info)

@Xenza, thank you for your report. But it looks strange. Please provide more info, how I can reproduce your problem.

JamesDevware’s picture

Commerce product is attached to a product display
Product displays are indexed in search api

Field:
Product > Price > Amount (decimal) | field_product:commerce_price:amount_decimal | Indexed as "Decimal"

AJAX Ranges Selected (This is the same setup which was used and worked for "Ranges Min/Max UI Slider")
Update via AJAX and selected "Empty Facet Behaviour"

Unfortunately this setup didn't work before I patched the JS.

There was also an issue with this setup and jQuery 1.8+ Which was with the decimals being passed to the jquery slider as strings rather than numeric values.
This was fixed with the below:

if (settings.facetapi.facets[index].widget == 'facetapi_ajax_ranges') {
            $('#' + settings.facetapi.facets[index].id + ' div.slider-wrapper:not(.processed)').each(function () {

              var $sliderWrapper = $(this);

              $sliderWrapper.slider({
                range: true,
                min: parseFloat($sliderWrapper.data('min')),
                max: parseFloat($sliderWrapper.data('max')),
                values: [ parseFloat($sliderWrapper.data('min-val')), parseFloat($sliderWrapper.data('max-val')) ],
                slide: function( event, ui ) {
                  Drupal.ajax_facets.processSlider($sliderWrapper, ui.values[0], ui.values[1]);
                }
              }).addClass('processed');


              // Bind input fields.
              var $sliderWrapperParent = $sliderWrapper.parent();
              $sliderWrapperParent.find("input[type='text']").each(function() {
                $(this).change(function() {
                  var min = $sliderWrapperParent.find('.ajax-facets-slider-amount-min').val();
                  var max = $sliderWrapperParent.find('.ajax-facets-slider-amount-max').val();
                  // If values are numeric and min less than max.
                  if (!isNaN(parseInt(min)) && isFinite(min) && !isNaN(parseFloat(max)) && isFinite(max) && min < max) {
                    $sliderWrapper.slider('values', 0, min);
                    $sliderWrapper.slider('values', 1, max);
                    Drupal.ajax_facets.processSlider($sliderWrapper, min, max);
                  }
                });
              });
            });
          }
fmfpereira’s picture

I also have tried with a commerce price, and the problem is the same.

#9 also solved my problem for now.

Filipe

eugene.ilyin’s picture

Status: Postponed (maintainer needs more info) » Active
esiao’s picture

I had the same problem and #9 solved my issue. But I had another,

While the search query was executed correctly, the range slider was reset to it's initial values. So the end user wasn't aware that the modifications were effective.
I solved it by doing a little internal caching.

I added a new object

Drupal.ajax_facets.timer;
//Object to store ranges widget values
Drupal.ajax_facets.ranges = [];

And modified the ranges widget function attachement with the following

// Ranges.
          if (settings.facetapi.facets[index].widget == 'facetapi_ajax_ranges') {
            $('#' + settings.facetapi.facets[index].id + '-wrapper div.slider-wrapper:not(.processed)').each(function (index, element) {
              var $sliderWrapper = $(element);
              var $sliderWrapperParent = $sliderWrapper.parent();
              if (Drupal.ajax_facets.ranges[index] === undefined) {
                Drupal.ajax_facets.ranges[index] = {
                  min: $sliderWrapper.data('min'),
                  max: $sliderWrapper.data('max')
                };
              } else {
                $sliderWrapper.data('min-val', Drupal.ajax_facets.ranges[index].min);
                $sliderWrapper.data('max-val', Drupal.ajax_facets.ranges[index].max);
                $sliderWrapperParent.find('.ajax-facets-slider-amount-min').val(Drupal.ajax_facets.ranges[index].min);
                $sliderWrapperParent.find('.ajax-facets-slider-amount-max').val(Drupal.ajax_facets.ranges[index].max);
              }
              $sliderWrapper.slider({
                range: true,
                min: $sliderWrapper.data('min'),
                max: $sliderWrapper.data('max'),
                values: [ $sliderWrapper.data('min-val'), $sliderWrapper.data('max-val') ],
                slide: function( event, ui ) {
                  Drupal.ajax_facets.processSlider($sliderWrapper, ui.values[0], ui.values[1]);
                  Drupal.ajax_facets.ranges[index] = {
                    min: ui.values[0],
                    max: ui.values[1]
                  };
                }
              }).addClass('processed');

              // Bind input fields.
              $sliderWrapperParent.find("input[type='text']").each(function() {
                $(this).change(function() {
                  var min = $sliderWrapperParent.find('.ajax-facets-slider-amount-min').val();
                  var max = $sliderWrapperParent.find('.ajax-facets-slider-amount-max').val();
                  // If values are numeric and min less than max.
                  if (!isNaN(parseFloat(min)) && isFinite(min) && !isNaN(parseFloat(max)) && isFinite(max) && min < max) {
                    $sliderWrapper.slider('values', 0, min);
                    $sliderWrapper.slider('values', 1, max);
                    Drupal.ajax_facets.processSlider($sliderWrapper, min, max);
                    Drupal.ajax_facets.ranges[index] = {
                      min: min,
                      max: max
                    };
                  }
                });
              });

            });
          }

This is far from perfect as I think the best solution would be to change the "min-val" and "max-val" values on the slider when it gets recreated so in the ajax Callback done in the module file. And then in the Javascript initialize the slider with these values, instead of creating an object to store the values and retrieve them like I did.

If this can help.

esiao’s picture

I had the same problem and #9 solved my issue. But I had another,

While the search query was executed correctly, the range slider was reset to it's initial values. So the end user wasn't aware that the modifications were effective.
I solved it by doing a little internal caching.

I added a new object

Drupal.ajax_facets.timer;
//Object to store ranges widget values
Drupal.ajax_facets.ranges = [];

And modified the ranges widget function attachement with the following

// Ranges.
          if (settings.facetapi.facets[index].widget == 'facetapi_ajax_ranges') {
            $('#' + settings.facetapi.facets[index].id + '-wrapper div.slider-wrapper:not(.processed)').each(function (index, element) {
              var $sliderWrapper = $(element);
              var $sliderWrapperParent = $sliderWrapper.parent();
              if (Drupal.ajax_facets.ranges[index] === undefined) {
                Drupal.ajax_facets.ranges[index] = {
                  min: $sliderWrapper.data('min'),
                  max: $sliderWrapper.data('max')
                };
              } else {
                $sliderWrapper.data('min-val', Drupal.ajax_facets.ranges[index].min);
                $sliderWrapper.data('max-val', Drupal.ajax_facets.ranges[index].max);
                $sliderWrapperParent.find('.ajax-facets-slider-amount-min').val(Drupal.ajax_facets.ranges[index].min);
                $sliderWrapperParent.find('.ajax-facets-slider-amount-max').val(Drupal.ajax_facets.ranges[index].max);
              }
              $sliderWrapper.slider({
                range: true,
                min: $sliderWrapper.data('min'),
                max: $sliderWrapper.data('max'),
                values: [ $sliderWrapper.data('min-val'), $sliderWrapper.data('max-val') ],
                slide: function( event, ui ) {
                  Drupal.ajax_facets.processSlider($sliderWrapper, ui.values[0], ui.values[1]);
                  Drupal.ajax_facets.ranges[index] = {
                    min: ui.values[0],
                    max: ui.values[1]
                  };
                }
              }).addClass('processed');

              // Bind input fields.
              $sliderWrapperParent.find("input[type='text']").each(function() {
                $(this).change(function() {
                  var min = $sliderWrapperParent.find('.ajax-facets-slider-amount-min').val();
                  var max = $sliderWrapperParent.find('.ajax-facets-slider-amount-max').val();
                  // If values are numeric and min less than max.
                  if (!isNaN(parseFloat(min)) && isFinite(min) && !isNaN(parseFloat(max)) && isFinite(max) && min < max) {
                    $sliderWrapper.slider('values', 0, min);
                    $sliderWrapper.slider('values', 1, max);
                    Drupal.ajax_facets.processSlider($sliderWrapper, min, max);
                    Drupal.ajax_facets.ranges[index] = {
                      min: min,
                      max: max
                    };
                  }
                });
              });

            });
          }

This is far from perfect as I think the best solution would be to change the "min-val" and "max-val" values on the slider when it gets recreated so in the ajax Callback done in the module file. And then in the Javascript initialize the slider with these values, instead of creating an object to store the values and retrieve them after like I did.

If this can help.

  • eugene.ilyin committed 178ff52 on 7.x-3.x
    Issue #2341081 by eugene.ilyin, Xenza: Integrate Ajax facets and a range...
eugene.ilyin’s picture

I've applied some corrections. But not exactly as in the snippets of code above.

So ajax ranges works pretty good for me right now. With decimals also.
I don't want to make this issue too big. Please create new issues if you'll have some trouble.

P.S. @esiao
Your problem isn't fully clear for me. I don't understand how it happens that slider has been reset. Can you explain it please? Step by step approach is the best.

  • eugene.ilyin committed ecd47a7 on 7.x-3.x
    Issue #2341081 by eugene.ilyin: Integrate Ajax facets and a range slider
    
eugene.ilyin’s picture

Status: Active » Closed (fixed)

@esiao ok, I'm closing this issue. If you still have a trouble please open the new one related with this.

dmitryVL’s picture

Status: Closed (fixed) » Active

Hello
I need some help, how i can get ranges widget without updating max and min values after rebuild ? Maybe you can advise me some code edits on your module ?

eugene.ilyin’s picture

Status: Active » Fixed

This issue is pretty long and old. Please create new one.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.