Material UI MenuItem not showing selected item with hardcoded values - reactjs

I am using material-ui MenuItem like the following and noticing following issue. I have hardcoded the Yes or No values and on the UI, my dropdown looks like following:
Image 1:
When I click on dropdown icon, it shows me the following:
Image 2:
When i select Yes or No,my selection doesn't stays on the screen and after selecting , it goes back to look exactly like Image 1. Why it is happening? I noticed that this is happening with hardcoded values only. All other places where I am displaying dynamic data via api call is showing the selected item on screen.
Here is my code snippet:
<CustomSelectDropdown name="yesornofordata" type="select" placeholder="Is the data approved?"/>
const CustomSelectDropdown = ({
placeholder,
disabled,
...props
}) => {
const [field, meta] = useField(props);
const errorText = meta.error && meta.touched ? meta.error : "";
return (
<div>
<InputLabel id="selectLabel">{placeholder}</InputLabel>
<Field
labelId={placeholder}
{...field}
disabled={disabled}
as={StyledSelect}
error={!!errorText}>
<MenuItem data-selected-value={'Y'} onClick={handleSelectedAnswer}>Yes</MenuItem>
<MenuItem data-selected-value={'N'} onClick={handleSelectedAnswer}>No</MenuItem>
</Field>
</div>
);
};
Added code for the function :
const handleSelectedAnswer = event => {
const { selectedValue } = event.currentTarget.dataset;
console.log("Storing selected answer in session storage ")
sessionStorage.setItem("selectedAnswer", selectedValue)
}

Related

useRef is getting cleared when filtering array of objects

I've created one Demo Application where I've been able to add comments while clicking on the chat icon textarea will be expanded, currently, the functionality is I've created a reference using useRef of that particular text area using unique id, and I'm saving comments to that reference array, & rendering on UI using ref.current Method, everything is working as I expected but when I click on those filter buttons, the reference is getting null! my requirement is even though I do filter comments should be persisted!
Any suggestion, Any new Approach except using useRef would be Appreciated! Thanksyou!!
Here's my codesandbox link
https://codesandbox.io/s/proud-resonance-iryir7?file=/src/App.js
Your comment ref should only contains comments, not includes textarea element. So you should create a component to handle textarea value
const TextArea = ({ value, handleSaveComment }) => {
const ref = useRef(null);
return (
<>
<textarea
placeholder="Enter Here"
ref={ref}
defaultValue={value}
></textarea>
<div
className="save-button"
onClick={() => {
handleSaveComment(ref.current.value);
}}
>
Save
</div>
</>
);
};
and use it in table
const handleSaveComment = (fsValidationId, value) => {
comment.current[fsValidationId] = value;
setExpandedId((prev) => (prev === fsValidationId ? "0" : fsValidationId));
};
<AccordionDetails>
<TextArea
handleSaveComment={(value) =>
handleSaveComment(row.id, value)
}
value={comment.current[row.id]}
/>
</AccordionDetails>
You can check full code in my codesandbox. Hope it help!

Set checkbox checked state of checkbox group programmatically in Formik

I have a checkbox group (checkboxes with the same name), that I'd like to toggle them through an external button.
The parent component will map over the data and create multiple checkboxes given the data, like so:
(options.map(
option => (
<Field
name={field.name}
value={option.value}
component={CheckBoxButton}
/>
)
)}
And the CheckBoxButton is
const CheckBoxButton = ({
value,
field,
...props
}) => {
const [activeState, setActiveState] = useState(false)
return (
<div>
<Field
type="checkbox"
{...field}
{...props}
value={value}
checked={activeState}
/>
<Button
active={activeState}
onClick={() => {
setActiveState(!activeState)
}}
>
Toggle Checkbox
</Button>
</div>
)
}
Now on submission, it seems the checked={activeState} value passed to the field seemed to be ignored, nor that it triggers onChange when changed. I have tried to use setFieldValue() but since we have multiple checkboxes with the same name, it only captures the last value. To use it means I'd have to manually structure the value array and pop/add values, which seems like an overkill.
I also tried using useRef and setting ref.current.checked manually, but at no use.
Any insights on what I might be doing wrong, or how to properly set the value programmatically?
So, I managed to get a workaround that solves the problem by wrapping the button (now a div) and checkbox within the same Label, and overriding the state within the onChange event of the field. Each field would have a unique identifier id which the label binds to using htmlFor.
While a valid workaround, it would still be nice to have a programmatic way to do so.
const CheckBoxButton = ({value,field,...props}) => {
const [activeState, setActiveState] = useState(active)
const { handleChange } = useFormikContext()
const fieldId = `${field.name}-${value}`
return (
<label htmlFor={fieldId}>
<Field
id={fieldId}
type="checkbox"
{...field}
{...props}
value={value}
onChange={(event) => {
setActiveState(!activeState)
handleChange(event)
}}
className={style.checkbox}
/>
<span active={activeState} >
Toggle Checkbox
</span>
</label>
)
}

React select multiple true- comma separated value display

