Custom grid drop down filter doesn't clear selection

7 Answers 125 Views
Grid
Bob
Top achievements
Rank 2
Veteran
Iron
Bob asked on 27 Apr 2021, 05:15 PM

I have implemented a custom drop-down filter following the instructions at Reusable Custom Filter Components.

So far so good.  I select a filter

and we can see it clearly in the settings for the grid and the Category column shows it has been applied.

 

Now I select the clear filter:

But the filter for the column is not cleared.

I have modified your code to give me an emitter when the default item is selected:

import { ComponentEventEmitterInputOutput } from '@angular/core';
import { FilterServiceBaseFilterCellComponent } from '@progress/kendo-angular-grid';
@Component({
    selector: 'drop-down-list-filter',
    template: `
    <kendo-dropdownlist
      [data]="data"
      (valueChange)="onChange($event)"
      [defaultItem]="defaultItem"
      [value]="selectedValue"
      [valuePrimitive]="true"
      [textField]="textField"
      [valueField]="valueField">
    </kendo-dropdownlist>
  `
})
export class DropDownListFilterComponent extends BaseFilterCellComponent {
    @Output() clearGridFilter = new EventEmitter<any>();
    public get selectedValue(): any {
        const filter = this.filterByField(this.valueField);
        return filter ? filter.value : null;
    }
    @Input() public filterany;
    @Input() public dataany[];
    @Input() public textFieldstring;
    @Input() public valueFieldstring;
    public get defaultItem(): any {
        return {
            [this.textField]: 'All...',
            [this.valueField]: 0
        };
    }
    constructor(filterServiceFilterService) {
        super(filterService);
    }
    public onChange(valueany): void {
        if (value === 0) {
            this.removeFilter(this.valueField// remove the filter
            this.clearGridFilter.emit(this.valueField);
        } else {
            this.updateFilter({ // add a filter for the field with the value
                field: this.valueField,
                operator: 'eq',
                value: value
            })
        }
        // this.applyFilter(
        //     value === null ? // value of the default item
        //         this.removeFilter(this.valueField) : // remove the filter
        //         this.updateFilter({ // add a filter for the field with the value
        //             field: this.valueField,
        //             operator: 'eq',
        //             value: value
        //         })
        // ); // update the root filter
    }
}

 

Which then clears all filters:

  clearGridFilter(): void {
    this.ncNotesGridSettings.state.filter = {
      logic: 'and'
      filters: []
    };
  }

 

Hardly ideal.  How do I hook the Clear filter button into the DropDownListComponent and make it work predictably? 

 

 

7 Answers, 1 is accepted

Sort by
0
Martin
Telerik team
answered on 30 Apr 2021, 12:22 PM | edited on 30 Apr 2021, 12:23 PM

Hello Bob,

Thank you for the provided screenshots and code samples.

When using a DropDownList, the filter monitors the drop-down value in order to update the data results. In order the keep the selected filter value, we have opted for storing it outside of the <drop-down-list-filter> which gets destroyed when the popup is closed and the `selectedValue` is lost:

export class DropDownListFilterComponent {
  @Output() public onSelectChange = new EventEmitter();
  @Input() public selectedValue;

   ......
    
   public categoryChange(value): void {
      this.onSelectChange.emit(value);
      ...
    }
}
@Component({
  selector: "my-app",
  template: `
     ...
      <kendo-grid-column field="Category.CategoryName" title="Category">
        <ng-template
         ...
        >
          <my-dropdown-filter
            ...
            [selectedValue]="selectedValue"
            (onSelectChange)="onSelectChange($event)"
            ...
          >
          </my-dropdown-filter>
        </ng-template>
      </kendo-grid-column>
      ....
  `
})
export class AppComponent {
  ...

  onSelectChange(e) {
    this.selectedValue = e;
  }
}

The reason why the `Clear` button is not performing as expected in combination with a drop-down list is that when clicked this condition is never hit as the 'Clear' button does not trigger the valueChange of the DropDownList, instead only filterChange/dataStateChange event is emitted:

 if (value === 0) {
            this.removeFilter(this.valueField) // remove the filter
            this.clearGridFilter.emit(this.valueField);
}

What can be done instead of extending the `BaseFilterCellComponent`, pass the Grid's filter service instance to the custom <drop-down-list-filter> component. Then bind both the `valueField` to the CategoryName field:

 


The column filed is also passed to the custom drop-down filter component in order to be used when applying the filter on `categoryChange`.

For your convenience, we have put up a working demo in StackBlitz:

https://stackblitz.com/edit/angular-kvbqqy-ewsf2p

I hope this helps.

Regards,


Martin
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Bob
Top achievements
Rank 2
Veteran
Iron
answered on 04 May 2021, 10:04 AM

Hi Martin,

Using your implementation I'm not able to filter at all due to an error in the browser:

Here's my template:

