How to combine these two filter objects?

10 posts, 2 answers
  1. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 26 Aug 2014 Link to this post

    I've got a custom dropdown multi-select widget in one of my grid column headers, "Status". Each of the three statuses that can be chosen represent a group of statuses to show together when one of the dropdown values is selected. I need to be sure not to wipe out any current statuses that might be applied to my grid from the other columns. 

    For example, I retrieve the current filters like so:

    var grid = $('#accountsGrid');
    var currentFilters = grid.data('kendoGrid').dataSource.filter();

    Which gives me this object:
    {"filters":[{"field":"name","operator":"contains","value":"JOHNSON"},{"field":"city","operator":"contains","value":"MILWAUKEE"},{"field":"state","operator":"eq","value":"WI"}],"logic":"and"}

    I then build my status filter, resulting in this object:
    {"logic":"or","filters":[{"field":"status","operator":"eq","value":"A"},{"field":"status","operator":"eq","value":"G"},{"field":"status","operator":"eq","value":"O"},{"field":"status","operator":"eq","value":"P"},{"field":"status","operator":"eq","value":"S"}]}

    I then combine them together and apply to the datasource:

    var newFilters = { logic: "and", filters: [] };
    newFilters.filters.push(currentFilters);
    newFilters.filters.push(statusFilters);
    grid.data('kendoGrid').dataSource.filter(newFilters);

    newFilters object:
    {"logic":"and","filters":[{"filters":[{"field":"name","operator":"contains","value":"JOHNSON"},{"field":"city","operator":"contains","value":"MILWAUKEE"}],"logic":"and"},{"logic":"or","filters":[{"field":"status","operator":"eq","value":"A"},{"field":"status","operator":"eq","value":"G"},{"field":"status","operator":"eq","value":"O"},{"field":"status","operator":"eq","value":"P"},{"field":"status","operator":"eq","value":"S"}]}]

    Here's my issue: when status gets changed again, I need to get the current filters (which will be the above value), but I need to parse out any existing status filters, so I can rebuild with the new criteria, without losing any other filter information. I think it's the nested result from combining filters that's making it so difficult, but I also think someone with experience transversing these kind of objects would probably be able to do it in their sleep!





  2. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 26 Aug 2014 in reply to Hunter Link to this post

    Oops, sorry for the misleading thread name...when I first started this post, I was having issues with the combining of objects!
  3. Kendo UI is VS 2017 Ready
  4. Answer
    Daniel
    Admin
    Daniel avatar
    2117 posts

    Posted 28 Aug 2014 Link to this post

    Hello,

    You can use the following logic(used by the filter menu) to remove the filters for a field and preserve the other filters:
    function removeFiltersForField(expression, field) {
        if (expression.filters) {
            expression.filters = $.grep(expression.filters, function(filter) {
                removeFiltersForField(filter, field);
                if (filter.filters) {
                    return filter.filters.length;
                } else {
                    return filter.field != field;
                }
            });
        }
    }
    var filter = that.dataSource.filter() || { filters:[], logic: "and" };
     
    removeFiltersForField(filter, "status");

    I created an example that demonstrates this approach.


    Regards,
    Daniel
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  5. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 28 Aug 2014 in reply to Daniel Link to this post

    Exactly what I was looking for! Thanks, Daniel.
  6. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 29 Aug 2014 in reply to Daniel Link to this post

    Daniel,

    I was hoping you could help with another issue on a similar subject, that is with my kendoMultiSelectBox in my column header of a grid. Everything works great now that I'm manually manipulating the filter object when checkbox selections are made. However, I disabled sorting on this column due to the sort event firing every time the dropdown was opened, which makes sense because my dropdown element is getting created within the "k-link" anchor tag that wraps the column header waiting for a click to fire sorting. Now, the users want sorting AND the dropdown and I'm trying to figure out a way for them to have their cake and eat it too!

    First, here's my column definition:
    {
        field: 'status',
        title: 'Status',
        width: 130,
        filterable: false,
        sortable: false,
        headerTemplate: '<input id="statusMultiSelect" style="width:90px" />',
        template: function(dataItem) {
            return dataItem.statusDesc;
        }
    },

    Here's my widget:
    var statusDropdown = $('#statusMultiSelect');
    statusDropdown.kendoMultiSelectBox({
        dataTextField: 'text',
        dataValueField: 'value',
        dataSource: [{"value":"AC","text":"Active"},{"value":"OH","text":"On Hold"},{"value":"CL","text":"Closed"}],
        showSelectAll: true,
        //autoBind: false,
        emptySelectionLabel: "Status",
        selectionChanged: function() {
        applyStatusFilter(this.value());
        }
    });

    Is there a way I can enable filtering, yet keep it from firing when clicking within my dropdown box? I've already set my column width a little bigger than my widget, so there's room for a user to click inside the column header box without being in the dropdown. I was hoping somehow I could make this the only area that would fire the sort event.
  7. Answer
    Daniel
    Admin
    Daniel avatar
    2117 posts

    Posted 02 Sep 2014 Link to this post

    Hi again,

    I can suggest either to move the multiselectbox to the toolbar or to stop the click event propagation in order to prevent sorting when clicking on the widget e.g.
    var statusDropdown = $('#statusMultiSelect');
    statusDropdown.kendoMultiSelectBox({
       ...
    });
    statusDropdown.data("kendoMultiSelectBox").wrapper.on("click", function (e) {
        e.stopPropagation();
    });


    Regards,
    Daniel
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  8. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 02 Sep 2014 in reply to Daniel Link to this post

    Thanks Daniel...I used the stop propagation angle and it worked fine. One odd thing I just noticed is that when I change the column setting to "sortable: true", it causes the down arrow in my dropdown to disappear. It looks like I lose the class on the second span on the right hand-side of the dropdown that displays the down arrow, but as soon as I disable sorting it comes back. Is there an issue with displaying down arrows both in the dropdown and in the column (when it's clicked to enable sorting)?
  9. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 02 Sep 2014 Link to this post

    I tried the following JQuery command after the dropdown is created:

    $("span.k-select").html('<span class="k-icon k-i-arrow-s"></span>');

    But my newly rendered down arrow only appears for a flicker. I suspect that when sorting is enabled, it's removing all arrow related classes from all spans within my header, so it can then decide if it should display up, down, or none. 

    Here's the generated HTML when column sorting is disabled:

    <th class="k-header" data-title="Status" data-field="status" role="columnheader">
      <span class="k-widget k-dropdown k-header" style="width: 90px;" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="statusMultiSelect_listbox" aria-disabled="false" aria-readonly="false" aria-busy="false">
        <span class="k-dropdown-wrap k-state-default custom-multiselect-summary-empty" unselectable="on">
          <span class="k-input" unselectable="on">Status</span>
          <span class="k-select" unselectable="on">
            <span class="k-icon k-i-arrow-s"></span>
          </span>
        </span>
        <input id="statusMultiSelect" style="width: 90px; display: none;" data-role="multiselectbox">
      </span>
    </th>

    And here's the HTML with sorting enabled and activated in my column:

    <th class="k-header" data-title="Status" data-field="status" role="columnheader" data-role="sortable" style="background-color: rgb(211, 211, 211);" data-dir="desc" aria-sort="descending">
      <a class="k-link" href="#">
        <span class="k-widget k-dropdown k-header" style="width: 90px;" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="statusMultiSelect_listbox" aria-disabled="false" aria-readonly="false" aria-busy="false">
          <span class="k-dropdown-wrap k-state-default custom-multiselect-summary-empty" unselectable="on">
            <span class="k-input" unselectable="on">Status</span>
            <span class="k-select" unselectable="on"></span>
          </span>
          <input id="statusMultiSelect" style="width: 90px; display: none;" data-role="multiselectbox">
        </span>
        <span class="k-icon k-i-arrow-s"></span>
      </a>
    </th>


  10. Daniel
    Admin
    Daniel avatar
    2117 posts

    Posted 04 Sep 2014 Link to this post

    Hi,

    Indeed, since the same class is used to display the sort direction on the header, the arrow will be removed. The approach with adding the element after the initialization will not work because it will be removed again after the data is bound. You will need to use the dataSource change event in order to add the element again e.g.
    var statusDropdown = $('#statusMultiSelect');
    statusDropdown.kendoMultiSelectBox({
        ...
    });
     
    var grid = $('#accountsGrid').data("kendoGrid");
    grid.dataSource.bind("change", function () {
        statusDropdown.data("kendoMultiSelectBox").wrapper.find("span.k-select").html('<span class="k-icon k-i-arrow-s"></span>');
    });


    Regards,
    Daniel
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  11. Hunter
    Hunter avatar
    24 posts
    Member since:
    Jan 2014

    Posted 04 Sep 2014 in reply to Daniel Link to this post

    Thanks again, Daniel. I actually just chose to add my own icon to the dropdown, to help differentiate between the dropdown and the sorting arrow:

    $("span.k-select").html('<span id="dropDownArrow"></span>');
    #dropDownArrow {
        background:url(/images/module/home/down_arrow-16.png);
        background-repeat: no-repeat;
        margin-top:5px;
        height:16px;
        display: block;
    }

Back to Top
Kendo UI is VS 2017 Ready