react-select not setting defaultValue param properly - reactjs

So I have this piece of code, and somehow it's not setting the defaultValue properly, here's the value of patchsOptions[0]:
console.log(patchOptions[0]); // Object { value: "10.15.1", label: "10.15.1" }
<Select
className="col-2"
placeholder="Patch"
defaultValue={patchsOptions[0]}
options={patchsOptions}
onChange={option => this.onChangePatch(option.value)}
/>
The default value keeps empty, but the options are loaded correctly, so I didn't see the problem since looking at some examples, it also uses the "options[0]" variable.
By changing the code this way, it works as expected:
<Select
className="col-2"
placeholder="Patch"
defaultValue={{ value: 'test', label: 'test' }}
options={patchsOptions}
onChange={option => this.onChangePatch(option.value)}
/>
They both have the same obj structure, so I didn't get where's the problem. I logged the default value before rendering, and it's setting normally, it's not empty.

As the patchesOptions is set from an Async call, then the first render time it will be null, and the defaultValue doesn't change if you change it's value, this is like an initial value, so what you can do is to use value option, and link it to the selectedPatch, also I did some change (onChange) like this:
<Select
className="col-2"
placeholder="Patch"
value={{this.state.selectedPatch.value, this.state.selectedPatch.label}}
options={patchsOptions}
onChange={option => this.onChangePatch(option)}
/>

Related

How to get value from React Select Form

Sorry for just a basic question, But I'm a little stuck here to find any way to get values from React Select after making a selection.
This is a Simple Selection setup.
const selectOptions = [
{ value: 'YES', label: 'Set to Active' },
{ value: 'NO', label: 'Set to Mute' }
]
<Label className='form-label'>Select</Label>
<Select
isClearable={false}
className='react-select'
classNamePrefix='select'
options={selectOptions}
theme={selectThemeColors}
/>
I want to get the value against user-selected choice and put it into userChoice content using useState.
const [userChoice, setUserChoice] = useState("")
value can be YES or NO as defined in selectOptions. But how to pass this into userChoice.
I tried using onChange={(e) => setUserChoice(e.target.value)} But this thing is not working.
Also tried onInputChange={handleInputChange} as suggested in previously asked threads on StackOverflow but not working here.
The onChange callback handler gets called with the whole choice object instead of the event object. Therefore it should be like this.
<Select
...
...
onChange={(choice) => setUserChoice(choice)}
/>
If you only intested in YES / NO value, then use,
onChange={(choice) => setUserChoice(choice.value)}

How to get 'name' in event [Autocomplete] component

