I am using react-select to allow the user to choose their birth year. If the user has already filled it in, it will be preset to some value, e.g. 1950. The input shows the correct value, however when the menu is opened it is scrolled to the top and shows the most recent years (2018, 2017, 2016, etc).
How do I get it to scroll down to 1950 and highlight that item by default?
My code:
class YearPicker extends React.PureComponent {
options = [
{label: 2018, value: 2018},
{label: 2017, value: 2017},
// ...
{label: 1950, value: 1950},
{label: 1949, value: 1949},
// ...
]
render () {
return (
<Select
options={this.options}
value={this.props.value}
/>
)
}
}
CodeSandbox—this should default to 2002. Once you select a value (2002 or otherwise) it works fine, but when the page first loads you have to scroll down within the menu to find the value.
Per the docs I have tried value and defaultValue as well as selectedOption but nothing seems to work. I created a very hacky workaround by leveraging onMenuOpen to find the correct DOM element after it's rendered and then scroll to it, however this breaks the functionality of the arrow keys.
I looked at their source code and actually, you are doing everything right. The issue is in the following line of their code in Select.js:
const selectedIndex = menuOptions.focusable.indexOf(selectValue[0]);
Here they are determining the index of the default option using indexOf and comparing objects. Object equality is performed by reference and not by value. So when you initialize the component for the first time and you explicitly provide an object, the equality fails. Wrong option is highlighted only for the first time. Rest of the times, object equality works since they extract the selected object out of the options and indexOf works
Check the working fork https://codesandbox.io/s/0xzmy6wvln
What I have done is created a function that extracts the selected option from the options array and passes that and so the equality works even for the first time.
I would encourage you to raise this issue on their repo and try to get it fixed.
Set the default value to the object from the options menu.
<Select
options={this.options}
defaultValue={this.options.find(option => option.value === this.props.value)}
/>
This is a workaround for the bug that #cdoshi described.
Related
I want to set a MUI Selection for a list of objects ([{name: "", id: "" }]).
The selection list should show the name and id of the object and the selected value should only show the name. The most important part is that I want to return the selected object with id and name in the onChange-handler.
I basically already got the solution what I want to have, but I can't get rid of the "You have provided an out-of-range value..." warnings. Is there a way to solve this or should I just ignore/disable this warnings?
A codesandbox-example of the component is found here
This is happening because you set a value on the MenuItem to a full object, while you pass a value into Select to be just a string. Change your MenuItem to this:
<MenuItem key={el.id} value={el.id}>
and the Select to this:
<Select
value={entityForm.entity.id}
And you will need to update your handle form code as well, but that would deal with that warning.
EDIT updated answer to use id rather than name
I am using React Antd v3 & upgrading it to v4, I noticed one issue, where the Autocomplete component was changed & now it is behaving in a weird manner
Passing a json array of [{value: string, label: 123}], everything works well except that on value selection, the value is shown (not the label)
How to show the label instead & keep the value selected as the option value?
Here is a link that shows the problem in a sandbox
Another link where passing array of Options also doesn't work correctly
Note:
It was working well in Ant v3, as shown in this link
You can use key attribute to pass unique Id, and use value as label. And then, use 2 parameters in your onSelect function to retrieve the key or any other attributes.
The first parameter is used to pass the value, and
the second one is used to pass the object of the selected option.
Example data options:
const dataSource = [
{ key: 1, value: "John Doe"},
{ key: 2, value: "Jane Doe"}
]
Example field:
<AutoComplete
options={options}
onSelect={(val, option) => onSelect(val, option)}
onSearch={onSearch}
>
<Input.Search size="large" />
</AutoComplete>
Full code example: codesandbox
According to the docs https://ant.design/components/auto-complete/#components-auto-complete-demo-basic
it's intented to use value when it's uncontrolled and passing options in. if you want the label to be different than the actual value, you have to use
const { Option } = AutoComplete;
and pass the array of Option into Autocomplete's Children
<AutoComplete style={{ width: 200 }} onSearch={handleSearch} placeholder="input here">
<Option value="111">Hello</Option>
</AutoComplete>
see https://ant.design/components/auto-complete/#components-auto-complete-demo-options
As indicated in the issue that I have opened on Antd repo, this behaviour is intended in the new version
However, the closest thing to what I needed is the Antd Select with a search option, which does exactly what was needed in my question without any hacks
I'm using react JS and I have a problem. I don't know how to get the value from my dropdown and put that value into a onclick button. I have read lots of topics but I haven't find anything really useful for a beginner like me.
I am using "scheduler" that helped me built my dropdown and some other stuffs.
So, my dropdown get data from a local file and looks like this:
{values.map(v => (
<option value={this.value}>{v.value}</option>
))}
console.log(ref)
And my button is like this:
<Button onClick={() => this.decrement()}>
Ajouetr la réservation
</Button>
The decrement method was only there to test if it was working, and it is.
Actually, what I want to do is quite simple: I have some values in my dropdown (from 1 to 7). And I have a state that says there is 30 places available. What I want is when I choose a specified item in my dropdown AND validate with my button and then my state to decrement with the specified number. Because right now it only decrement with 1.
I hope it's clear enough for someone to help me, because I spent 2 days on that problem and I don't know what to do.
Thank you :)
Next time, it's nice to provide an interactive example with your question. Here's a CodeSandbox I made that (I hope) illustrates your example (link). If you want to fiddle with the example, just click "Fork" in the top right corner.
Back to the solution:
I think what you're missing is storing the selected value in your state along with the 30 "places". What you want is to make your <select /> tag into a "controlled component". When someone interacts with the <select /> you want to change the internal state so that it matches the selected value. That way, when you call decrement() from your button, you can use the internal state's value rather than getting it from a ref (I think that's what you were trying to do).
Here's a link to the React doc that explains how to use forms, specifically the <select /> tag: (link).
Take care!
I would say that you can think about this in 2 different steps:
SET THE QUANTITY STATE
Set the state with the current dropdown value - For achieving this, you can just use the onChange method in your select:
<select name="quantity"
value={this.state.quantity}
onChange={this.onSelectQuantity}
>
In your constructor, you create a variable quantity inside your state
Create a function called onSelectQuantity where you will set the quantity state with setState.
Do not forget to bind the function onSelectQuantity on the constructor.
With this, every time that you change the value on select, your state would capture its value. You can log it from the function if you want to test if it works.
DECREMENT FROM THE BUTTON
After this, you can just decrease the value of the state again from decrement function
<Button onClick={this.decrement}>
Ajouetr la réservation
</Button>
You will have a function...
decrement() {
const newQuantity = this.state.quantity - 1;
this.setState({
quantity: newQuantity
})
}
Hope it helps!
I am using redux-form in my Laravel project (implementing React 15.4.2) and the form I have includes several radio buttons. I need a handleChange function in order for these to remember what is checked (if they are changed from a previous value or selected for the first time) but I don't want to have to write a separate one for each radio button, or implement a huge if else set of rules to handle each one.
Here's one of my fields (just the 'yes' value):
<input type="radio" onChange={this.handleChange.bind(this, 'maintain_licence', 'yes')} checked={maintain_licence.value === 'yes'} id="maintain-licence-yes" value="yes" name="maintain_licence" /><span>Yes</span>
And this is what I have for a single radio button on change, based on the radio button called maintain_licence being interacted with:
handleChange(fieldName, value) {
if(fieldName === 'maintain_licence') {
this.props.fields.maintain_licence.onChange(value);
}
}
This works fine - however, since I have about 20 radios in my form, I can imagine this function getting rather long. Ideally, I'd want something similar to:
handleChange(fieldName, value) {
this.props.fields.fieldName.onChange(value);
}
But as it's trying to find a field actually named 'fieldName' it throws an error stating that it cannot run onChange on an undefined value.
Basically I just need to find a way of using a single function to handle the changes on all radio buttons but I don't know how to do this.
You could use property accessors to get the property you want. Something like:
handleChange(fieldName, value) {
this.props.fields[fieldName].onChange(value);
}
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors
I'm trying to add a select box to a Backgrid.Grid in order to fire a function that will reset the state: {pageSize} to the value the user selects. But I can't figure out how or where to bind the events to the grid.
My understanding is that the element needs to be part of the view (which I believe is the Backgrid.Grid), so I added the select box to the footer of the grid and gave it an id and tried adding an events parameter and matching function to it, but it does nothing.
So, in my footer I have
select id="changePageSize"
And in the grid
events: {
'change #changePageSize' : 'changePageSize'
},
changePageSize: function(){ console.log('hooray!');}
I believe my approach is completely wrong at this point but can't find anything to direct me down the correct path.
What I ended up doing was adding the event listener and function to the backgrid-paginator extension.
Added the select box to the _.template('...
_.template('...<div class="page-size"><select name="pageSize" class="pageSize"><option...');
Under events I added:
'change select.pageSize' : 'changePageSize'
And then created the function:
changePageSize: function(e){
e.preventDefault();
this.collection.state.pageSize = Math.floor(e.currentTarget.value);
this.collection.reset();
},
It makes sense to make this function and its display optional and to also allow a developer to assign an array to generate custom option values. When I get time.
Regarding Duffy Dolan's answer: everything si great in your example, except if you are on let's say on third page and select to have all results only on one page, you get an error.
You just need to add:
this.collection.getPage(1); // it will always select first page