ugly-tan
ugly-tan3h ago

Select in ant dropdown filter

I'm building a custom table column dropdown filter using ant design components that uses a <Select> component as the filter input, and I'm having trouble with it rendering correctly. Initially, it displays all the options and, when an option is selected, it filters correctly, but subsequently, when I open the <DropdownFilter> again, the select displays the internal value of the selected option, not the label. Here's the relevant code: <FilterDropdown {...props}> <Select placeholder={filterPrompt} options={columnProps.filterProps?.enumerations} allowClear value={props.selectedKeys?.[0] || undefined} onChange={(val) => { props.setSelectedKeys(val ? [val] : []); props.confirm(); }} /> </FilterDropdown> How can I get the select to always render the label of the selected option?
8 Replies
kapa.ai
kapa.ai3h ago
Hi @Hypnotic Meat. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The issue you're experiencing—where the Ant Design <Select> in a <FilterDropdown> shows the internal value (e.g., an ID) instead of the label after filtering or re-opening—is a known challenge when the value types (string vs. number) or mapping between value and label are not handled correctly. This is especially common when the filter value comes from the URL or is synced with location, as Ant Design always normalizes selected keys to strings, but your options may use numbers or other types as values. Solution: Use the mapValue prop in <FilterDropdown> to normalize value types Refine provides a mapValue prop on <FilterDropdown> to help you map the selected keys (which are always strings from Ant Design) back to the correct type (e.g., number) expected by your options. This ensures that the <Select> component can correctly match the value to its label and display the label instead of the raw value. Here's how you can update your code:
<FilterDropdown
{...props}
mapValue={(selectedKeys) => selectedKeys.map((i) => parseInt(i.toString()))}
>
<Select
placeholder={filterPrompt}
options={columnProps.filterProps?.enumerations}
allowClear
value={props.selectedKeys?.[0] || undefined}
onChange={(val) => {
props.setSelectedKeys(val ? [val] : []);
props.confirm();
}}
/>
</FilterDropdown>
<FilterDropdown
{...props}
mapValue={(selectedKeys) => selectedKeys.map((i) => parseInt(i.toString()))}
>
<Select
placeholder={filterPrompt}
options={columnProps.filterProps?.enumerations}
allowClear
value={props.selectedKeys?.[0] || undefined}
onChange={(val) => {
props.setSelectedKeys(val ? [val] : []);
props.confirm();
}}
/>
</FilterDropdown>
- The mapValue function converts the string keys back to numbers (or whatever type your option values are). - This ensures that the <Select> component can find the correct label for the selected value and display it properly. Reference Example from Refine Docs:
<FilterDropdown
{...props}
mapValue={(selectedKeys) => selectedKeys.map((i) => parseInt(i.toString()))}
>
<Select
style={{ minWidth: 200 }}
mode="multiple"
placeholder="Select Category"
{...categorySelectProps}
/>
</FilterDropdown>
<FilterDropdown
{...props}
mapValue={(selectedKeys) => selectedKeys.map((i) => parseInt(i.toString()))}
>
<Select
style={{ minWidth: 200 }}
mode="multiple"
placeholder="Select Category"
{...categorySelectProps}
/>
</FilterDropdown>
See the official documentation for more details and examples. Why this happens:
Ant Design's Table filter system always serializes filter values as strings (especially when syncing with the URL), but your <Select> options may use numbers or other types. Without mapping, the <Select> can't match the value to the label, so it just displays the raw value. Summary:
Add the mapValue prop to your <FilterDropdown> and ensure it converts the selected keys to the correct type for your <Select> options. This will ensure the label is always displayed correctly, even after filtering or page reloads. FilterDropdown mapValue property documentation ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3h ago
<@224018850419572736> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
ugly-tan
ugly-tanOP2h ago
@kapa.ai changing it to onSelect fixed my issue, thanks. Now I have a different problem with a <DatePicker> filter. Consider the following code: <FilterDropdown {...props}> <DatePicker placeholder={filterPrompt} /> </FilterDropdown> When I initially filter, I can see that the url parameter is correctly passing the selected date. However, when I open the filter dropdown subsequently, I get the error: "date.isValid is not a function". What am I doing wrong?
kapa.ai
kapa.ai2h ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The error "date.isValid is not a function" when re-opening a <DatePicker> filter in a <FilterDropdown> is a known issue that occurs because, when the filter value is restored from the URL (with syncWithLocation enabled), it is a string rather than a Dayjs object. Ant Design's <DatePicker> expects a Dayjs object as its value, so passing a string causes this error. How to fix:
You need to use the mapValue prop on <FilterDropdown> to convert the string value (from the URL or filter state) back into a Dayjs object before passing it to <DatePicker>. Here’s how you can do it:
import dayjs from "dayjs";

