(React) How to make checkbox UI look checked after mutating state? - javascript

How to change the UI of the CheckBox component? State mutates finely as I wanted, however the checkbox doesn't look checked after the onCheck call (when click it).
I guess I must create or use an existing props for input objects:
onCheck = item => {
this.setState(prevState => ({
usage: prevState.usage.concat(item.label, ",")
}));
//Todo: Display as checked
};
{checkboxes.map(item => (
<div className="d-inline-block w-50 p">
<CheckBox
name={item.name}
onChange={this.onCheck.bind(this, item)}
/>
<label key={item.key}>{item.label}</label>
</div>
))}
const CheckBox = ({ type = "checkbox", name, checked = false, onChange }) => (
<input type={type} name={name} checked={checked} onChange={onChange} />
);

Welcome to the community, you need to pass checked true/false to the CheckBox component
<CheckBox
name={item.name}
checked={this.state.usage.includes(item.label)}
onChange={this.onCheck.bind(this, item)}
/>
Also you don't need to include ',' while concat as it is creating an array
Refer link for reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat

You need to include the checked property and you can use a state to handle it. Let's say "isChecked".
Example:
<CheckBox checked={this.state.isChecked} \> (+ your previously added properties)
And you'd include something like this in your function:
this.setState((prevState) => { isChecked: !prevState.isChecked});

Related

how to get value in dynamic text input in react.js?

I made one page in react.js project that has a text input and a button for each row of data.
I want to get each input value by on click button and do process over it.
{data.map((item, index) => <div><span>{item}</span>
<input type="text" placeholder='enter value' />
<button onClick={() => {alert(inputValue) }}>
click me
</button>
</div>
)}
You can do something like this
const data = [0, 1, 2, 3];
export default function App() {
const [inputs, setInputs] = useState({});
return (
<div className="App">
{data.map((item) => (
<div key={item}>
<input
onChange={(e) =>
setInputs((prev) => {
return { ...prev, [item]: e.target.value };
})
}
/>
<button onClick={() => alert(inputs[item])}>Click</button>
</div>
))}
</div>
);
}
Codesandbox: https://codesandbox.io/s/divine-wildflower-1ge7ev?file=/src/App.js:58-550
The correct react way of doing this would be to create a standalone component e.g. UserInput and keep track of user input's state:
// Create state
const [input, setInput] = React.useState('')
return (
<input type="text" placeholder='enter value'
onChange={event => setInput(event.target.value)}
/>
<button onClick={() => {alert(input) }}>
click me
</button>
);
You can then add this to your current component as follows:
{data.map((item, index) => <div><span>{item}</span><UserInput/></div>)}
I suggest you use an object instead of an array. It's more appropriate for key-value pairs.
If you use an object, it will be easier, readable and more maintainable.
How to do this?
You just need to modify your code to loop through the keys of your object then every time the input value changes (onChange), then set the value of the object onChange={(e) => data[key]=e.target.value}. To access the value when the button of the field is clicked, just use the data[key].

Having an issue getting vaues to onClickHandler Due to MUI

So I want to get a category navigation which contains icons and labels.
I've tried with Chips:
{categories.map((category) => (
<Chip
key={category._id}
avatar={<Avatar alt={category.name} src={category.icon} />}
label={category.name}
variant="outlined"
onClick={(e) => handleClick(e)}
value={category._id}
/>
))}
Ive tried using Tabs -> Tab. But they don't produce a "value" when i
const handleClick = (e) => {
const valueTargeting= e.target.value;
console.log(valueTargeting);
};
Is there a way to use any of these, or do I have to resort to designing a button?
Also notice they do output a "value" when clicked at a certain area(which is small surface area). Is that a bug on my part?
Chip is not returning the expected value is because the Chip does not explicitly maintain a value. In order for it to return a value to your event handler, you'll need to wrap the value that you want it to return in the onClick handler itself. For example:
{categories.map((category) => {
return (
<Chip
label={category.name}
// Notice 'category._id' being sent from the handler, not `e`
onClick={handleClick(category._id})}
/>
);
})}
Working MUI 4 Code Sandbox: https://codesandbox.io/s/chip-click-mui4-ggl0z?file=/demo.js:940-1325
Working MUI 5 Code Sandbox: https://codesandbox.io/s/chip-click-mui5-y5xkk?file=/demo.js

Could not console log the updated state array