      <ng-template *ngIf="col.field === 'noteCategory'"
        kendoGridFilterMenuTemplate
        let-column="column"
        let-filter
        let-filterService>
        <drop-down-list-filter
          [filter]="filter"
          [filterService]="filterService"
          [data]="ncNoteCategories"
          textField="noteCategory"
          valueField="noteCategory"
          [selectedValue]="selectedCategory"
          (onSelectChange)="onSelectCategoryChange($event)"
          [field]="col.field">
        </drop-down-list-filter>
      </ng-template>

 

And here's my component:

import { ComponentEventEmitterInputOutput } from '@angular/core';
import { FilterService } from '@progress/kendo-angular-grid';
@Component({
    selector: 'drop-down-list-filter',
    template: `
    <kendo-dropdownlist
      [data]="data"
      (valueChange)="onChange($event)"
      [defaultItem]="defaultItem"
      [value]="selectedValue"
      [valuePrimitive]="true"
      [textField]="textField"
      [valueField]="valueField">
    </kendo-dropdownlist>
  `
})
export class DropDownListFilterComponent {
    @Output() public onSelectChange = new EventEmitter();
    @Input() public selectedValue;
  
    @Input() public filterany;
    @Input() public dataany[];
    @Input() public textFieldstring;
    @Input() public valueFieldstring;
    @Input() public filterServiceFilterService;
    @Input() public fieldstring;
  
    public get defaultItem(): any {
      return {
        [this.textField]: "Select item...",
        [this.valueField]: "Select item..."
      };
    }
  
