Closed Xizario closed 6 years ago
Сustom filter component for inside the filter cell would be nice option.
Please at the custom filter component, it would help many user who want to create something that is not Standard.
in my mind the custom component for the filter cell itself is the most flexible option.
A custom component to the cell would have such props as interface when the grid instantiate it.
interface FilterCellProps {
field: any;
filterType: 'text' | 'numeric' | 'boolean' | 'date';
value: any;
operator: string;
onChange: (event: {
value: any,
operator: string,
syntheticEvent: React.SyntheticEvent<any>
}) => void;
}
Then the user will be able to create class like
class MyFilterCell extends React.Component<FilterCellProps, {}>{ /* custom logic here */}
Add pass it as custom cell for his columns:
<Column field="someField" filterCell={MyFilterCell} />
The pros:
The cons:
To avoid the cons, I am thinking of adding additional render prop to the Grid, that will be called for each filterCell that is about to be rendered. And this gives some more options for customization:
<Grid
...
filterCellRender={(cell: JSX.Element | null, props: FilterCellProps) => {
// return the original cell as it would be rendered without modification.
return cell;
// or clone and modify
return cell && React.cloneElement(
cell,
{
...cellEditEvent,
someAdditionalProps
},
cell.props.children
//or some other children
);
// or change it entierly
return (<EntierlySomethingDifferent {...props}/>);
}}
>
Ok, now I got yout point. Because we dont use automatically generated columns i didnt see this before. For me, implementing the "fully working cell" ist not that big of a deal.
I guess the FilterCellProps in the second snippet are the same as listed above? In that case i dont have any access to the column itself to make a decision what kind of filter i need to render. The datatype alone is not sufficient.
To stay consistent in the column definition defining the filterCell in the same way as the customCell would be the best. If you want maximum fleixibility for all upcoming scenarions you could add the filterCellRender option on the grid and each column. The one on the colum would override the other.
We plan to add both ways of customization. So you could use one of them, or both of them at the same time.
First if there is filterCell
defined for the column, it will be instantiated. This is the MyFilterCellA
in the example below.
If you have set filterCellRender
, it will be passed through the props of the grid to the columns. And they could either use it, or ignore it, see MyFilterCellB
.
If filterCellRender
is set, it will be called for our built-in filters.
class MyFilterCellA extends GridFilterCell {
render() {
return (
<div>
my filter cell <b>A</b>
<input
value={'VAL: ' + this.props.value}
/>
</div>
);
}
}
class MyFilterCellB extends GridFilterCell {
render() {
const myRendering = (
<div className="k-filtercell">
My filter cell <b>B</b>
<DropDownList />
</div>
);
if (this.props.render) {
return this.props.render(myRendering, this.props);
}
return myRendering;
}
}
function cellRenderer(cell: any, props: GridFilterCellProps) {
if (props.field === 'UnitsInStock') {
// customize by field
return cell;
}
const children = cell.props.children;
return React.cloneElement(
cell,
{
...cell.props
},
[
cell.props.children,
(<div key={0}><input value={'OP:' + props.operator} /></div>)
]
);
}
<Grid
data={this.state.data}
filterable={true}
filter={this.state.filter}
filterChange={this.filterChange}
filterCellRender={cellRenderer}
>
<Column field="ProductName" title="A" filterCell={MyFilterCellA} />
<Column field="ProductName" title="B" filterCell={MyFilterCellB} />
<Column field="ProductName" title="built-in cell" />
<Column width="200px" field="UnitsInStock" title="clear built-in" />
</Grid>
And this is without the filterCellRenderer
<Grid
data={this.state.data}
filterable={true}
filter={this.state.filter}
filterChange={this.filterChange}
>
<Column field="ProductName" title="A" filterCell={MyFilterCellA} />
<Column field="ProductName" title="B" filterCell={MyFilterCellB} />
<Column field="ProductName" title="built-in cell" />
<Column width="200px" field="UnitsInStock" title="clear built-in" />
</Grid>
This looks fine to me. :) But i have a question about the current interface. I have added a screenshot of our version, based on the jquery library. There you can see exactly the filter that i need to build. It is based on your multi-checkbox-filter with some added sugar. We use a configured delimiter to split the values if needed. (ignore the fact that its based on the headerrow and not the filterrow)
To make this work we need a CompositeFilterDescripter - same as in the GridFilterChangeEvent & GridFilterRowProps - for the initial value and the onChangeEvent that is limited to one field. The second part i am unsure about: how can i access the datasource to get the distinct values of my current resultset?
@jannhofman, I would like to keep the filterCellProps
as little as possible, passing all grid data to them, and giving them opportunity to return complex filter will break some separation of concern and encapsulation principles.
However, on application level, you could pass your data to your custom cells, by using a higher-order component.
<Column field="ProductName" filterCell={filterCellWithData(products, this.state.data)} />
function filterCellWithData(data: any[], currentData: any[]) {
return class MyFilterCellB extends GridFilterCell {
render() {
const modifiedData = currentData.slice();
modifiedData.push({ ProductName: '' });
return (
<div >
<DropDownList
textField="ProductName"
defaultValue="ProductName"
data={data}
onChange={(e) => {
this.props.onChange({
value: e.target.value.ProductName,
operator: 'eq',
syntheticEvent: e.syntheticEvent
});
}}
/>
<DropDownList
textField="ProductName"
defaultValue="ProductName"
data={modifiedData}
onChange={(e) => {
this.props.onChange({
value: e.target.value.ProductName,
operator: 'contains',
syntheticEvent: e.syntheticEvent
});
}}
/>
</div>
);
}
};
}
I have just placed two DropDown-s into the filter menu to give you and example, one is bound to all data, and the other only to the filtered(same as the grid) with additional empty item, see it in action.
And of course instead of the DropDown you could place listbox/multiselect and/or build complex descriptor and return it using callback passed in the filterCellWithData.
To be honest, i am new to react, never typed a line of code so far. Some of my develepoers are laughing right now - about me not knowing this pattern. :) You are right, with a HOC we can solve our needs. Thx for yout patience.
In the latest dev version @progress/kendo-react-grid@0.5.0-dev.201804041130
we have added
filterCellRender property of the grid as well as filterCell per each Column
An example of how to use the cellRender
prop of the grid in general can be seen here: https://www.telerik.com/kendo-react-ui-develop/components/grid/editing/editing-in-cell/
Same approach is applicable for the filterCellRender
as well for modifying the currently built-in cells.
An example with entirely custom filterCell
per column can be seen here:
https://www.telerik.com/kendo-react-ui-develop/components/grid/data-operations/filtering/#toc-custom-filter-cell
If this is resolves the issue, it will be closed when we publish next official version, so give it a try using the development builds.
Available in v0.5.0
I suggest to add an option to make the filter look like this one (from the kendo ui JQuery). An icon beside the title :
Agree with @ZiedHf , it will be awesome if we have for example filterDropDown
same as filterCell
, as per Grid Row/Cell editing, you are providing different approachs for editing (inline, modal, custom forms ..etc). The same thing for filters will be cool
@ZiedHf Wonderful idea, something i miss in the current react version too, but i think that create a new issue is a better solution, because this one is closed.
Currently there are only 5 options for the filter cells:
text
,boolean
,numeric
,date
and disabled filtering for the column.The user should be able to customize the filter cells similar to how he can define custom Cells for the data rows.
Possible solutions: