React select - change the way selected values are shown - javascript

I am using react select control in my ReactJs based application. I am using this as a multi-select control. But once the user selects more than 1 value, instead of showing all the selected values, I want to show the first selected value + N. So if two values are selected, I want to say 'XYZ' + 1. If only one value is selected I will say 'XYZ'. here is a working example

You need to override ValueContainer like below. working sandbox
const ValueContainer = props => {
let length = props.getValue().length;
return (
<components.ValueContainer {...props}>
{length > 1 ? (
<>
{props.children[0][0]}
{!props.selectProps.menuIsOpen && `${length - 1} Items`}
{React.cloneElement(props.children[1])}
</>
) : (
<>{props.children}</>
)}
</components.ValueContainer>
);
};
In Select you need to override
<Select
components={{ValueContainer}}
hideSelectedOptions={false}
...
/>

Related

Update state from <select> tag using onChange and filter through list of categories to display blog posts from that category

I'm rendering a dropdown list of categories dynamically by storing the names of these categories in strings within an array and want to update my list of blog posts based on which category is selected in the dropdown.
The category array looks like this:
const tags = ['Sustainability', 'Electrical', 'Mechanical', 'Engineering']
I'm then mapping through this array to display these strings in a select tag dropdown like so:
<div className='col-span-8 md:col-span-2'>
<select
placeholder='Categories'
onChange={handleChange}>
<option value='' selected disabled hidden>
Choose Category
</option>
{tags.map((t) => (
<option>{t}</option>
))}
</select>
</div>
I then have a list of blogs coming from Prismic (headless CMS) which I have stored in state, and am mapping through to list them out in the UI. I've stored these in state called selectedBlogs like so:
const [selectedBlogs, setSelectedBlogs] = useState(blogs);
And mapped through like so (this just displays every blog currently)
{selectedBlogs.results.map((blog) => (
<SwiperSlide key={blog.data.title} className='blog-wrap1'>
<a
href={`/resource/${blog.slugs}`}
className='h-full object-cover'>
<img src={blog.data.image.url} alt='' />
<div className='absolute bottom-5 text-left text-white p-5 w-full font-header'>
<h1 className='text-2xl overflow-ellipsis'>
{RichText.asText(blog.data.title)}
</h1>
</div>{' '}
</a>
</SwiperSlide>
))}
Simply put, I want to update this list of blogs based on which Category is selected in this dropdown, and when it is selected filter the blogs and display only those within that category.
I know I need to use an onChange in the select tag which I have but how can I store the dropdown item which is selected and re-render my blog posts based on that?
Many thanks in advance for any guidance!
I assume this is how you set your handleChange function, and after that do the following step :
const tags = ['Sustainability', 'Electrical', 'Mechanical', 'Engineering']
const [selectedBlogs, setSelectedBlogs] = useState(blogs);
/* you need this below state to store selected tag */
const [selectedTag, setSelectedTag] = useState("")
/* handle the value selected from the form option */
const handleChange = (e) => {
const selected_tag = e.target.value;
setSelectedTag(selected_tag)
}
useEffect(() => {
const filtered_blog = blogs.filter(blog => blog.data.tag === selectedTag);
setSelectedBlogs(filtered_blog)
}, [selectedTag]) // <--- listen to the changes on selectedTag that trigger this
// Then your selectedBlogs will update everytime you change the tag
I would introduce a new state to set the filter like so:
const [filter, setFilter] = useState('')
And then set the state with an onClick() handler on the select element.
Since this is not an input-field where we can track the change of each letter, i wouldn't use onChange.
<option onClick={()=>setFilter(t)}></option>
You should be able to pass that state into a filter-function:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/filter
To make sure the filter-function runs whenever the state of our filter-state changes I would wrap it in a useEffect-hook:
The useEffect hook takes in a state at the end. The function inside the hook runs once whenever that state gets updated. I your case whenever you update the 'filter' state by clicking on a tag.
useEffect(()=>{
console.log(your-filterfunction)
},[filter])

Bind the Selected option text To Input box

Im new to react, Im acheiving to search the text,which will post to the api, and the results will be displayed as options in box,for which im using twitter bootstrap just the className's to match with REACT.I want to make the make the option's value to be bind to the input text box above, if i select the option. How to achieve this using useRef and at the same time ,the select box should close if the option is selected.The HandleCHange for the input box triggers the api call for every keystrole
Below is the code for the select box.
<input
className='form-control'
placeholder='Search Drug...'
onChange={handleChange}
/>
<select class='custom-select' size={drugList.drugs?.length> 0 ? '10' : ''} onChange={handleSelectChange}>
{drugList.drugs?.length > 0 &&
drugList.drugs.map((each,index) => {
return (
<option key={index} value={`${each.drug}`}>
{each.drug}
</option>
)
})}
</select>
Here i want the selected value to be bind to the input box.It will be great if you give the sample code or snippet.
Please refer the image above.Thanks in Advance!
I want to make the make the option's value to be bind to the input text box above
---> use component state to store the selected value from the options dropdown
at the same time ,the select box should close if the option is selected.
----> hide/display select options based on input box focus by toggling component state.
created a sandbox for your app, please check
I think you can do this like this.
handleSelectChange = (event) =>{
this.setState({selectvalue:event.target.value});
}
handleChange= (event) =>{
this.setState({selectvalue:event.target.value});
---- and your code here---
}
<input
className='form-control'
placeholder='Search Drug...'
onChange={this.handleChange}
value={this.state.selectvalue}
/>
<select class='custom-select' size={drugList.drugs?.length> 0 ? '10' : ''} onChange={this.handleSelectChange}>
{drugList.drugs?.length > 0 &&
drugList.drugs.map((each,index) => {
return (
<option key={index} value={`${each.drug}`}>
{each.drug}
</option>
)
})}
</select>

How to use FormControl for multiselect using react-bootstrap?

I am new to reactjs. I am trying to use multi select using form control.
Below is my code:
handleIds(e){
let id = null;
if(e.target.value) {
id = parseInt(e.target.value, 10);
} else {
id = null
}
this.state.Ids.push(id);
}
<FormGroup controlId="formQueryIds"
validationState = {this.validateNotEmpty(this.state.queryIds)}>
<ControlLabel>Query Ids</ControlLabel>
{this.loadQueries()}
<FormControl componentClass="select"
placeholder="Select ids"
onChange={this.handleIds}
multiple>
{this.state.items.map((item) => <option key={item.id}>{item.id}</option>)}
</FormControl>
<FormControl.Feedback />
</FormGroup>
Here items is an array of ids which is dynamically providing the option values.
The problem here is: for every single selection of option, it's triggering handleIds and adding the value to the array Ids[].
But when we unselect the option which we selected already, I am unable to trigger handleIds and remove the value from the array.
Is there a way to design to remove value from the array as soon it's unselected or instead of triggering handleIds for every selection, just triggering once and provide all the selected values as an array?

antd design select placeholder issues

I am using antd design in my React app.
Here's a code snippet where I am facing the issues :
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = "{this.state.company}"
name = "company"
onSelect = "{this.handleCompanyChange}"
>
Now it shows the correct value selected if this.state.company is not null. But if this.state.company is empty or null, placeholder doesn't shows up.
How can I solve this issue so that the placeholder appears if value is null?
set this.state.company to be undefined instead of null.
you should update as below:
<Select
showSearch
optionFilterProp = "children"
placeholder = "Select Company"
value = {this.state.company || undefined} ---- update this line
name = "company"
onSelect = "{this.handleCompanyChange}"
>
It should be set to undefined instead of null or "" empty string.
this.props.form.setFieldsValue({
myFieldName: undefined
})
I have faced the the same issue, heres the solution:
Code snippet for ant design select
<Select key="1" value={this.getStateValue()} showSearch allowClear placeholder='Select Weight' onChange={onWeightChange}>
{options}
</Select>
where getStateValue will be this:
getStateValue = () => {
const { value } = this.state;
if (value) {
return value;
}
}
I changed from:
const [value, updateValue] = useState("");
To:
const [value, updateValue] = useState(undefined);
And it worked!
If you are using Form.create() of the Antd then there is another cool way to set/get the value of the form. Note that in this method the components (Select and others) have to be inside a <Form> element. Also the enclosing class should be passed in Form.create() object as props, as shown below:
export default connect(mapStateToProps, mapDispatchToProps)(Form.create()(YourClassName));
This way we have this.props.form available in the props. This will have an important function named getFieldDecorator, as shown below:
const { getFieldDecorator } = this.props.form;
Every Input component must be wrapped inside a , see below:
<FormItem>
{ getFieldDecorator('prefix', {
initialValue: '86',
})(
<Select style={{ width: 70 }}>
<Option value="86">+86</Option>
<Option value="87">+87</Option>
</Select>
);}
</FormItem>
As you can see above, this is more easier way to set initial value to the form elements.
Note that at times when you need to set values of the form elements in functions programatically then you can use setFieldsValue, setFields etc.
Before using getFieldsValue getFieldValue setFieldsValue and so on, please make sure that corresponding field had been registered with getFieldDecorator.
Please refer https://ant.design/components/form/?locale=en-US#Form-fields for more information on coordinated controls.
Example:
componentDidMount() {
if (someCheckHere){
this.props.form.setFieldsValue({
company: userData.companyName
})
}
}
Check the image posted, you need to target the name and try to set it to null if its an empty string, this should work.

React defaultValue for Select with Dynamically Generated Options

Use the defaultValue or value props on instead of setting selected on .
<select defaultValue="react">
<option value="react">React</option>
<option value="angular">Angular</option>
</select>
defaultValue would work with the above select tag. However, it does not seem to work with options generated by loop.
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Probably options not fully been set when defaultValue was declared?
I could do manual assigning in componentDidUpdate() and onChange event.
But my question is - Is there any cleaner(better) way to solve it?
Thanks.
This is old, but since answer #1 is related to a controlled Select and the question seems to be related to uncontrolled Select I think is worth to leave some lines for future readers:
The problem is that for uncontrolled components React needs to know what are the options before the first render, since from that moment the defaultValue won't override the current value of the Select. This means that if you render the Select before the options it won't know what to select.
You can solve the problem avoiding the render before the options are available:
const RenderConditionally = ({ options, selected }) => options.length > 0 ? (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
) : null;
Or without ternary if you desire:
const RenderConditionally = ({ options, selected }) => {
if (options.length === 0) {
return null;
}
return (
<select defaultValue={selected}>
{options.map(item => (
<option key={item.id} value={item.value}>{item.label}</option>
))}
</select>
);
};
For users running into this issue, you can get the desired functionality by using the value prop, instead of defaultValue, e.g.:
<select value={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
Most probably you have something wrong with option_id and options arrays structure, or selectedOptionId variable. The way you build your select component is ok.
I've made a fiddle where this code works fine:
render: function() {
let option_id = [0, 1];
let options = [{name: 'a'}, {name: 'b'}];
let selectedOptionId = 1
return (
<select defaultValue={selectedOptionId}>
{option_id.map(id =>
<option key={id} value={id}>{options[id].name}</option>
)}
</select>
)
}
The best solution that I could find is to set key attribute the same as defaultValue so it will be a different element.
Aftermaths are not researched by me but I believe it should be okay.

Categories