React Semantic-UI: Dropdown.Menu / Problem - reactjs

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>

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?

reactstrap, dropdown with search input

In order to benefit the design of reactstrap dropdown, I want to use it as a search bar with results shown in the dropdown menu. But the default key listener that enables navigating through results by keyboard (arrow keys Up/Down), only captured by Input, and cannot propagate it to the parent or whatever is listening to key events when the result is visible.
<Dropdown toggle={() => setIsOpen(!isOpen)} isOpen={isOpen}>
<DropdownToggle>
<Input onChange={(e) => setQuery(e.target.value)} placeholder="search placeholder" />
</DropdownToggle>
<DropdownMenu>
{fetchedItems.map((item) => (
<div key={item}>
<DropdownItem>action #1</DropdownItem>
<DropdownItem>action #1</DropdownItem>
<DropdownItem text>Dropdown Item Text</DropdownItem>
<DropdownItem disabled>Action (disabled)</DropdownItem>
<DropdownItem divider />
</div>
))}
</DropdownMenu>
</Dropdown>
Now looking at this sandbox I am searching for two approaches, either add key event listeners to default as default dropdown behavior, or customize the <Input type=" search"/>
Now the question is how to do it. I assume handling key listener might be better.
One way to do this would be by adding an eventListener with the dropdown component.
You would also want to maintain a state which tracks the currently navigated dropdown item's index.
The eventListener can increment and decrement the selected index
If nothing is selected, on up keystroke set 0 and on down keystroke set length - 1 as the current index
Now increment or decrement on different keystrokes
If something new is searched, change it to undefined or 0 at your convenience
Give custom styling to the currently navigated index
Please follow following thing:
1)The above "event listner" should be part of parent of list.
2)Set value of "current-index" to 0 once you get new set of data.
3) When user move the selection with the arrow button "incsease" and "decrease" once as per "key-value".
4)If use jump from one point to other get the "id" or "serial number".
5) Ideal event listener should be "onfoucs" if using on the children.
The whole problem was from a type of event listener, so the DropDownToggle component receives the onKeyDown events not the onKeyPress
<DropdownToggle onKeyDown={(e) => {/* now have access to e.key */} }

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>

React tabs - switching destroys component, need to maintain the same component

I am trying to make a multi-tabbed SPA with React and Material-UI. I use code from this demo as an example: https://codesandbox.io/s/qlq1j47l2w
It appears that if I follow the aforementioned example, I end up returning new instance of the component with tab contents each time I navigate between the tabs:
<Tabs
value={value}
onChange={this.handleChange}
indicatorColor="primary"
textColor="primary"
scrollable
scrollButtons="auto"
>
<Tab label="Tab 1" />
<Tab label="Tab 2" />
</Tabs>
</AppBar>
{value === 0 && <Tab1Contents/>}
{value === 1 && <Tab2Contents/>}
As Tab1Contents is a form, I would like its internal state to be retained, instead of loading a new instance of the component, which the code above appears to do.
What is the best way to get React to use only one instance of the component and 'memorise field values'?
EDIT
I have added Redux to the example, but the store corresponding to the form within the Tab is destroyed the moment I switch away. Is there any other way to implement tabs in React that would hide the tab contents, instead of destroying them and re-creating them from scratch each time I navigate away?
The solution to my problem was quite simple! If you don't want to destroy the component (remove it from DOM), you can simply hide it!
Instead of:
{value === 0 && <Tab1Contents/>}
Use:
<div style={{ display: value === 0? 'block': 'none'}}>
<Tab1Contents/>
</div>
It was already mentioned that you have to prevent your component from being removed from the DOM. The easiest solution with MUI5 TabPanel is in fact to just replace
{value === index && children}
with
{children}
that means your Tabpanel would look like that:
import * as React from "react";
const TabPanel= ({ children, value, index, ...other }) => {
return (
<div
role="tabpanel"
hidden={value !== index}
id={`tabpanel-${index}`}
aria-labelledby={`tab-${index}`}
{...other}
>
{children}
{/* {value === index && children} // This was removed */}
</div>
);
};
export default TabPanel;
No additional logic necessary as the hidden prop already takes care of the visibility aspect. This way your components should maintain their state!
You would need to persist the state between the tab changes. I prototyped a form using React forms documentation for Tab1Container and as you play around with it, the value will disappear
https://codesandbox.io/s/material-demo-ojwhr
What you ideally need to use something like Redux, which will use a store to keep the information even between the state changes like Tab clicks.
Hope this helps!

Ant Select closes dropdown

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.

Resources