i have handler fn for handle input from Textfield.
I want use it fn for autocomplete component, but i cant get 'name' and value from it.
function handlerChange(e){
const { name, value, checked } = e.target;
return { name, value: value || checked };
}
<Autocomplete
id="distributions"
name="defaultDistr"
options={distributions}
getOptionLabel={distribution => distribution}
inputValue={defaultDistr}
defaultValue={defaultDistr}
onChange={(e, value) => {
console.log('e', e, 'value', value);
}}
renderInput={params => (
<TextField
{...params}
name="defaultDistr"
label="distributions"
margin="normal"
fullWidth
/>
)}
/>
For Autocomplete, there are many different events that can cause changes to the value. There are several different elements from which those events can come from, so you cannot rely on the target of the event to get the name. Similarly the target of the event does not necessarily have a value and even if it does, that value may not represent the current value of the Autocomplete. This is why the correct value is passed as a second parameter to your onChange handler.
Assuming there is more significant code in handlerChange than what you've shown such that it is worth trying to reuse, you can do something like shown below which creates a new object organizing the information into the structure the handler is expecting.
<Autocomplete onChange={(event, value)=> { handlerChange({target: {name: "defaultDistr", value: value}})} .../>

How do i get the option selected by a user using the Dropdown button to operate on?

I am new to react and office-ui-fabric and I am trying to create a VSCode Extension takes certain input parameters and based on the input the user selects, I should be operating on the option selected. I take the user input in the form of options under dropdown button. Currently once the user selects one of the options from the dropdown i do not see the option selected in the dropdown.I see only undefined being displayed in the console.
I have tried different ways of getting this input parameters from the user but i still end up with undefined being show in the console.
const Options: IDropdownOption[] = [
{ key: 'A', text: 'A', itemType: DropdownMenuItemType.Header },
{ key: 'B', text: 'B' },
{ key: 'C', text: 'C' },
];
const [selectedItem, setOption] = React.useState<string | undefined>(undefined);
return (
<div>
<Dropdown placeholder="Select option" options={Options} styles={dropdownStyles} selectedKey={selectedItem} onChange={event =>{
setOption((event.target as HTMLInputElement).value);console.log(selectedItem)}} />
)
windows.console should show me the input the user selects whereas currently i see undefined
The office-ui-fabric Dropdown component triggers change events via the onChanged prop which when invoked, passes the actual option object underlying the drop down item that has been selected by the user.
By changing onChange to onChanged, and then revising this events handler to read the text of the selected option (rather than value of the event.target) that should produce the required result:
<Dropdown placeholder="Select option"
options={Options}
styles={dropdownStyles}
selectedKey={selectedItem}
onChanged={ selectedOption =>{
setOption(selectedOption.text);
console.log("Selected", selectedOption.text);
}}/>
Update
This: setOption(selectedOption.text); calls the setOption() function, and passes the display value of the option selected by the user to it. When calling setOption(), this updates the stat selectedItem state of the component with the value that is passed (ie the display value of the selected option). Note that a side effect of calling setOption() is that a re-render of the component will occour, meaning that parts of your component displaying/relying on selectedItem will be automatically updated, etc.

React check if property exists AND is false

I have some form inputs and I'd like to be able to set some to be required and some to be optional. I'd like to use the required property so that the HTML is semantically correct:
<input onBlur={this.handleBlur} name="first_field" />
<input onBlur={this.handleBlur} name="first_field" required={false} />
<input onBlur={this.handleBlur} name="first_field" />
I'd prefer to add required={false} so I don't have to add the required prop to every field. However, checking for this then becomes somewhat strange:
handleBlur = (e) => {
if (e.target.value === '') {
// show an error if field empty and required
// NOT explicitly set to false
if (!this.props.required) {
setError('This field is required')
}
}
}
I can't do if (!this.props.required) because that would be true if the property isn't declared.
Is there a simpler way to handle this than the double check?
UPDATE: I hastily assumed this was a code issue, but after some discussion in comments below I now believe it is a semantic issue of how the HTML 'required' attribute should be used, OR how to handle this with React. I chose not to delete the question since there may be some value to this for others in future.
It sounds like you are trying to change the semantics of required. This attribute should default to false if it is not present. Explicitly setting required={false} is perfectly fine. However, changing the meaning when required is not present seems like a bad practice to me.
Instead, you can write your own component. You can name it OptionalInput for example. Give it a prop named optional and then have a render() function with something like this:
render() {
return <input name={this.props.name}
id={this.props.id}
...
required={!this.props.optional}/>
}
You will also need to add props for all input attributes which you want to support.
You can simplify it using defaultProps:
defaultProps: {
required: true
}
If the property is not defined, true will be used instead.
However, it might be better to invert the condition and call it optional, then you will be able to use it simply as:
<input name="first_field" optional />
The simplest way to approach this would be with a forced boolean casting. Any falsey values like undefined, null, 0, or false will result in false, any other value will be considered true. In this case, since required doesn't exist until it's specified as a prop, it will return false until assigned its value. You can try the following on your browser's terminal;
const data = {};
console.log('no required has been defined, ', !!data.required);
data.required = false;
console.log('required has been set to false, ', !!data.required);
data.required = true;
console.log('required should be true now, ', !!data.required);
delete data.required;
console.log('back to not defined, ' !!data.required);
Hope that helps!

Setting a checkbox "check" property in React

I am having a very annoying issue with React and checkboxes. The application I am working with requires a list of checkboxes that represent settings that are persisted in the back-end. There is an option to restore the settings to their original state.
At first, I created a component that has an object like a map of settings. Each setting has a key and a boolean value. Hence:
{
bubbles: true,
gregory: false
}
Is to be represented as:
<input type="checkbox" value="bubbles" checked="checked" />
<input type="checkbox" value="gregory" />
Now, it seems React is ignorant about how a checkbox is supposed to work. I don't want to set the checkboxes' values, I want the "checked" property.
Yet, if I try something like this:
<input
type="checkbox"
value={setting}
checked={this.settings[setting]}
onChange={this.onChangeAction.bind(this)}
/>
I get this warning:
Warning: AwesomeComponent is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: [some useless docs page I read several times to no avail]
So I decided to create another component to wrap each individual checkbox and I got this:
<input
type="checkbox"
checked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Now the checked is a property present directly in my state.
This yields the same warning, so I tried using defaultChecked:
<input
type="checkbox"
defaultChecked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Which makes the warning disappear, but now it is unable to reset the checked value to the default one. So I tried playing with the method componentWillReceiveProps, this way I am quite sure my state is correct, this.state.checked is correct and the component renders again.
And it does. But the checkbox remains as it was originally.
For now I left that ugly warning and I am using checked.
How do I fix this thing so the warning goes away?
I was thinking that perhaps there is a way to force-re-render the component, so it captures the new defaultChecked value and uses it. But I don't know how to do that. Perhaps suppress the warning only for this component? Is that possible? Perhaps there is something else that can be done?
The problem arises if you set the checked property of your checkbox to null or undefined.
Those are "falsy" values in JS. However, React treats a value of null as if the property was not set at all. Since the default state of a checkbox is unchecked, everything will work fine though. If you then set checked to true, React thinks the property suddenly comes into existence! This is when React figures you switched from uncontrolled to controlled, since now the prop checked exists.
In your example, you can get rid of this warning by changing checked={this.settings[setting]} to checked={!!this.settings[setting]}. Notice the double bang (!!). They will convert null or undefined to false (and leave true alone), so React will register your checked property with a value of false and start off with a controlled form component.
I had this problem too and I, too, read the docs about controlled-components several times to no avail, but I finally figured it out, so I thought I'd share. Also, since version 15.2.0, normal inputs are triggered to be controlled by setting value, while checkboxes are initialized as controlled by setting checked, regardless of their value property, which added a bit to the confusion.
Amoebe's answer is correct, but I think there's a cleaner solution than the double bank (!!). Simply add a defaultProps property with value false for checked prop of your Checkbox component:
import React from 'react';
const Checkbox = ({checked}) => (
<div>
<input type="checkbox" checked={checked} />
</div>
);
Checkbox.defaultProps = {
checked: false
};
export default Checkbox;
Basically, the defaultChecked means you don't want to control the input – it just renders with this value and then there is no way to control it. Also, value shouldn't be used, but checked instead, so your second code should be correct. And you shouldn't use them both simultaneously.
<input
type="checkbox"
checked={this.state.checked}
onChange={this.onChangeAction.bind(this)}
/>
Can you create a small fiddle with this behaviour?
Here is an answer using hooks should you choose to convert the class component to a functional one...
export default Checklist = () => {
const [listOfItems, setListOfItems] = useState([
{name: 'bubbles', isChecked: true},
{name: 'gregory', isChecked: false}
]);
const updateListOfItems = (itemIndex, isChecked) => {
const updatedListOfItems = [...listOfItems];
updatedListOfItems[itemIndex].isChecked = isChecked;
setListOfItems(updatedListOfItems);
}
return (
{listOfitems.map((item, index) =>
<index key={index} type="checkbox" checked={item.isChecked} onChange={() => updateListOfItems(index, !item.isChecked)} />
)}
)
}
You can assign your data to the state and then make use of the checked property associated with the individual checkbox to set the state as
{ this.state.data.map(function(item, index) {
return (
<input type="checkbox" checked={item.value} onChange={this.handleChange.bind(this, index)}/>
);
}.bind(this))
}
Sample Data in state is as
data: [{name:'bubbles', value: true}, {name:'gregory', value: false}]
JSFIDDLE
What finally worked, combining other answers:
const [categories, setCategories] = useState(
[
{
field: 'Label 1',
checked: true
},
{
field: 'Label 2',
checked: false
},
{
field: 'Label 3',
checked: false
}
]
)
const updateList = (item, isChecked) => {
const updatedList = [...categories];
updatedList[item].checked = isChecked;
setCategories(updatedList);
}
... in your markup:
{
categories.map((item, index) =>
<div key = {item.field}>
<label>
<span>{item.field}</span>
<input key={index}
type="checkbox"
checked={item.checked}
onChange={() => updateList(index, !item.checked)}
/>
</label>
</div>
)
}

Resources