Ant Select closes dropdown - reactjs

I am using Ant Select component inside Dropdown component. Here is my index file which renders Dropdown
const getMenu = filter => (
<MenuContainer
...
/>
);
<Dropdown
overlay={getMenu(searchFilter)}
trigger={['click']}
visible={this.state.search}
onVisibleChange={val =>
this.handleDropdownVisibility(val, searchFilter)
}
>
...
</Dropdown>
Here is my MenuContainer which return Select Component inside it
handleSelectChange = val => {
this.setState({
selectedValue: val,
});
};
<Select
ref="selectBox"
onChange={this.handleSelectChange}
style={{ width: '100%' }}
>
{numberComparision.map((item, i) => {
return (
<Option key={i} value={item.id}>
{item.name}
</Option>
);
})}
</select>
so on clicking select value onVisibleChange fires and closes dropdown

In current v3.3.1 there is no API to prevent to close the Dropdown list.
As a solution I can offer this custom component.
Item has a property clickable which indicates will be the droplist closed after click or not. You can set true/false or css name of an element which should not trigger closing drop-list.

Change Menu.Item where the select is contained to a Menu.ItemGroup, those do not trigger the onVisibleChange when clicked.

You are mixing components that are not meant to be mixed here, I believe.
Dropdown expects its overlay to be a menu of some sorts. Or at least something static that does not open yet another dynamic <div> layer.
Select already has a dropdown type behaviour. So your Dropdown opens the Select which opens the Select dropdown, and then they both react to the click event and close.
It is currently not clear from your question and screenshot what you are actually trying to achieve, that could not be achieved using just a Select. You could try clarifying that.

Related

react-select doesn't play well in mobile when dropdown icon is "overridden" and onMenuOpen+onMenuClose are used

I am using react-select for value input in my web app. I have to override dropdown indicator icon according to design and some dynamic modifications has to be performed depending on the opened/closed status of the menu. I am using styled-components and I have simplified the code a bit to be presented here:
const DropdownIndicator = (props) => {
return (
<components.DropdownIndicator {...props}>
</components.DropdownIndicator>
);
};
<S.InputField
disabled={disabled}
labelLeft={labelLeft}
noLabel={!label}
className={className}
fieldType={state?.type}
inputType={state?.inputType}
notClearable={notClearable}
extendOnOpen={extendOnOpen && menuIsOpen}
menuIsOpen={menuIsOpen}
menuHeight={menuHeight}
>
<label htmlFor={id}>{label}</label>
<div className="input-wrapper">
<Select
id={id}
placeholder={'test'}
components={{ DropdownIndicator }}
// menuIsOpen={menuIsOpen}
onMenuOpen={() => {
console.log('menu opened');
setMenuIsOpen(() => true);
}}
onMenuClose={() => {
console.log('menu closed');
setTimeout(() => setMenuIsOpen(() => false), 3000);
}}
/>
</div>
</S.InputField>
Now, when I try to open the menu clicking on the Select's control field, the menu opens as expected, but when I want to open it clicking on the dropdown icon, the operation becomes hardly predictable - basically I get the 'menu opened' and 'menu closed' directly after, so menu doesn't stay open. Why could that be? Is it a bug in the react-select design?
The funny thing is, if I comment either components={{ DropdownIndicator }} or one of onMenuOpen or onMenuClosed, the menu opens/closes as expected, but never when both ("overridden" DropdownIndicator and onMenuOpen/onMenuClosed) are employed. And I put "overridden" in quotes as it is not technically overridden (I've removed the icon change from <components.DropdownIndicator {...props}></components.DropdownIndicator> as it doesn't impact the outcome), it's actually mimicking (as I understand) the default behaviour of react-select's menu flow.
Important! It only happens in mobile resolutions. Desktop res works just fine. So my understanding this has got something to do with onFocus/onBlur and the way they are treated in touch devices.
Any thoughts?

React Semantic-UI: Dropdown.Menu / Problem