<FilterDropdown
{...props}
mapValue={(selectedKeys, event) => {
if (event === "value") {
// Convert string to Dayjs object for DatePicker
return selectedKeys.map((key) => (typeof key === "string" ? dayjs(key) : key));
}
// For onChange, just return the ISO string
return selectedKeys;
}}
>
<DatePicker placeholder={filterPrompt} />
</FilterDropdown>
import dayjs from "dayjs";

<FilterDropdown
{...props}
mapValue={(selectedKeys, event) => {
if (event === "value") {
// Convert string to Dayjs object for DatePicker
return selectedKeys.map((key) => (typeof key === "string" ? dayjs(key) : key));
}
// For onChange, just return the ISO string
return selectedKeys;
}}
>
<DatePicker placeholder={filterPrompt} />
</FilterDropdown>
This approach ensures that: - When the filter value is restored from the URL (as a string), it is converted to a Dayjs object for the <DatePicker>. - When the value changes, it is stored as a string (ISO format), which is compatible with URL sync and Refine’s filtering. Reference:
This pattern is described in the Refine documentation for handling date filters with <FilterDropdown>, especially when using syncWithLocation or restoring filter values from the URL. The same principle is used for <DatePicker.RangePicker> with the rangePickerFilterMapper utility, but for a single date, you can use a similar mapping function as shown above.
See the official documentation for details and examples. Summary:
Always use mapValue to convert string values from the filter state or URL into Dayjs objects before passing them to <DatePicker>. This will prevent the "date.isValid is not a function" error and ensure your filter works correctly after page reloads or when restoring from the URL. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2h ago
<@224018850419572736> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
ugly-tan
ugly-tanOP2h ago
@kapa.ai when I add the mapValue function, it errors out that selectedKeys.map is not a function. When I log it to console, I can see that selectedKeys is a dayjs object
kapa.ai
kapa.ai2h ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You're encountering this error because, depending on the event and the state of the filter, selectedKeys can be either an array or a single value (such as a Dayjs object or a string). The .map function only works on arrays, so if selectedKeys is not an array, calling .map will throw an error. How to handle this: You should check the type of selectedKeys before calling .map. If it's not an array, wrap it in an array or handle it accordingly. Here’s an example pattern:
import dayjs from "dayjs";

<FilterDropdown
{...props}
mapValue={(selectedKeys, event) => {
// Ensure selectedKeys is always an array
const keys = Array.isArray(selectedKeys) ? selectedKeys : [selectedKeys];

if (event === "value") {
return keys.map((key) =>
typeof key === "string" ? dayjs(key) : key
);
}
return keys;
}}
>
<DatePicker placeholder={filterPrompt} />
</FilterDropdown>
import dayjs from "dayjs";

<FilterDropdown
{...props}
mapValue={(selectedKeys, event) => {
// Ensure selectedKeys is always an array
const keys = Array.isArray(selectedKeys) ? selectedKeys : [selectedKeys];

if (event === "value") {
return keys.map((key) =>
typeof key === "string" ? dayjs(key) : key
);
}
return keys;
}}
>
<DatePicker placeholder={filterPrompt} />
</FilterDropdown>
This approach ensures that .map is always called on an array, preventing the error you saw. Reference:
This pattern is consistent with the guidance in the Refine documentation, which notes that filter values restored from the URL may not always be in the expected format and may require normalization before being passed to Ant Design components. The documentation also highlights the importance of type normalization when using the mapValue prop, especially for date and select filters, to avoid type mismatches and runtime errors FilterDropdown mapValue property documentation. If you continue to see issues, double-check the value of selectedKeys in both "value" and "onChange" events, as their structure may differ depending on how the filter is being restored or updated. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2h ago
<@224018850419572736> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?