Updated state not reflecting properly - javascript

I have below code where I am checking or unchecking the checkbox based on some conditions, and I came across an issue where I am trying to check the checkbox, and it is failing the first time and from the second time onwards works perfectly.
export const AntdDefaultOverrideInputNumberAdapter = ({
input: { onChange, value },
disabled,
defaultValue,
formatter,
...rest
}) => {
const [isDefaultValueOverriden, setIsDefaultValueOverriden] = useState(
!!value && value !== defaultValue
);
const handleCheckboxChange = () => {
const hasOverride = !isDefaultValueOverriden;
setIsDefaultValueOverriden(hasOverride);
onChange(hasOverride && !!value ? value : defaultValue);
};
const handleOverrideChange = (v) => {
onChange(v);
};
return (
<Badge
offset={[0, -6]}
count={
<div>
<Checkbox
disabled={disabled}
checked={isDefaultValueOverriden}
onChange={handleCheckboxChange}
style={{ zIndex: 10 }}
/>
</div>
}
>
<InputNumber
size="small"
onChange={handleOverrideChange}
disabled={disabled || !isDefaultValueOverriden}
style={{ width: 65 }}
value={isDefaultValueOverriden ? value : defaultValue}
formatter={formatter}
{...rest}
/>
</Badge>
);
};
I am not sure where I am wrong with the above code, The problem only appears on trying to check the checkbox the first time, and it disappears from the second time onwards..
Could anyone suggest any idea on this? Many thanks in advance!!
I am using the "ANTD" library for the checkbox, and the "value" is an empty string, and the defaultValue is "5"

Related

Material UI Autocomplete: highlighted option should become input value

