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)}
...
/>
Related
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)
}
I am new to ReactJS and pairing it with Material UI is really causing me some roadblocks. I have created a reusable search filter component for my data tables and it worked exactly the way I wanted, but now I want to add a button to clear the field and show the unfiltered results, as well as return the InputSearch component back to its default state so it will display the label inside the field again, not up in the field’s border as these Material UI TextFields do then they are focused or have a current value. This is where I am hitting my roadblock. I have tried multiple solutions I found online, like using the inputRef/useCallback method to change the values, but it didn’t seem to work…or maybe I misunderstood and did it wrong. I was also recommended to put my search values to state. As happens with state my searches are now always one render behind (I.E. , results matching ‘US’ for ‘USA’ , ‘USA’ for ‘USAF’, etc…). Then when I run the handleFilterReset function to set the filter values back to an empty string, nothing happens. I just want my search filter to work instantly (like it did before I moved the value to state [commented out]) and be able to be cleared, resetting the table back to its default display.
Can someone please help me figure this out? Suggestions are appreciated, but code snippets are much more helpful since I am really new to React and especially Material UI.
dataTable.js
const [inputValue, setInputValue] = useState('')
const [searchFn, setSearchFn,] = useState({ fn: items => { return items; } });
// Searching Data
const handleSearch = e => {
setInputValue(e.target.value) // value displayed in input field
let query = (e.target.value).toString().toLowerCase();
setSearchFn({
fn: items => {
if (query === "")
return items;
else
return items.filter(x =>
(x.tankName !== null && x.tankName.toLowerCase().includes(query)) ||
(x.dimensions !== null && x.dimensions.toLowerCase().includes(query))
)
}
})
}
// Clearing Filters
const handleFilterReset = () => {
setInputValue('');
setSearchFn({fn: items => {return items;}})
};
// Search and filter Inputs
<div>
<InputSearch
value={inputValue}
onChange={handleSearch}
/>
<Button
text="Reset"
onClick={handleFilterReset}
/>
</div>
InputSearch.js
export default function InputSearch(props) {
const { inputRef, name, value, error=null, onChange, ...other } = props;
return (
<TextField
label="Search..."
name={name}
value={value}
onChange={onChange}
{...other}
{...(error && {error:true, helperText:error})}
>
</TextField>
)
}
You need to pass the value to InputSearch
Heres an example:
https://codesandbox.io/s/morning-brook-durbvd?file=/demo.tsx
React has a pretty good introduction on its site.
https://reactjs.org/docs/components-and-props.html
The code has been updated with a solution to this issue. I created a display value for the input that I passed to state, which was set to a blank string when the reset is pressed as well as passing an unfiltered data set.
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 }));
}
};
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.