Is it possible to get the display of selected values as comma separated.. instead of the box with cross sign
import Select from 'react-select'
<Select
name=''
styles={customStyles}
isClearable
isMulti
/>
You can create your own custom MultiValueContainer component. To display comma separated options, we can do something like this:
render() {
const components = {
MultiValueContainer: ({ selectProps, data }) => {
const values = selectProps.value;
if (values) {
return values[values.length - 1].label === data.label
? data.label
: data.label + ", ";
} else return "";
}
};
return (
<Select
value={this.state.value}
onChange={this.handleChange}
isMulti
name="colors"
options={colourOptions}
className="basic-multi-select"
classNamePrefix="select"
components={components}
/>
);
}
here is the code sandbox link to see above code in action.
According to the React-Select docs, you can change the styles of the individual selected items.
But, they render as boxes with x buttons on them so that the user can choose to de-select any of the selected items.
I would suggest playing with the React-Select styles like this:
<Select
styles={customStyles}
/>

React Select - Multi Select custom way to display multiple options

I am looking to customize the multiselect and the way we create the display of showing selected options.
Right now, with many options selected the select component takes up a prohibitive amount of space for certain UIs. See example:
I'd like to utilize the out of the box chip display for selected options within the input, but I only want to show only a few selected options (like 3/4 max) and then add a "badge" count for the number of selected options that aren't shown in the value container in the input. The options that are selected but are past the max number of chips allowed to show in the input should show as selected within the dropdown list, while the chips that do show's values should not show in our dropdown.
I've implemented part of this with using a custom ValueContainer to show only the first few chip selections, and then adding a count of additional/"overflow" selections. I'm unsure of how I can utilize the prop hideSelectedOptions to achieve this to show selected items in the list only when my max is met without showing all of them since this prop takes a boolean.
Here's what I have so far: https://codesandbox.io/s/custom-react-select-sjtib
import React, { Component } from "react";
import Select, { components } from "react-select";
import { colourOptions } from "./docs/data";
import "./example.css";
class CustomSelect extends Component {
state = {
values: []
};
handleChange = values => {
this.setState({ values });
};
render() {
const { values } = this.state;
return (
<div>
<Select
hideSelectedOptions={values.length < 3 ? true : false}
isMulti
options={colourOptions}
onChange={this.handleChange}
value={values}
components={{ ValueContainer }}
/>
</div>
);
}
}
export default CustomSelect;
const ValueContainer = ({ children, getValue, ...props }) => {
let maxToShow = 3;
var length = getValue().length;
let displayChips = React.Children.toArray(children).slice(0, maxToShow);
let shouldBadgeShow = length > maxToShow;
let displayLength = length - maxToShow;
return (
<components.ValueContainer {...props}>
{!props.selectProps.inputValue && displayChips}
<div className="root">
{shouldBadgeShow &&
`+ ${displayLength} item${length != 1 ? "s" : ""} selected`}
</div>
</components.ValueContainer>
);
};
I would personally keep hideSelectedOptions={false} and go for styles property usage (options property to be more exact) and setting display: 'none' for the ones which shouldn't be visible:
const styles = {
option: (base, value) => {
return (shouldBeShown(value) ? { ...base } : { display: 'none'});
}
};
shouldBeShown(value) is a custom function for checking if the particular option should be shown.
In order to get option data you can use value.data.
Then you can set styles={styles} in Select component:
<Select
hideSelectedOptions={false}
isMulti
styles={styles}
onChange={this.handleChange}
options={options}
value={values}
components={{ ValueContainer }}
/>

react-select How to hide dropdown menu programmatically when 'no results found' is shown?

Github Repo: react-select
After searching in the select box:
After typing a text that is not in the dropdown and enter is pressed. I want to hide the dropdown box.
My implementation:
<Select
ref={ input => this.input = input }
name="form-field-name"
searchable
autoBlur
clearable={false}
openOnFocus
onInputKeyDown={this.onInputKeyDown.bind(this)}
value={this.state.selectedOption}
onChange={this.handleChange.bind(this)}
options={this.props.items}
/>
using onInputKeyDown I am detecting enter keycode. What do I do to remove the dropdown there when 'No results found' is shown?
onInputKeyDown(e) {
if (e.keyCode === keys.ENTER) {
console.log('on input key down');
// How to detect 'No results found' shown?
// And then, how to close the dropdown?
}
}
In V2 you can achieve this by setting noOptionsMessage to a function that returns null:
<Select noOptionsMessage={() => null}/>
This will prevent the fallback option from displaying completely. Note that setting noOptionsMessage to null directly will result in an error, the expected prop type here is a function.
First method:
Turn off <Menu /> component to hide dropdown list.
<Select
components={{
...components,
Menu: () => null
}}
/>
Second method:
Turn off dropdown conditionally. e.g. When there is no value in input.
// Select.js
import { Menu } from './Menu'
<Select
{...props}
components={{
Menu
}}
/>
-------
// Menu.js
import { components } from 'react-select'
export const Menu = props => {
if (props.selectProps.inputValue.length === 0) return null
return (
<>
<components.Menu {...props} />
</>
)
}
Try using the noResultsText prop. Set it to null whenever you would want to hide it.
If you want to hide the menu when no more options are available you can try to override the MenuList component. This worked for me:
const MenuList = ({ children, ...props }: MenuListProps) => {
return Array.isArray(children) && children?.length > 0 ? (
<components.MenuList {...props}>
{children}
</components.MenuList>
) : null;
};

Resources