Question

Dear developers out there,

I have an application up and running with the Telerik MVC Grid, which is great.

However, the users do not like the fact that they have to type filter values for columns that have only enumerable values.

Does anyone have experience with the implementation of multiselect filters with prepopulated enumerable values?

This would be much appreciated, not in the least by the end users.

Was it helpful?

Solution

I finally managed to add enumerable filters by overriding some of the telerik javascript methods.

The code provided does not work as is (it also contains persistence for filter values, uses jquery ui), but should be usable if you have enough javascript experience:

var MyCompanyFilteringBaseImplementation = (function (
  origCreateTypeSpecificInput, 
  origClearClick, 
  origFilterClick, 
  origCreateFilterMenu) {


  return {
      baseCreateTypeSpecificInput: origCreateTypeSpecificInput,
      baseFilterClick: origFilterClick,
      baseClearClick: origClearClick,
      baseCreateFilterMenu: origCreateFilterMenu

  };
} ($.telerik.filtering.implementation.createTypeSpecificInput,
   $.telerik.filtering.implementation.clearClick,
   $.telerik.filtering.implementation.filterClick,
   $.telerik.filtering.implementation.createFilterMenu
));


// Override existing functions for Filtering
var MyCompanyFilteringImplementation = (function (baseRender, baseClear, baseClick) {

  var _createTypeSpecificInput;
  var _filterClick;
  var _clearClick;
  var _createFilterMenu;
  var _filterExpr;



  _createTypeSpecificInput = function (html, column, fieldId, value) {

      var filter = eval('MyProject.filterVariables.' + column.member);
      if (filter) {

          html.cat('<div><ol id="' + filter.ColumnName + 'Filter" 
                    class="multiselectfilter" member="' + column.member + '">');

          $.each(filter.Values, function (index, value) {
              if (index >= 0) {
                  html.cat('<li value="')
                    .cat(value.DisplayedValue)
                    .cat('">')
                    .cat(value.DisplayedValue)
                    .cat('</li>');
              }
          });

          html.cat('</ol></div>');



      } else {
          this.baseCreateTypeSpecificInput(html, column, fieldId, value);
      }
  }

  _filterClick = function (e) {
      var self = this;

      e.preventDefault();
      var $element = $(e.target);
      var column = $element.closest('.t-animation-container').data('column');
      column.filters = [];
      var hasErrors = false;

      var filter = eval('MyProject.filterVariables.' + column.member);
      if (filter) {

          $('#' + filter.ColumnName + 'Filter .ui-selected')
            .each($.proxy(function (index, input) {
              var $input = $(input);
              var value = $(input).attr('value');
              for (var i = 0; i < filter.Values.length; i++) {
                  if (filter.Values[i].DisplayedValue == value) {
                      for (var j = 0; j < filter.Values[i].Values.length; j++) {
                          column.filters.push({ 
                               operator: filter.Values[i].Values[j].Operator, 
                               value: filter.Values[i].Values[j].Value });
                      }
                  }
              }
              //column.filters.push({ operator: filter.Operator, value: value });
          }, this));

          if (!hasErrors) {
              if (column.filters.length > 0) {
                  if (self.filterClickHandlers().length > 0) {
                      var that = this;
                      $.each(self.filterClickHandlers(), function (i, handler) {
                          handler(that.filterExpr());
                      });
                  } else {
                      this.filter(this.filterExpr());
                  }
              }

              this.hideFilter();
          }

      } else {
          this.baseFilterClick(e);
      }
  }

_clearClick = function (e) {

    var self = this;

    e.preventDefault();
    var $element = $(e.target);
    var column = $element.closest('.t-animation-container').data('column');
    column.filters = null;

    var filter = eval('MyProject.filterVariables.' + column.member);
    if (filter) {
        $('#' + filter.ColumnName + 'Filter .ui-selected').removeClass('ui-selected');

        var handlers = self.filterClickHandlers();
        if (handlers.length > 0) {
            var that = this;
            $.each(handlers, function (i, handler) { handler(that.filterExpr()); });
            this.hideFilter();
        } else {
            this.filter(this.filterExpr());
        }

    } else {
        this.baseClearClick(e);
    }
}

_createFilterMenu = function (column) {
    var filter = eval('MyProject.filterVariables.' + column.member);
    if (filter) {

        var $t = $.telerik;

        var filterMenuHtml = new $t.stringBuilder();

        filterMenuHtml.cat('<div class="t-animation-container"><div class="t-filter-options t-group" style="display:none">')
                .cat('<button class="t-button t-button-icontext t-clear-button"><span class="t-icon t-clear-filter"></span>')
                .cat(this.localization.filterClear)
                .cat('</button>');

        var fieldIdPrefix = $(this.element).attr('id') + column.member;


        this.createTypeSpecificInput(filterMenuHtml, column, fieldIdPrefix, true);


        filterMenuHtml.cat('<button class="t-button t-button-icontext t-filter-button"><span class="t-icon t-filter"></span>')
                      .cat(this.localization.filter)
                      .cat('</button></div></div>');

        var $filterMenu = $(filterMenuHtml.string());

        var returnValue = $filterMenu
                    .appendTo(this.element);

        // use jquery ui selectable for multiselect filter. Make every click act as a CTRL click on this control
        $('.multiselectfilter').bind("mousedown", function (e) {
            e.metaKey = true;
        }).selectable();

        var filteredColumns = $.grep(this.columns, function (column) {
            return column.filters;
        });

        // reselect stored filter selection
        if (filteredColumns) {
            $.each(filteredColumns, function (index, column) {
                if (column.filters) {
                    $.each(column.filters, function (index, filter) {
                        var value = filter.value;
                        if (filter.operator === 'isnull')
                            value = 'NULL';
                        if (filter.operator === 'isnotnull')
                            value = 'NOT NULL';
                        $('ol[member="' + column.member + '"] li[value="' + value + '"]').addClass("ui-selected");
                    });
                }
            });
        }

        return returnValue;


    } else {
        var result = this.baseCreateFilterMenu(column);

        if (column.type == 'Date') {

            var operators = $('#MyDateFieldfirst').closest('.t-filter-options').find('.t-filter-operator');

            if (column.filters) {
                if (column.filters[0]) {
                    $('#MyDateFieldfirst').val(column.filters[0].value);

                    // deselect all operators
                    $(operators[0]).find('option').removeAttr('selected');

                    // select stored operator
                    $(operators[0]).find('option[value="' + column.filters[0].operator + '"]')
                        .attr('selected', 'selected');
                }


                if (column.filters[1]) {
                    $('#MyDateFieldsecond').val(column.filters[1].value);

                    // deselect all operators
                    $(operators[1]).find('option').removeAttr('selected');

                    // select stored operator
                    $(operators[1]).find('option[value="' + column.filters[1].operator + '"]')
                        .attr('selected', 'selected');
                }
            };
        }

        return result;
    }
}

_filterExpr = function () {
    var result = [];
    var $t = $.telerik;

    var filtersPerColumn = [];

    for (var columnIndex = 0; columnIndex < this.columns.length; columnIndex++) {
        var column = this.columns[columnIndex];
        var columnFilterStringComponents = [];
        var filterName = 'MyProject.filterVariables.' + column.member;
        var MyProjectFilter = eval(filterName);
        if (column.filters)
            if (MyProjectFilter && MyProjectFilter.Multiselect == true) {               // multiselect column

                for (var filterIndex = 0; filterIndex < column.filters.length; filterIndex++) {
                    var filter = column.filters[filterIndex];

                    var operator = filter.operator;
                    if (operator === 'isnull')
                        operator = "eq";
                    if (operator === 'isnotnull')
                        operator = "ne";

                    columnFilterStringComponents.push(new $t.stringBuilder()
                        .cat(column.member)
                        .cat('~')
                        .cat(operator)
                        .cat('~')
                        .cat(this.encodeFilterValue(column, filter.value)).string());
                }

                var columnFilterstr = columnFilterStringComponents[0];
                for (var i = 1; i < columnFilterStringComponents.length; i++) {
                    columnFilterstr = '(' + columnFilterstr + '~or~' + columnFilterStringComponents[i] + ')';
                }

                result.push(columnFilterstr);
            }
            else {          // not a multiselect column
                for (var filterIndex = 0; filterIndex < column.filters.length; filterIndex++) {
                    var filter = column.filters[filterIndex];

                    var operator = filter.operator;
                    if (operator === 'isnull')
                        operator = "eq";
                    if (operator === 'isnotnull')
                        operator = "ne";

                    columnFilterStringComponents.push(new $t.stringBuilder()
                        .cat(column.member)
                        .cat('~')
                        .cat(operator)
                        .cat('~')
                        .cat(this.encodeFilterValue(column, filter.value)).string());
                }
                result.push(columnFilterStringComponents.join('~and~'));
            }
    }

    return result.join('~and~');
}






return {
    createTypeSpecificInput: _createTypeSpecificInput,
    filterClick: _filterClick,
    clearClick: _clearClick,
    createFilterMenu: _createFilterMenu,
    filterExpr: _filterExpr
};

} ($.telerik.filtering.implementation.createTypeSpecificInput,
   $.telerik.filtering.implementation.clearClick,
   $.telerik.filtering.implementation.filterClick,
   $.telerik.filtering.implementation.createFilterMenu
));


var filteringExtensions = (function (
    origCreateTypeSpecificInput, 
    origClearClick, 
    origFilterClick, 
    origCreateFilterMenu) {
    var _filter = function (filterBy) {
        this.currentPage = 1;
        this.filterBy = filterBy;

        // restore filters that were stored in cookie
        var storedColumns = jQuery.parseJSON($.cookie('ColumnFilters'));


        for (var index in storedColumns) {
            var storedColumn = storedColumns[index];
            var member = storedColumn.member;
            var matchingColumn = $.grep(this.columns, function (column) {
                return column.member == member;
             });


            if (matchingColumn && matchingColumn[0] && !matchingColumn[0].filters) {
                matchingColumn[0].filters = storedColumn.filters;

            }
        };


        if (this.isAjax()) {
            this.$columns().each($.proxy(function (index, element) {
                $('.t-grid-filter', element).toggleClass('t-active-filter', !!this.columns[index].filters);
            }, this));

            this.ajaxRequest();
        } else {
            this.serverRequest();
        }
    }

    return {
        filter: _filter
    }
} (
));





jQuery.extend($.telerik.grid.prototype, MyCompanyFilteringBaseImplementation);

$.telerik.filtering.implementation.createTypeSpecificInput = MyCompanyFilteringImplementation.createTypeSpecificInput;
$.telerik.filtering.implementation.filterClick = MyCompanyFilteringImplementation.filterClick;
$.telerik.filtering.implementation.clearClick = MyCompanyFilteringImplementation.clearClick;
$.telerik.filtering.implementation.createFilterMenu = MyCompanyFilteringImplementation.createFilterMenu;
$.telerik.filtering.implementation.filterExpr = MyCompanyFilteringImplementation.filterExpr;
$.telerik.filtering.implementation.filter = filteringExtensions.filter;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top