When a user browses through the options using the arrow keys on his keyboard, I take the value from the highlighted option and use it as the current input value (input here has its own state).
Unfortunately, the highlighted state of the option is lost upon saving the title or value of the option as the input. Is there a way to not lose it?
Here is an example:
https://codesandbox.io/s/modern-rgb-5tew1p?file=/demo.tsx
P.S.:
Although this property sounded like it was made for it, includeInputInList does not help.
Thanks in advance!
Try this (I made some changes to your code like adding reason and isOptionEqualToValue):
export default function ComboBox() {
const [input, setInput] = React.useState(null);
const handleInputChange = (event, value) => {
setInput(value);
};
const handleHighlightChange = (event, option, reason) => {
if (option && reason === "keyboard") {
setInput(option);
}
};
const handleFilterOptions = (currentOptions) => currentOptions;
return (
<Autocomplete
id="combo-box-demo"
value={input}
onChange={handleInputChange}
options={top100Films}
isOptionEqualToValue={(option, value) => option.label === value.label}
includeInputInList={true}
onHighlightChange={handleHighlightChange}
getOptionLabel={(option) => option.label}
filterOptions={handleFilterOptions}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}

Editing an input field among many in React

check this code please https://stackblitz.com/edit/react-koqfzp?file=src/Section.js
Everytime i add an item, i'm also adding an random number that i want to edit. The number is rendered at a MUI Text field component.
<TextField
type="number"
variant="standard"
aria-readonly={edit === true ? false : true}
value={edit === true ? value : numbers[i]}
onChange={(e) => setValue(e.target.value)}
/>
And the buttons are rendered based on edit's state, like this:
{edit === true ? (
<button onClick={() => saveEdit(i)}>Save</button>
) : (
<button onClick={() => setEdit(true)}>Edit</button>
)}
And it's working, i can edit it and rerender with the new value, the problem is that when i click the edit button, every field receives the new input value and the save button shows up in every field, though when i save it, it returns to it's original value. How i can do what i'm doing but to just one specific field?
The problem is that you are using setEdit as a boolean
You can define it as the index of the array to edit with -1 as starting value
const [edit, setEdit] = useState(-1)
...
{edit === i ? (
<button onClick={() => saveEdit(i)}>Save</button>
) : (
<button onClick={() => setEdit(i)}>Edit</button>
)}
I recommend creating another component Exemple:Item with it has it's own states edit,value states
And pass the needed props to it which are the value,numbers,saveEdit(index,newValue),removeItem(index) and also the index
saveEdit has to be changed in section by passing the index and the newValue
I hope this clear for you
add the map values in a component and add the states inside the component so you will have multiple states for each component not just 1
parent component
{section.items.map((item, i) => (
<Component key={i} item={item}/>
)}
child component
const Component = ({ section, addItem, removeItem}) => {
const [newItem, setNewItem] = useState('');
const [edit, setEdit] = useState(false);
const [value, setValue] = useState(0);
const [numbers, setNumbers] = useState(section.number);
const handleChange = (e) => {
setNewItem(e.target.value);
};
return (
<TextField
type="number"
variant="standard"
aria-readonly={edit === true ? false : true}
value={edit === true ? value : numbers[i]}
onChange={(e) => setValue(e.target.value)}
/>
)

How to remove text from previous element if condition is not satisfied - reactjs

I'm making small app in react js which basically would display SELECTED if item is selected.
Here is my code:
import React, { useState } from 'react';
function SelectedFiles(props) {
const [selectedFile, setSelectedFile] = useState(0);
const selectSelectedFileOnChange = id => {
setSelectedFile(id);
props.onSetSelectedFile(id);
};
return (
<MainContainer>
<RadioButton
key={props.id}
value={props.id}
name="Acfile"
onChange={e => {
selectSelectedFileOnChange(props.id);
}}
disabled={false}
></RadioButton>
<span>{props.file.name}</span>
<span>{props.file.size}</span>
<span>{props.file.isPrimary === true ? 'SELECTED' : null}</span>
</MainContainer>
);
}
export default SelectedFiles;
This component is part of parent component and purpose of this component is just to display an items:
<AddF className="modal-body">
{docs && docs.length > 0
? docs.map(file => (
<SelectedFiles
key={file.id}
id={file.id}
file={file}
onSetSelectedFile={handleSetPrimaryFile}
/>
))
: null}
</AddF>
const handleSetPrimaryFile = id => {
props.onSetPrimaryFile(id);
};
As its possible to see guys I dont know how to remove text from NOT SELECTED element..
Thanks guys ! Cheers
Could you please try below and see if it works?
const [files, setFiles] = useState({docs[0].id: true});
<AddF className="modal-body">
{docs && docs.length > 0
? docs.map(file => (
<SelectedFiles
key={file.id}
id={file.id}
file={file}
isPrimary={!!files[file.id]}
onSetSelectedFile={handleSetPrimaryFile}
/>
))
: null}
</AddF>
const handleSetPrimaryFile = id => {
setFiles({[id]: true});
props.onSetPrimaryFile(id);
};
Change SelectedFiles.js as
<span>{props.isPrimary === true ? 'SELECTED' : null}</span>
Hope it helps.
This snippet {props.file.isPrimary === true ? 'SELECTED' : null} is determining when SELECTED should appear. But I don't see where props.file would ever change.
I also see you using both the useState hook and some sort of prop function passed in to handle selection.
The solution is to have some sort of unique identifier for the files (perhaps that's file.id), then check this value on the selectedFile to determine if SELECTED should appear, e.g., props.file.id === selectedFile.

React Material UI - Make Slider update state

I am building a multi-step form (survey) with React.js and Material-UI components library.
At the step with a slider, the component doesn't update the state. I was trying to set value with setValue from React.useState() and other various methods. Didn't work out. Does anybody know what the problem is? I'm stuck.
Here is the link to Codesandox: project's code
Code of the Slider component:
import React from 'react';
import { Slider, Input } from '#material-ui/core/';
export default function DiscreteSlider({ values, handleChange }) {
const [value, setValue] = React.useState(values.areaSpace);
const handleSliderChange = (event, newValue) => {
setValue(newValue);
};
const handleInputChange = event => {
setValue(event.target.value === '' ? '' : Number(event.target.value));
};
const handleBlur = () => {
if (value < 0) {
setValue(0);
} else if (value > 100) {
setValue(100);
}
};
return (
<div onChange={handleChange('areaSpace')} style={{marginTop: '20px', marginBottom: '20px'}}>
<Input
value={value}
margin="dense"
onChange={handleInputChange}
onBlur={handleBlur}
inputProps={{
step: 1,
min: 0,
max: 800,
type: 'number',
'aria-labelledby': 'input-slider',
}}
/>
<Slider
style={{marginTop: '20px'}}
value={typeof value === 'number' ? value : 0}
onChange={handleSliderChange}
aria-labelledby="input-slider"
step={1}
min={0}
max={800}
onChangeCommitted={handleChange}
/>
</div>
);
}
On your Slider you have the following:
onChangeCommitted={handleChange}
The handleChange above is being passed from MainForm.js which defines it as:
// Handle inputs change
handleChange = input => event => {
this.setState({ [input]: event.target.value });
}
When that function gets called, all it is going to do is return another function. You need to call handleChange("areaSpace") in order to get a function that will then try to set the "areaSpace" state when it is called. Another problem is that the change function is getting the value from event.target.value, but for the Slider the value is passed as a second parameter.
The following code addresses both of these issues:
onChangeCommitted={(event, value) =>
handleChange("areaSpace")({ target: { value } })
}
There are more elegant ways of dealing with this, but the above fixes the problem without changing any other layers. It does still leave another problem which is that if you change the input instead of the Slider, the areaSpace state won't be updated, but I'll leave that as a problem for you to work through.

Material-ui Textfield null value for zero

I have a Material-Ui TextField handled with Formik.
Input value (string) is converted to number on Input Change.
My problem is that when the value number zero passes, it's considered as a false value and renders an empty string.
I want it to get 'number zero' showing in TextField.
If I removes TextField value condition ( value || ' ' ), It will give me a warning message below.
Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components.
How can I work around with it ?
input.js
const Input = ({
classes,
icon,
styleName,
field: { name, value, onBlur },
form: { errors, touched, setFieldValue },
...props
}) => {
const errorMessage = getIn(errors, name);
const isTouched = getIn(touched, name);
const change = (e, name, shouldValidate) => {
e.persist();
const inputValue = e.target.value;
let value;
if (inputValue !== '') {
value = isNaN(inputValue) ? inputValue : parseInt(inputValue, 10);
} else {
value = null;
}
return setFieldValue(name, value, shouldValidate);
};
return (
<TextField
name={name}
value={value || ''}
onChange={e => change(e, name, true)}
onBlur={onBlur}
{...props}
className={classes[styleName]}
helperText={isTouched && errorMessage}
error={isTouched && Boolean(errorMessage)}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<Icon
name={icon}
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
/>
</InputAdornment>
),
}}
/>
);
};
I experienced a situation like this in some of our projects.
This isn't specific to Material-UI but to react.
To work around this, just set the initial value to an empty string ''.
So far we're fine with setting the value to an empty string since it's the default event.target.value of input type number when it's empty.
See: https://codesandbox.io/s/affectionate-stonebraker-cgct3
The suggested solution did't work for me.
Number 0 is falsy. so it renders an empty string.
I resolved it with this approach.
const input = value === 0 || value ? value : '';
return (
<TextField
name={name}
value={input}
...
/>
);

Categories