    public onChange(value): void {
      this.onSelectChange.emit(value);
      this.filterService.filter({
        filters: [
          {
            field: this.field,
            operator: "eq",
            value: value
          }
        ],
        logic: "or"
      });
    }
}

 

Any pointers gratefully received...
Cheers,
Bob

Bob
Top achievements
Rank 1
Iron
Iron
Iron
commented on 06 May 2021, 04:17 PM

Any move on this?
0
Dimiter Madjarov
Telerik team
answered on 07 May 2021, 07:49 AM

Hi Bob,

The provided sample code looks correct and I was unable to identify the root cause of the problem. Would it be possible to send us a runnable example of the same or update the one provided by my colleague Martin, so we could inspect it locally and assist further?

I am looking forward to hearing from you.

Regards,
Dimiter Madjarov
Progress Telerik

Тhe web is about to get a bit better! 

The Progress Hack-For-Good Challenge has started. Learn how to enter and make the web a worthier place: https://progress-worthyweb.devpost.com.

0
Bob
Top achievements
Rank 1
Iron
Iron
Iron
answered on 11 May 2021, 02:17 PM | edited on 11 May 2021, 02:18 PM

Hi Dimiter,

No matter what I try here the implementation of the filter service does not seem correct.

this.filterService.filter({
      filters: [
        {
          field: this.field,
          operator: "eq",
          value: value
        }
      ],
      logic: "or"
    });

 

As soon as I hit the drop down component the filter service has no method for filter just the actual filter values.

 

I have set my grid up as follows:

setGridSettings(): GridSettings {
    const today = new Date();
    let nextMonth = new Date(moment(today).add(1'week').toString());
    let filterCompositeFilterDescriptor;
    filter = {
      logic: 'and',
      filters: [{
        field: 'nextReviewTime',
        operator: 'lte',
        value: nextMonth
      }]
    }
    return {
      state: {
        skip: 0,
        take: 50,
        // Initial filter descriptor
        filter: filter,
        group: [],
        sort: []
      },
      columnsConfig: [{... code removed for brevity...

 

And at the head of my grid component page I have:

public ncNotesGridSettingsGridSettings = this.setGridSettings();

 

It's not a show-stopper - I can run with standard filters but it's just annoying when something doesn't work and you've spent a few hours on it.
Any ideas why the invocation of the filterservice does not include the filter command?

Cheers,
Bob

 

 

0
Martin
Telerik team
answered on 14 May 2021, 07:49 AM

Hello Bob,

The following error:

typically appears when the filterService is initialized like this:

 <ng-template
          kendoGridFilterMenuTemplate
          let-column="column"
          let-filter="filter"
          let-filterService
        >
          <my-dropdown-filter
            [filter]="filter"
            [filterService]="filterService"
            [data]="distinctCategories"
          ...
          >
          </my-dropdown-filter>
        </ng-template>

Please make sure that the filterService is assigned as demonstrated in this section of our documentation:

 <ng-template
          kendoGridFilterMenuTemplate
          let-column="column"
          let-filter="filter"
          let-filterService="filterService"
        >
          <my-dropdown-filter
            [filter]="filter"
            [filterService]="filterService"
            [data]="distinctCategories"
          ...
          >
          </my-dropdown-filter>
        </ng-template>
Regards,
Martin
Progress Telerik

 

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Bob
Top achievements
Rank 1
Iron
Iron
Iron
answered on 16 May 2021, 11:25 AM | edited on 16 May 2021, 11:29 AM

Hi Martin,

Still having problems on the "Clear" button for the filter and believe I may problems in setup.  Spent many hours on this...
I'm persevering because I can see many different grids I can use this on if I can get it to work predictably.
Your code makes the assumption that there will only be one filter and it can therefore be cleared if the Clear button is selected.
My grid starts with a filter set in a state object.
Let me explain and hopefully you can either see the mistake or point me the right direction.

My initial grid state is set up with this code:

setGridSettings(): GridSettings {
    const today = new Date();
    let nextWeek = new Date(moment(today).add(1'week').toString());
    let filterCompositeFilterDescriptor;
    filter = {
          logic: 'and',
          filters: [
            {
              field: "nextReviewTime",
              operator: "lte",
              value: nextWeek
            }
          ]
        };
    return {
      state: {
        skip: 0,
        take: 50,
        // Initial filter descriptor
        filter: filter,
        group: [],
        sort: []
      },
      columnsConfig: [{... code removed for brevity...

 

My grid is declared as below:

  <kendo-grid #ncNotesGrid
    [data]="ncNotesGridSettings.gridData"
    [pageSize]="ncNotesGridSettings.state.take"
    [skip]="ncNotesGridSettings.state.skip"
    [sort]="ncNotesGridSettings.state.sort"
    [filter]="ncNotesGridSettings.state.filter"
    [kendoGridSelectBy]="'id'"
    [selectedKeys]="selectedIds"
    [scrollable]="'none'"
    [sortable]="allowUnsorttruemode'multiple' }"
    [pageable]="true"
    filterable="true"
    [columnMenu]="{  columnChooserfalse  }"
    [resizable]="true"
    [reorderable]="true"
    [resizable]="true"
    [groupable]="showFootertrue }"
    [group]="ncNotesGridSettings.state.group"
    [selectable]="true"
    (dataStateChange)="dataStateChange($event)"
    (filterChange)="onNoteCategoryFilterChange($event)"
    [rowClass]="rowCallback">

 

My drop down template:

      <ng-template *ngIf="col.field === 'noteCategory'"
        kendoGridFilterMenuTemplate
        let-column="column"
        let-filter="filter"
        let-filterService="filterService">
        <drop-down-list-filter [filter]="filter"
          [filterService]="filterService"
          [data]="ncNoteCategories"
          textField="noteCategory"
          valueField="ncNoteCategoryId"
          [selectedValue]="selectedValue"
          (onSelectChange)="onSelectNoteCategoryChange($event)"
          [field]="'ncNoteCategoryId'">
        </drop-down-list-filter>
      </ng-template>

 

And the onChange method in the component:

  public onChange(value): void {
    this.onSelectChange.emit(value);
    this.filterService.filter({
      filters: [
        {
          field: this.field,
          operator: "eq",
          value: value
        }
      ],
      logic: "or"
    });
  }

 

Everything works fine with the initial selector for the drop down.  It's when I come to select the "Clear" button that I seem to have problems.  Let me show you.
The Clear button hits the dataStateChanged method which is great:

 

and goes on to hit the method fired by the emission from the component.

Here we can see the new filters object has been placed as a nested filters array within the initial state.filter.filters array.
I'm very close now but I need to find a way to find the filter on "ncNoteCategoryId" and remove it from the filters array.
The whole implementation has me scratching my head, I have even tried passing the state of the grid down to the component and tried to modify directly there but the same thing happens.  Should I be cloning the state.filter object and emptying and then replacing with the clone?  It's all a bit confusing as to how I'm getting a nested filters object as an array within the state.filter.filters array.

I'm hoping you can see something clearly wrong and point me in the right direction for finding and removing the drop-down filter after I press the "Clear" button.

Cheers,
Bob

 

 

 

0
Martin
Telerik team
answered on 19 May 2021, 11:56 AM

Hi Bob,

Thank you for the code snippets.

As I mentioned earlier in this thread, the reason why the `Clear` button is not performing as expected is that when it's clicked it doesn't trigger the valueChange of the DropDownList, instead only filterChange/dataStateChange event of the Grid is emitted.

The most straightforward approach of removing the filter in this scenario, is to utilize kendoGridBinding directive instead of data, and leave the process of removing the filter on the directive:

 <kendo-grid
      [kendoGridBinding]="gridData"
      filterable="menu"
      [height]="400"
      (filterChange)="onFilterChange($event)"
    >

https://stackblitz.com/edit/angular-kvbqqy-ewsf2p

Regards,
Martin
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
Grid
Asked by
Bob
Top achievements
Rank 2
Veteran
Iron
Answers by
Martin
Telerik team
Bob
Top achievements
Rank 2
Veteran
Iron
Dimiter Madjarov
Telerik team
Bob
Top achievements
Rank 1
Iron
Iron
Iron
Share this question
or