Prevent closing after click on Dropdown.Item in React-bootstrap - javascript

When I click on Dropdown.Item, Dropdown.Menu hides. I want to prevent this, i.e. leave Dropdown.Menu open after a click, and close it only if there was a click outside of Dropdown at all. I've found similar questions, but there were in original bootstrap using jQuery. How to implement this in react-bootstrap? Thanks
////
<Dropdown.Menu>
<Dropdown.Item>- Pending</Dropdown.Item>
<Dropdown.Item>- Completed</Dropdown.Item>
<Dropdown.Item>- Cancelled</Dropdown.Item>
</Dropdown.Menu>
////

Add autoClose="inside" to the Dropdown component.
By default, the dropdown menu is closed when selecting a menu item or clicking outside of the dropdown menu. This behavior can be changed by using the autoClose property.
By default, autoClose is set to the default value true and behaves like expected. By choosing false, the dropdown menu can only be toggled by clicking on the dropdown button. the inside makes the dropdown disappear only by choosing a menu item and the outside closes the dropdown menu only by clicking outside.
https://react-bootstrap.github.io/components/dropdowns/

You can make use of show prop of Dropdown. Using this you can manually hide and show the dropdown.
So what i did is i added dropdown props state variable to the Dropdown element and then using onToggle function i hide and show dropdown on particular conditions.
<Dropdown {...this.state.dropdownProps} onToggle={(isOpen, event) => this.onToggleFunction(isOpen, event)} />

Try this:
const [isShown, setIsShown] = useState(false);
const onToggleHandler = (isOpen, e, metadata) => {
if (metadata.source != 'select') {
setIsOpen(isOpen);
}
}
<Dropdown
show={isShown}
onToggle={(isOpen, e, metadata) => onToggleHandler(isOpen, e, metadata)}
>
*onSelect method can be used normally

For functional components, simply create the state:
const [ show, setShow ] = useState(false);
Then write your dropdown component like this:
<Dropdown show = {show}>
<Dropdown.Toggle onClick = {() => setShow(!show)}>Toggle Trigger.</Dropdown.Toggle>
</Dropdown>

Related

React-Select Creatable prevent user from entering additional options if length of selection is reached

Currently I have a Createable component that has a dropdown menu and users can also freely enter any new value. However I want to disable creating new values if the maximum number is reached.
Here I used a custom menulist component to hide the dropdown (There is still a visible small line here beneath the component tho). But the user can still type, in the input. Is there any way to disable this specifically and not disable the whole component since they should still be able to delete selections.
const CustomMenuList = (props: any) => value?.length === 5 ? null : <components.MenuList {...props} />;
Your logic is generally correct but you need to apply it to the Menu component which is the container for MenuList, that's why you still see something when you hide MenuList
import { components } from 'react-select';
const CustomMenu = ({ children, ...props }) =>
props.options.length === 5 ? null : (
<components.Menu {...props}>{children}</components.Menu>
);
<Select
components={{
Menu: CustomMenu,
}}
/>
As for disabling the input, just follow the same logic and override the input's disabled attribute when options reach 5.

Maintaining default open/close behavior with custom ValueContainer in react-select