I am making a simple application where the user can create a new form on a button click, so for this, I have an array state like this :
const [numbers, setNumbers] = useState([0]);
const [count, setCount] = useState([0]);
And on my button onClick method I have this,
setCount(count + 1);
setNumbers(numbers.concat(numbers[0] + count));
In my render method, I have :
{numbers.map((number) => {
return (
<div key={number}>
<InputCreator id={number} value={number} />
</div>
);
})}
And my InputCreator component is a simple callback component with few textfields.
So far, it works well. Lately I wanted to add a delete functionality where the user can delete that particular form. So, I added.a button inside this form and on the onClick method, I tried console loging the "numbers" state to check everything is working, but it logs only the default value I have given while creating the state and not the updated state. What could be the reason ? So my idea is to delete that index from the array using the props passed, so that the component will re-render with the updated number of forms. Is there a better way to do this ?
EDIT : This is my InputCreator component,
const InputCreator = useCallback((props) => {
const { id, value } = props;
// console.log(titles[id]);
return (
<div>
<Col xs={12} md={8}>
<div className={styles.container}>
<Form
noValidate
validated={false}
onSubmit={handleSubmit}
encType="multipart/form-data"
>
<Form.Group controlId="formGroupTitle">
<Form.Label>Title</Form.Label>
<Form.Control
type="text"
placeholder="Title"
onChange={(e) => handleChange(e, value)}
name="title"
value={titles[id]}
/>
</Form.Group>
<Form.Group controlId="formGroupTitle">
<Form.Label>Description</Form.Label>
<Form.Control
type="text"
name="description"
placeholder="Max limit 30"
onChange={(e) => handleChange(e, value)}
maxLength={31}
value={descriptions[id]}
/>
</Form.Group>
<Button
variant="outline-primary"
size="sm"
className={styles.deleteBtn}
onClick={(e) => handleDelete(e, number)}
>
X
</Button>
</Form>
)})
handleDelete :
const handleDelete = (e, value) => {
e.preventDefault();
console.log(numbers);
}
I will just point out the mistakes I see as your question is not worded clearly.
Keys aren't passed into they are passed into list in order to create a list for every element with a unique ID. I am not sure what you are trying to do in your render method but I would suggest doing something like this :
const renderNumbers = () => myArray.map((number, index) =>
<MyComponent key={index} number={number} />
To delete an element. Create a function that takes in the ID. Filter it to show a new array without that ID, below is an example that you ca apply.
const deletePerson = (id) => {
setNumbers(numbers.filter((number) => number.id !== id));
};
Send this handle to the button that deletes the element
const handleDeleteNumber = () => {
deleteNumber(number.id);
};
Make a single handleInputChange() that you can use for all input changes. Such as this one :
const handleInputChange = (event) => {
setInfo({ ...info, [event.target.name]: event.target.value });
};
In the tag you pass in id and values separately like this
value={descriptions}
key={id}

How to get selected data from child state to parent in React

I have a flight page with various cards with different route information in each. Within each card I have a select button which is identified by the flightID.
Select(FD) {
this.state={route:''};
return (
<div>
{FD.FlightID}
<label>
<Checkbox id={FD.FlightID}
name={FD.FlightID}
checked={this.setState.route}
onChange={this.handleCheckboxChange}
/>
<span>Select</span>
</label>
</div>
)
}
The Select method is called within each card.
return data.map( FD1 => (
<Row>
<Card className="card">
<Card body className="text-center">
<CardTitle data-es-label="location"> Location:
{FD1.Departure}
</CardTitle>
<CardText data-es-label="Price">Price
{FD1.price}
</CardText>
{this.Select(FD1)}
<CardActions>'
How do I access the data of the specific card selected to send to make a booking?
EDIT:
the handleCheckBoxChange
handleCheckboxChange = event =>
this.setState({ route: event.target.checked });
One way to do this is to pass id in onChange method like this
<Checkbox
...
onChange={() => this.handleCheckboxChange(FD.FlightID)}
/>
Then in parent component you can get your element from data array like this
handleCheckboxChange = (id) => {
const selected = data.find(e => e.FlightID = id);
...
}
If you want to pass some data through more components you need to read about React context (https://reactjs.org/docs/context.html)
try this.
<Checkbox
id={FD.FlightID}
name={FD.FlightID}
checked={this.setState.route}
onChange={() => this.handleCheckboxChange(FD)}
/>

Material-UI Disabled attribute not working

I'm trying to disable the edit button once i click on complete but it is not working. I have passed in the state in disabled attribute but it seems not doing anything, don't know maybe because of setState's asynchronous nature. I passed callback while calling setState method and it seems logging data randomly, Can someone suggest what should be done ?
class App extends Component {
state = {
buttons: {
id: "test"
}
};
handleCheckBox = id => {
let buttons = Object.assign({}, this.state.buttons);
buttons.id = !this.state.buttons[id]
this.setState({buttons}, ()=>console.log(this.state.buttons));
}
render() {
return (
<div>
{todos.map(todo => (
<List key={todo.id}>
<ListItem
role={undefined}
dense
button
>
<Checkbox
onClick={()=>this.handleCheckBox(todo.id)}
checked={todo.complete}
tabIndex={-1}
disableRipple
/>
<ListItemText primary={todo.text} />
<ListItemSecondaryAction>
<Button mini color="secondary" variant="fab" disabled={this.state.buttons[todo.id]}>
<Icon>edit_icon</Icon>
</Button>
ListItemSecondaryAction>
</ListItem>
</List>
))}
</div>
);
}
}
Instead of using id to change the state use index of Array to update the state
Create an array in Component state which tracks the disabled attribute of each buttons
state = {
buttons: Array(todos.length).fill(false),
};
In componentDidMount initialise the array according to todos
componentDidMount(){
const buttons=this.state.buttons.slice();
for(var i=0;i<buttons.length;i++)
buttons[i]=todos[i].complete;
this.setState({buttons:buttons})
}
Now use the value in buttons state for disabled attribute of button based on the index of the component being rendered.
<Button mini color="secondary" variant="fab"
disabled={buttons[todos.indexOf(todo)]}>
Whenever CheckBox is clicked pass the index to the handleChange function and update the value corresponding to the index value
<Checkbox
onClick={() =>this.handleCheckBox(todos.indexOf(todo))}
checked={buttons[todos.indexOf(todo)]}{...other}
/>
handleCheckBox = index => {
const buttons=this.state.buttons.slice();
buttons[index] = !buttons[index];
this.setState({
buttons:buttons
})
}

Categories

Resources