Fluent UI DetailsList - Is there a way to add filters to each column
Asked Answered
Q

2

5

I am using Fluent UI DetailsList. My table looks like below: enter image description here

I need filters below every column (text or drop-down) as shown below: enter image description here

Please let me know if this is possible? Or maybe a way to display custom header (using html) ?

Quenelle answered 15/4, 2020 at 14:10 Comment(7)
The link you provided includes a demo with filter functions I guessLev
I know that. I do not want a common search box but need a way to add filters under every column.Quenelle
I'm working on the same implementation now, did you come up with a solution? There is an event to trigger a context menu, I'm just trying to work out the best/right way to put the ContextMenu inside the header...Woodworker
No. Did not proceed after this.Quenelle
10-4, I'm on it... will report back when I get it working.Woodworker
That would be great. Thanks.Quenelle
Solution below... slight variation from what you were looking for, but might be enough to get you in the right direction.Woodworker
W
16

This actually turned out to be easier than I thought it'd be...

If you're ok with clicking the column header to reveal the choices (vs having the dropdown directly under the title) then this can be achieved using the ContextualMenu component in conjunction with DetailsList. I got it working by tweaking from the variable row height example in the official docs: https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/variablerowheights.

Add a ContextualMenu underneath your DetailsList:

<DetailsList
    items={items}
    columns={columns}
/>
{this.state.contextualMenuProps && <ContextualMenu {...this.state.contextualMenuProps} />}

Inside your column definition, set the hasDropdown action so the user gets a UI indicator that they can/should click the header, and call a contextMenu method (note I'm using onColumnContextMenu as well as onColumnClick so it doesn't matter if they left or right click the header:

{
    key: 'dept',
    name: 'Department',
    fieldName: 'dept',
    minWidth: 125,
    maxWidth: 200,
    onColumnContextMenu: (column, ev) => {
        this.onColumnContextMenu(column, ev);
    },
    onColumnClick: (ev, column) => {
        this.onColumnContextMenu(column, ev);
    },
    columnActionsMode: ColumnActionsMode.hasDropdown,
}

When the onColumnContextMenu method gets invoked, we need to build the context menu properties that will get consumed by the ContextualMenu component. Note the dismissal method as well, which clears out the state so the menu is hidden.

private onContextualMenuDismissed = (): void => {
    this.setState({
        contextualMenuProps: undefined,
    });
}

private onColumnContextMenu = (column: IColumn, ev: React.MouseEvent<HTMLElement>): void => {
    if (column.columnActionsMode !== ColumnActionsMode.disabled) {
        this.setState({
            contextualMenuProps: this.getContextualMenuProps(ev, column),
        });
    }
};

Finally, inside of getContextualMenuProps you need to determine what the options should be for the user to click. In this example, I'm simply giving sort options (you'll need to add an onClick handler to actually do something when the user clicks the item), but I'll use the column to determine what those items should actually be and paint the filters into the items collection so the user can select one to filter.

private getContextualMenuProps = (ev: React.MouseEvent<HTMLElement>, column: IColumn): IContextualMenuProps => {
    const items: IContextualMenuItem[] = [
        {
            key: 'aToZ',
            name: 'A to Z',
            iconProps: { iconName: 'SortUp' },
            canCheck: true,
            checked: column.isSorted && !column.isSortedDescending,
        },
        {
            key: 'zToA',
            name: 'Z to A',
            iconProps: { iconName: 'SortDown' },
            canCheck: true,
            checked: column.isSorted && column.isSortedDescending,
        }
    ];

    return {
        items: items,
        target: ev.currentTarget as HTMLElement,
        directionalHint: DirectionalHint.bottomLeftEdge,
        gapSpace: 10,
        isBeakVisible: true,
        onDismiss: this.onContextualMenuDismissed,
    }
}

Note the target on the ContextualMenuProps object, which is what tells the ContextualMenu where to lock itself onto (in this case, the column header that you clicked to instantiate the menu.

Woodworker answered 28/5, 2020 at 16:28 Comment(3)
can you elaborate a little bit more how do you enter the html elements, like input tag in the context menu? Your example above does not explain how to accomplish that.Numinous
Burre, the IContextualMenuItem has an OnRender property. You can render whatever you like in there, like a TextField and a Button to sert the filterDuckett
Follow up regarding this, where will I insert the part that adds a filter object on the contextual menu dropdown?Kalinda
U
1

Detail list filter for each column without context menu -

https://codesandbox.io/s/rajesh-patil74-jzuiy?file=/src/DetailsList.CustomColumns.Example.tsx

For instance - Providing filter in text field associated with each column will apply filter on color column.

Uncinariasis answered 7/9, 2021 at 10:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.