I am trying to build a language selector dropdown showing the flag symbols of the languages - in the menu when it is not opened as well as in the opened menu. I would not like to show any texts.
I am using inline style to style my components in my app, therefore I would like to define the menu style as well via style={myStyle}, else the opening dropdown menu won't be affected by the style in the component.
<Dropdown
value={value}
selection
compact
style={myStyle}
onChange={getLanguage} // could be removed
options={countryOptions}
>
<Dropdown.Menu style={myStyle} >
{countryOptions.map( country => {
return (
<Dropdown.Item key={country.key} value={country.value} flag={country.flag} onClick={getLanguage} />
)
})}
</Dropdown.Menu>
</Dropdown>
I use the code above and it works for me, the only problem is, that I get the error message, that I cannot use <Dropdown.Items> and options in the component at the same time:
Warning: Failed prop type: Prop `selection` in `Dropdown` conflicts with props: `children`. They cannot be defined together, choose one or the other.
My problem without using the options is, that I don't know how to set the active item in the component. Without the options it seems, it is not possible to display the current value inside this component.
What am I missing or doing wrong? Is it possible at all to set the current value without using options? Can I ignore the error message?
Thank you a lot for your help.
I think what you're asking for is to set active prop on the Dropdown.Item, with a test to see if the Item value matches the set value for the dropdown.
<Dropdown
value={value}
compact
style={myStyle}
selection
onChange={getLanguage} // could be removed
options={countryOptions}
>
<Dropdown.Menu style={myStyle} >
{countryOptions.map( country => {
return (
<Dropdown.Item
key={country.key}
value={country.value}
active={(value === country.value)}
flag={country.flag}
onClick={getLanguage}
/>)
})}
</Dropdown.Menu>
</Dropdown>

In react select how to allow user to select text of selected option to copy its text

React select does not allow text selection of selected option. I want user to be able to select text of selected option. Whenever user tries to select the text of selected option, react select's menu gets open(pops up).
link for code sandbox:
https://codesandbox.io/s/bzdhr?module=/example.js
Any help appreciated, Thanks in advance.
react-select doesn't allow us to select the text.. neither in options or the selected value for that matter..
the input component dominated the div that keeps the value.. there is no way to select that div.
however.. i managed to find a work-around for you.. this should do..
https://codesandbox.io/s/react-codesandboxer-example-5jhzf
This happens because of the react-select onMouseDown event.
You can better handle it by overriding react-select custom renderers, wrap the single value renderer in a div which doesn't propagate onMouseDown events.
import React from 'react';
import Select, { Props, components, SingleValueProps } from 'react-select';
const SingleValueRenderer: React.FC<SingleValueProps<any>> = ({ children, ...props }) => (
<div
onMouseDown={(event) => {
event.stopPropagation();
}}>
<components.SingleValue {...props}>{children}</components.SingleValue>
</div>
);
const Dropdown: React.FC<Props> = (props) => (
<Select
components={{ SingleValue: SingleValueRenderer }}
{...props}
/>
);
export default Dropdown;

React widgets combobox; how to clear input or prevent selection

I'm using the combobox from React Widgets as a search UI component.
I've put in a custom render item so that when you click a search result in the dropdown, you navigate to the relevant page.
However when you select a result, the name of the selected item goes into the text input, which isn't what a user will expect when they select a search result. I think they'd expect the search term to remain, or perhaps the input to be cleared.
I like the Combobox component and haven't found another UI widget that would do what I want, so I'd like to find a solution.
Is there some way to override the selection behaviour so that clicking a list item doesn't select it? I've tried setting the 'onSelect' property but this doesn't suppress the default selection behaviour, it just adds extra functionality.
Alternatively is there a way to manually set the selection to null? The docs don't seem to show anything. I tried getting the input node's value manually to '' with reactDOM, but the value didn't change. I would guess that the component controls it.
I've wrapped the Combobox in a functional component:
function Search(props) {
...
const onSelect = (value) => {
const node = ReactDOM.findDOMNode(Search._combobox);
const input = node.getElementsByTagName('input')[0];
input.value = '';
}
return (
<Combobox
ref={(c) => Search._combobox = c}
onSelect={onSelect}
textField="name"
valueField="_id"
/>
);
}
If I set the value prop of the Combobox then it is impossible to type into it.
Any suggestions? Thank you.
The solution I found is to create my own search controls using an input and a button, and hide the native input and button with display: none. "componentDidUpdate" detects when new search results arrive and opens the dropdown to show them.
There is a manually-added 'show more...' entry at the end of search results. Clicking this increases the search limit for that group. That's the main reason I wanted to avoid showing the clicked result in the text input. The custom input is not affected by the user's selection, it always shows the search term.
My search component now looks something like this:
<div className="search">
<div className="search-controls">
<Input
onChange={this.onChangeInput}
type="text"
/>
<Button
onClick={this.toggleOpen}
title="toggle results"
>
<FontAwesomeIcon icon={['fas', 'search']} style={{ 'color': iconColors.default }} size="1x" />
</Button>
</div>
<Combobox
busy={isSearching}
data={searchResults}
onChange={() => {}}
open={open}
onSelect={this.onSelect}
textField="name"
valueField="_id"
/>
</div>