I need to customize a react-select dropdown a bit. Its a multi-select, and my goal is that when the user select many options, the selected options only take up as much horizontal space in the box as is available. Overflow should be handled with an ellipse.
Default behavior - overflow items wrap to next line and make box height grow:
Desired behavior - custom rendering, with ellipse
My tactic in accomplishing this is to use a custom component in the select for ValueContainer:
const ValueContainer = (props) => (
<div
{...props.innerProps}
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{props.selectProps?.value?.map((p) => p.label).join(", ")}
</div>
);
const MyComponent = () => {
// state logic here
return (
<Select
options={options}
value={value}
isMulti
onChange={(value) => setValue(value)}
components={{ ValueContainer }}
/>
);
This is indeed working, as you can see in this codesandbox.
However, I seem to have lost the default behavior. In the left example in the sandbox (default as shown above), when you click on any part of the dropdown (existing selection, empty space, dropdown indicator, etc), the dropdown opens. This is the behavior I want. In my custom example, clicking on the list does not open the dropdown - you have to click specifically on the tiny little dropdown arrow to get it to open. Likewise, when its open, the default behavior has a click-away handler, where clicking anywhere on the screen closes the menu. That behavior is also lost with this custom ValueContainer component.
How can I maintain this custom open/close click behavior, while using a custom ValueContainer component? There does not seem to be an innerRef on the props of a ValueContainer, as described in the docs. Is there a setOpen prop somewhere in these props that I'm missing? Is there a better way to achieve my desired effect?

ReactJS - Make Click Event fire before onBlur

I am implementing a custom input element similar to React Select. Users will be able to type something into the input element and select a suggestion from a dropdown (in my case, I implemented a component called SuggestionList which serves the same purpose as that dropdown suggestion list).
Currently, the SuggestionList is a sibling React component to the input element that the user types into (I named it CustomInput).
I want SuggestionList to disappear when CustomInput loses focus, so I implemented an onBlur handler which makes SuggestionList either un-mount or have "display" CSS property set to none. However, the problem is that after SuggestionList disappears, its onClick/handleClick event handler doesn't get called, and that event handler is responsible for adding user-selected elements to the selected items list.
Code shown below. There is more explaination after this code.
const AutocompleteInput = ({...}) => {
const [suggestionVisible, setSuggestionVisible] = useState(true);
return (
....
<SystemComponent position="relative">
<SuggestionList p={theme.space[4]}
position="absolute"
visible={suggestionVisible}
value={value}
handleClick={handleSelect}
ref={suggestionBox}
/>
<CustomInput
variant="text"
placeholder={placeholder}
value={value}
onChange={(evt) => handleInputChange(evt.target.value)}
onKeyDown={handleKeyDown}
onFocus={ () => {setSuggestionVisible(true)} }
onBlur={ () => {setSuggestionVisible(false);} }
/>
</SystemComponent>
....
)
}
Therefore, when a user clicks something on the SuggestionList, my CustomInput immediately loses focus, causing SuggestionList to either be unmounted/disappear, and thus its event handler isn't called. As a result, the item the user selects isn't added to the suggestion list.
Having that said, I still want SuggestionList to disappear when the user clicks some other part of the website, thereby causing CustomInput to lose focus. Any suggestions ?
Let's say you are calling onClickHandler() inside your onClick. You can call this inside the onBlur on function.
For example
onBlur={ () => {onClickHandler(); setSuggestionVisible(false);} }

Custom actions in Material UI select MenuItem

I am using Material UI Select: https://material-ui.com/components/selects/
The select needs a bit of custom functionality. I have added this in a CodePen sandbox: https://codesandbox.io/s/material-demo-3nzpv
Some MenuItem might need to show a delete icon.
Selecting an option that has the delete icon (but not clicking the delete icon itself) should not show the delete icon after selection as the selected value. The delete icon should still be a part of the MenuItem though.
Clicking on the delete icon should not select the option but trigger the onClick of the delete icon instead. In essence, the default functionality of MenuItem should not trigger, just the icon onClick.
What's the best way I can achieve this?
You need to use renderValue prop from your Select component, in order cu custom render your selected value.
Add the following line to your Select component
renderValue={value => currencies.find(el => el.value === value).label}
You can check an updated version of your working sandbox HERE
Also you can check more on Select props HERE
LE: Update for point 3
In your <DeleteIcon> handler onClick, you need to stop the propagation of the event further. In the handleDelete() function add the event parameter and use e.stopPropagation() method.
const handleDelete = (e: React.ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
console.log("Delete");
};
And your component should look like this
<MenuItem key={option.value} value={option.value}>
<div>{option.label}</div>
<div>{option.action && <DeleteIcon onClick={handleDelete}/>}/div>
</MenuItem>
/>
I've also updated a sandbox, with the last version HERE
On your handleChange method, write a condition to change the value only if the value of a menu item does not have the value that does not need to be selected

Hide autocomplete suggestion list on select dropbdown item and enter click

I 've created autocomplete suggested input field, with debounce hook, only one issue left, is close drop-down when I select item or click outside? And what is the best solution to show selected item, show it in input value on create some 'redableRenderValue'.
Current behavior : when I click enter or on item itself the drop down close and reopen again
Expected value: close on blur , close on enter and close on select item
https://codesandbox.io/s/usedebounce-ncq2n
Try this:
const [showSuggestions, setShowSuggestions] = useState(true); //make useState initial value to true instead of false.
and, delete below code from useEffect
setShowSuggestions(true); //delete this line from your code
also alter here:
<input
type="text"
placeholder="Find"
onChange={e => setSearchTerm(e.target.value)}
onClick={onInputClick} //add this attribute
onKeyDown={onKeyDown}
// onBlur={onBlur}
value={searchTerm}
autoFocus
/>
and a corresponding function to call:
const onInputClick = () =>{
setShowSuggestions(true);
}
and Run your code.
I try it this will be working fine by doing this. Hope this will help you to.

Categories

Resources