I have a <TextField> component from Material UI that's supposed to allow a user to choose a numerical value. The field is for use on a medical product so we cannot have a default value that's displayed; rather, the value is initially an empty string and onInput we update it accordingly. The min/max props don't work as needed when passed to InputProps, so we manually check if the value passed is less than or equal to zero ('-' also evaluates to true here), and if so we reset the value to 1. However, when I try to instead reset the value to an empty string (i.e. clear the input), the actual state value changes, but the text displayed in the TextField component remains the same for some reason. If anyone knows why the text displayed is not clearing and what I could do to fix this, please let me know!
Code below:
<TextField
disabled={!!requirement.id}
type="number"
value={requirement.val}
variant="outlined"
InputProps={{ inputProps: { min: 1, max: 1000000 } }}
placeholder={'Title!'}
onInput={(e) =>
handleRequirementChange(
Number(e.target.value),
index
)}
/>
const handleRequirementChange = (val, index) => {
const requirement = [...requirement]
if (val <= 0) val = 1
requirement[index] = val
setRequirement(requirement)
}
Related
I am wondering why React is not updating the state after a method onChange is called.
Summary: A simple input element with two float-right icons to display. One icon to display if the length of the input text is 0 while the other if the input text length > 0. But it seems React is updating the state after I enter the second text in my input element.
What I need is:
Display % if length == 0 and display X is length is > 0.
And if the length > 0 then user on click of X set the input text == "" OR input.length = 0.
Problem is: Though I am able to clear the input but the icon % is not displayed.
const onChange = (e: any) => {
//setting user input
if (userInput.length > 0)
setDisplayIcon({ default: "d-none", clear: "d-block" });
else setDisplayIcon({ default: "d-block", clear: "d-none" });
};
const clearText = (e: any) => {
setUserInput("");
};
return (
<label id="default" className={`${displayIcons.default}`}>
%
</label>
<label className={`${displayIcons.clear}`} onClick={clearText}>
X
</label>
);
}
Add setting display icon state:
const clearText = (e: any) => {
setUserInput("");
setDisplayIcon({ default: "d-block", clear: "d-none" });
};
You will not be able to console.log the updated state value inside of the same function. Try placing your console.log outside of the function and you will see that it does in fact update.
"setState is asynchronous call means if synchronous call get called it may not get updated at right time like to know current value of object after update using setState it may not get give current updated value on console. To get some behavior of synchronous need to pass function instead of object to setState." - https://www.geeksforgeeks.org/reactjs-setstate/
I'm beginner with React JS and I'm doing a test project to train my skills.
I have a list of farms being rendered on the screen. The user can click on the button to register a new farm or can click on the property to be able to edit the existing property.
In a single Dialog Modal I do both. The problem is when I try to edit the Input field, it is not working. It doesn't matter what I type and nothing happens.
That's my input field, I'm using TextField from React Material:
<TextField
id="farmer-name"
label="Farm Name"
value={propertyData.farmerName}
onChange={(event) =>
changeField("farmerName", propertyData.id, event.target.value)
}
className={classes.input}
InputProps={{
className: classes.inputContent
}}
InputLabelProps={{
className: classes.inputLabel
}}
/>
And here's my function that will be able update my data:
const changeField = (field, id, value) => {
const newPropertyData = { ...propertyData };
if (newPropertyData.id === id) {
newPropertyData.field = value;
}
};
Here's my code, I put in CodeSandBox: https://codesandbox.io/s/spring-breeze-xnv3r?file=/src/index.js
Screen of my application
Can someone help me to edit that´s values? Thanks
You should save state on change in text field
const changeField = (field, id, value) => {
const newPropertyData = { ...propertyData };
if (newPropertyData.id === id) {
// change field value for specific id
newPropertyData[field] = value;
}
// set updated field value into state to show on form
setPropertyData(newPropertyData);
};
You are not actually changing the propertyData stored in the useState hook.
Currently, there will be a new property added called field in the newPropertyData object. However, this variable is never used or stored and you probably don't want the value to be stored in the field property.
The shortest answer is to pass a function to the setPropertyData which will receive the previous value of propertyData.
The previous propertyData can be extended with a dynamic property by using the following syntax: [field]: value.
const changeField = (field, id, value) => {
if (propertyData.id === id) {
setPropertyData(data => ({ ...data, [field]: value }));
}
};
I have a form that comes with some data from a country. The data comes from a GraphQL API with Apolo Client.
By default, the data is read-only, if the user wants to change the value, should click on the edit button.
The problem is that I am not able to edit the value in TextInput, by default, the value value is already pre defined. I try to edit the value through onChange(), but it doesn't work.
Everything I type does not appear in the Input field.
Here's my code, I put in CodeSandBox: https://codesandbox.io/s/serverless-water-p9p7l?file=/src/App.js
I'm using TextField from react-material.
Can someone help me to update that´s values? Thank you in advance.
Few Change on your code:
In your cangeField function, you need 3 parameters the field with you want to change, the country ID owner of this field, and the new value for the field.
To change the value you need first find the country in the country list and then update the value for the field.
const changeField = (field, id, value) => {
console.log(id, country);
const newCountryInfo = [...country];
newCountryInfo.forEach(c => {
if (c._id === id) {
c[field] = value;
setCountry([...newCountryInfo]);
return;
}
});
};
On your textInput you call the change field and pass the three parameters as expected first the name of the country property you want to change on this case "name" -> country.name, second the Country ID country._id and the last is the new value for the field
<TextField
...
onChange={event => changeField('name', item._id, event.target.value)}
...
/>
You can note I remove the brace after the ES6 function '=>' because in you use this brace you need to return inside
<TextField
...
onChange={event => {
return changeField('name', item._id, event.target.value);
}}
...
/>
in your code, you forgot to return but is cleaner to return directly
<TextField
...
onChange={event => changeField('name', item._id, event.target.value)}
...
/>
When using text input using this.state it doesn't matter to give value a state variable and you'll able to edit the value, in my case here I am rendering a list and when I specify value of text input I can no longer edit that value because it's outside the state, I don't want to use placeholder to show the value, I need a way to have it as value but also be able to edit that value.
<TextInput
keyboardType='decimal-pad'
value={String(roomData.room_attached_dimensions.depth)}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
Also I don't understand why should I wrap my values with String, it shows nothing otherwise.
My list looks like so
const attachedRooms = this.state.rooms_attached.map((item, index) => (
<View key={index}>
...
</View>
))
The function does nothing special
handleRoomEdit = (value) => {
this.setState({ roomEdit: true, value: value })
}
Of course I have different inputs I cannot simply give them different names, the data is stored on asyncStorage and even if I edit the array it dont work unless I re mount the damn component
Okay there's you error. You are not handling your input's value with state. That's why it does not work. You can do something like this -
<TextInput
keyboardType='decimal-pad'
value={this.state.value || String(roomData.room_attached_dimensions.depth)}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
I think this should work. Now you are handling your input's value with state. Or you can use defaultValue to give initial value, but I think react discourages using defaultValue and Value both -
<TextInput
keyboardType='decimal-pad'
defaultValue={String(roomData.room_attached_dimensions.depth)}
value={this.state.value}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
EDIT:: Also you can use ES6 to make your code clean -
handleRoomEdit = (value) => {
this.setState({ roomEdit: true, value }) //use ES6 shorthand //
}
I have a functional component that contains user input and it is child of a class component which contains the state with the input. In the child functional component I want a function that can swap values between two TextFields(https://material-ui.com/api/text-field/).
What I have tried so far:
<TextField
id="outlined-from"
label="Από"
className={classes.textField3}
value={transport_detail[idx].from}
onChange={handleDynamicChange('from', idx)}
ref={x => from = x}
/>
<IconButton onClick={()=>{
var temp = from.value;
console.log(temp)
from.value = to.value;
to.value = temp;
}}>
<SyncIcon/>
</IconButton>
<TextField
id="outlined-to"
label="Προς"
className={classes.textField3}
value={transport_detail[idx].to}
onChange={handleDynamicChange('to', idx)}
ref={x => to = x}
/>
I tried using ref, but as I see from the docs it is only used with class components.
Anyone has any solution to this?
Since you are already saving the values of the textfields in the state, you can remove the ref and just change, how you save the texts. This will let you easily swap the contents.
Here is a sandbox, to show you the final result.
Just like in your example, the functional component gets the values and the handleDynamicChange function. This will populate the textfields and updates on changes of the text.
The button simply calls handleDynamicChange for each value with the opposing key:
handleDynamicChange("to", idx)({ target: { value: transport_detail[idx].from} });
handleDynamicChange("from", idx)({ target: { value: transport_detail[idx].to} });
This will set the value of the from text field to the value of the to textfield and vice versa.
Obviously, you need to adjust the values to fit your data structure, but this should work, without the need of refs.