How to I keep a Material-ui Select open when I click on only one of the items in it

I have been writing a custom Material-UI Select dropdown which has an optional text field at the top to allow the user to search / filter items in the Select if there were many entries.
I am struggling with how to keep the Select open when I click on the text field (rendered as an InputBase) and just have the normal behavior (of closing the Select when a regular MenuItem is selected.
CodeSandbox here : https://codesandbox.io/s/inspiring-newton-9qsyf
const searchField: TextField = props.searchable ? (
<InputBase
className={styles.searchBar}
onClick={(event: Event) => {
event.stopPropagation();
event.preventDefault();
}}
endAdornment={
<InputAdornment position="end">
<Search />
</InputAdornment>
}
/>
) : null;
return (
<FormControl>
<Select
className={styles.root}
input={<InputBase onClick={(): void => setIconOpen(!iconOpen)} />}
onBlur={(): void => setIconOpen(false)}
IconComponent={iconOpen ? ExpandMore : ExpandLess}
{...props}
>
{searchField}
{dropdownElements.map(
(currEntry: string): HTMLOptionElement => (
<MenuItem key={currEntry} value={currEntry}>
{currEntry}
</MenuItem>
)
)}
</Select>
</FormControl>
);
As you can see above I've tried using stopPropagation and preventDefault but to no avail.
check out this codesandbox link: https://codesandbox.io/s/busy-paper-9pdnu
You can use open prop of Select API
I was able to make a controlled open select by providing open prop as a react state variable and implementing correct event handlers. To make it controlled you must provide onOpen and onClose props of the Select and make sure the open prop stays true when the custom textfield is clicked.
One more important thing I had to do was override the default keyDown behavior of the Select component. If you open up a Select and start typing into it, it shifts focus to the select option that matches what you are typing. For example, if you Select had an option with the text Foobar and if you start typing Food and water, it would cause focus to shift from your custom text input onto the Foobar option. This behavior is overridden in the onKeyDown handler of the custom textfield
Working sandbox here
Edit: even though this worked in the codepen, I had to add onChange={handleOpen} to the Select as well to get it working on a real browser with React and Next.
You can still use stopPropagation to make it work
// open state
const [isSelectorOpen, setisSelectorOpen] = useState(false)
// handle change
const handleChange = event => {
const { value } = event.target
event.stopPropagation()
// set your value
}
// selector
<Select
multiple
open={isSelectorOpen}
onChange={handleChange}
input={(
<Input
onClick={() => setisSelectorOpen(!isSelectorOpen)}
/>
)}
// other attribute
>
<MenuItem>a</MenuItem>
<MenuItem>b</MenuItem>
<MenuItem>c</MenuItem>
</Select>
In my case, none of the above worked, but this did the trick to stop closing the Select:
<MenuItem
onClickCapture={(e) => {
e.stopPropagation();
}}>
You can also change onMouseEnter to change some default styling that comes with using MenuItem (like pointer cursor when mouse enters its layout)
onMouseEnter={(e) => {
e.target.style.backgroundColor = "#ffffff";
e.target.style.cursor = "default";
}}
In my case i also needed to remove the grey clicking effect that MenuItem makes on click, which is a new object generated in MuiTouchRipple-root, so changing display to none did the trick.
sx={{
"& .MuiTouchRipple-root": {
display: "none",
},
}}

Resources