If check box checked disable other, if unchecked enable all in react - javascript

I'm stuck in a sutiation where I need to disable the check boxs except the one which is checked.
The checkbox is dynamically created with the help of API and key will be passed to each checkbox. Is there a way to achieve above requirement.
Thanks
{this.state.imageinfo.map((image, key) => {
return(
<div key={key}>
<input type="checkbox"
onClick={(e)=> this.setCoverImage(e,key)}>Cover Image
<div className="delete-image" onClick={() => this.removeImage(key)}>
×
</div>
</div>
);
})
}

You could have that checkbox change a boolean saved in state and have the disabled attribute of all the others equal to that sate object.

use radio instead of checkbox
checkboxes behaviour is multiple selection, while radio isnt
if you want to use checkboxes:
setCoverImage(e, key) {
...
this.setState({active: key})
}
render() {
...
<input type="checkbox"
onClick={(e)=> this.setCoverImage(e,key)} checked={this.state.active === key}>

You are required to set a checked keyword which is boolean in an array which is set in your state. When ever function is called then it will set checked keyword in only that element of Array where the key is provided. Rest of The checked keyword in Arrays will be deleted.and then you will set the Updated Array in your State. Like this.
setCoverImage=(key)=>{
const ItemKeyTobeChecked=key;
const imageinfoArray=this.state.imageinfo;
for(var i=0;i<imageinfoArray.length;i++){
if(key===i){
imageinforArray[key].checked=true;
}
else{
if(imageinforArray[i].checked){
delete imageinforArray[i].checked
}
}
}
this.setState({
imageinfo:imageinfoArray
})
}

Related

Enable Disable multiple checkboxes in React Bootstrap Table Next

I'm having a hard time trying to enable/disable checkboxes using Bootstrap Table Next and React.
For the checkboxes I'm using a column formatter like this:
formatter: (cell, row) => {
return (
<div className='text-right togglebox form-check form-check-inline'>
<input type="checkbox" checked={ row.isInMaintenanceMode } disabled={ row.isReadOnly } className="form-check-input" onChange={(e) => {
row.isReadOnly = true;
if (row.isInMaintenanceMode) {
this.props.update(row.name, { "/redirect" : false });
} else {
this.setState({ isModalOpen: true, server: row.name, isInMaintenanceMode: !row.isInMaintenanceMode });
}
}}
/>
</div>
);
},
Updating the maintenance mode status takes a while and I'd like to disable the checkbox to prevent multiple clicks. Setting row.isReadOnly to true doesn't do anything and no changes are reflected in the column, the checkbox will only be disabled if the isReadOnly property is initially set to true.
Additionally, before setting the maintenance mode to true (NOT the isReadOnly property) the user is presented with a confirmation modal which then calls the update method and then automatically closes, so I'd like to be able to also disable the checkbox from the modal itself.
I've tried using state but I'm not sure it's the right approach as there are potentially hundreds if not thousands of records.
Can anyone tell me what I'm doing wrong?
Thanks

useState to check if all radio boxes selected

I in my React Application, I have a set of mapped questions from backend data where the user selects a response with a radio button:
<RadioGroup row>
{data.response.map((dt, rIndex) => {
return (
<div className="answerContainer">
<FormControlLabel
className="MuiTypography-body1"
value={dt.value}
onChange={() => {
debugger;
setAnswer(
dt.value,
data.questionTitle,
qIndex,
rIndex
);
}}
checked={selectedAnswers[qIndex] === rIndex}
control={
<Radio
className="PrivateRadioButtonIcon-root-9"
required={true}
/>
}
label={dt.value}
/>
</div>
);
})}
</RadioGroup>
I want to disable the "next" navigation button unless all answers are checked off. I created a state called proceed which by default is false:
const [proceed, setProceed] = React.useState(false);
In my handleChange event if the number of questions is less than the number of answers, the button is disabled.
const setAnswers = async () => {
if (questionsData.length < selectedAnswers.length) {
setProceed(false);
return;
}
Then I added this statement in my setAnswers handleChange function to check if the user can proceed to the next page in the stepper:
if (questionsData.length === selectedAnswers.length) {
setProceed(true);
}
Finally I pass the handleChange function into my button:
<button
className={proceed ? 'enabled' : 'disabled'}
onClick={() => {
setAnswers();
}}
> Next </Button>
The setProceed === false condition works correctly. set proceed === true appeared to be working, but I discovered if I clicked the last answer in the questions without clicking the others, setProceed is === true is triggered and the button is enabled, allowing users to skip the questions.
I added the required flag to the MUI radio button, but the function bypasses it.
Similar to this answer on S/O (which is related to PHP), How can I ensure that all answers must be selected before enabling this state change in React?
Instead of using the length to compare if the all the values are filled . you can use the every from Array.
If your selected Answers contains a list of boolean ( [ true, false ] ) values then you can do
const isAllAnswersSelected = selectedAnswers.every(Boolean)
isAllAnswersSelected will be true if all the items in the selectedAnswers is true else it will return false.
Refer
Array Every
Material UI doesn't provide validations and you must take care of validations and error state yourself.
required form attribute adds the asterisks to the label and not the validations.
<Radio className="PrivateRadioButtonIcon-root-9" required={true} error={questionHasError(qIndex)}/> will again add style level error indicators.
You can maintain a state of answered questions instead?
const [answeredQuestions, setAnsweredQuestions] = useState([]);
.
.
.
const setAnswers = async (qIndex) => {
const updatedAnsweredIdx = [...answeredQuestions, qIndex];
setAnsweredQuestions(updatedAnsweredIdx );
// check if all the questions have been selected/answered
if(allQuestionIndex.every(idx => updatedAnsweredIdx.includes(idx))){
setProceed(true);
} else {
setProceed(false);
}
}
You can then enhance validations by tracking if question is answered and pass error prop to highlight error state.

Removing dropdown and text field from row removes incorrect field on State Change in ReactJS

I have a row which includes a React-Select Dropdown and an input field. I am trying to Remove a specific row by its index. I am passing the index in my handler function and want to remove both the fields from the row. The input field is getting removed correctly, but the dropdown value is not getting removed from the same row and it deletes the dropdown from the last index.
I am removing the row with the help of index in this handler
Removing the row by its index:
handleRemoveSocial(idx) {
let someArray = this.state.SocialData;
someArray.splice(idx, 1);
this.setState({ SocialData: someArray });
}
I am rendering the Select Dropdown and Textbox with the help of map method, mapping to the array in my state. Now, How can i map the Select dropdown value from the same row when i remove the textbox. I have included the Sandbox link in this post.
{this.state.SocialData.map((Social, idx) => (
<div className="form-group" key={idx}>
<label htmlFor={"socialprofile"} className="control-label">
Social profile
</label>
<div className="form-input-container select-social-link">
<Select
data-id={idx}
className="profile-module-select-container"
classNamePrefix="profile-module-select"
options={options}
onChange={(selected) => {
this.handleSocialNameChange(selected.value, idx);
}}
onMenuOpen={() => {
this.setState({
selectMenuOpen: true
});
}}
onMenuClose={() => {
this.setState({
selectMenuOpen: false
});
}}
components={{
IndicatorSeparator: () => null
}}
placeholder={"Select"}
isSearchable={false}
isClearable={false}
/>
</div>
<div className="form-input-container input-social-link">
<input
type="text"
id={`${SocialData[idx].socialname}-${idx}`}
className="social-form-control"
placeholder={`Social Url - ${Social.socialname}`}
value={SocialData[idx].name}
onChange={(e) =>
this.handleInputVlaueChange(e.target.value, idx)
}
/>
SANDBOX
This is where the problem is happening within handleSocialNameChange() Handler when change event is fired here.
onChange={(selected) => {
this.handleSocialNameChange(selected.value, idx);
}}
Using index as ids is overall not a good idea. Because they mess up things later and we have to add additional logic to the code as well.
We can use uuid() library or a trick new Date().getTime().toString() for our Ids efficiently.
Working code of CODESANDBOX Link:
https://codesandbox.io/s/reasontosmile-n6ww4?file=/src/App.js
Enjoy :)
You cannot set the index value as key. That will cause issues when adding and removing elements.
Also, don't use array.splice use array.filter. The splice will mutate the original state array.

Controlling a checkbox in react

I'm trying to create filters in react, where i manipulate the url to return me products based on colours, cost etc
its working so if you change ?color=red to ?color=white in the url it will display different products on the page
it's also working whereby if you select the colours in my checkbox filter component it will update the url and then display the new products. i.e click on red will change the url from /sport to /sport?color=red and then returns me just the products with red
however this is my problem
if I manually change the url, I then want the checkbox checked so I tried to do this:
checked={option.text === this.getParams() ? true : false}
this does actually work but then I lose the ability to actually select and deselect the checkbox. any ideas how I can get it to do both? I guess making it a controlled and uncontrolled component simultaneously??
You need to store the filters in the state. like in your constructor you can init your state with the query parameter and then change the state upon checkbox change.
You could try something like this. You will need to change this code according to your usage, here I am assuming, this.getParams('color') will return an array of all the selected colors.
constructor state init
constructor(props) {
super(props);
this.state = {
filters: this.getParams('color') // consedering, it will return array
}
}
default check the checkbox
defaultChecked ={this.state.filters.indexOf(option.text) === -1 ? false : true}
onChange={() => this.toggleCheckbox(option.text)}
for toggling it
// if not present, then add it
// else remove it
toggleCheckbox(option) {
if (this.state.filters.indexOf(option) === -1) {
this.setState({
filters: [...this.state.filters, option]
})
} else {
this.setState({
filters: this.state.filters.filter(text => text !== option)
})
}
}
You should set the state of the checkbox in the component state, and then update that state when it's clicked. You can set the initial state based on the url on construct or mount.
Something like this:
constructor(props) {
super(props);
const isChecked = this.props.match.params.checkbox === 'true';
this.state = {
checkbox: isChecked
}
}
And then in your checkbox:
<input type="checkbox" checked={this.state.checkbox} onChange={() => this._toggleCheckbox()} />
And the method to turn it on and off would be something like:
toggleCheckbox() {
this.setState({
checkbox: !this.state.checkbox // will toggle to the opposite of the current state
});
}
Note that this is has not been tested but has been written based on the information you gave. The principle behind this is what you need to do. It may also be useful to set the state of the checkbox initially within componentDidMount(), rather than constructor(), but that's up to you. The onChange function of the checkbox uses ES6, but you could bind the function if you prefer or do not use ES6 with this._toggleCheckbox().bind(this)
Edit
To update the checkbox when the url is changed, rather than updating it on click, you could change the toggle method to redirect the browser, and then update the checkbox within componentWillReceiveProps.
Taken from my own code with react-router you can use 'this.props.match.params' to find the url parameters. I use react-router-dom package to update the url. So for instance:
This will give you access to this.props.history.
import { withRouter } from 'react-router-dom';
toggleCheckbox() {
// Check the current state of the checkbox and update the url to the opposite
let toCheck = this.props.match.params.checkbox === 'true' ? 'false' : 'checked';
this.props.history.push('/?checkbox=' + toCheck);
}
componentWillReceiveProps(newProps) {
// Check the new url and update the checkbox if it is different from the checkbox state
if(newProps.match.params.checkbox != this.state.checkbox) {
this.setState({checkbox: newProps.match.params.checkbox});
}
}

Dynamically adding input fields and keeping track of what was entered

I am wanting to dynamically create input field values for each category a user creates, the issue is how can I keep track of what the user enters into the input field. As I cannot create X amount of states as it is dynamic. Any tips would be much appreciated, my code is shown below:
var categories = newData.map((category,index) => {
console.log(category)
return (
<div className="content row marginCenter" key={category._id}>
<p>{category.category}</p>
<input type="text" /> //How do I keep track of what was entered for this input field??
<button onClick={() => this.addCategoryLink(category._id)}>Add
link</button>
</div>
)
})
I am wondering how to bind that to the button element
The React docs have a section related to the core of this question:
https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers
Assuming your state holds an array of "categories" objects- essentially, I think what you're looking for boils down to something like this in your map function:
{this.state.categories.map(category => (
<input
type="text"
onChange={event => this.handleCategoryChange(category, event)}
value={category.value}
/>
)}
And then a change handler that looks something like this:
handleCategoryChange = (category, event) => {
const value = event.currentTarget.value;
this.setState(state => {
// Create a copy of the categories array:
const categories = [...state.categories];
// Create a copy of the category, with an updated value:
categories[category.index] = {
...category,
value
};
// Update state with the new values:
return { categories };
});
};
Here's a simple demo:
https://codesandbox.io/s/woqpwvl777
i have other Way for doing this , Of course this way just working well in some situation , forExample when you have just 1 or 3 value
i think you wanna create Input , and there Input are dynamic , and you want define that , if user click in first Button , you get and use first TextInput (value)
in my way ( again i say this : this way just well in some situation ) , we Create data Json like this
[
{ id: n ,
category: 'some',
value: ''
}
in this structure Value key , in the mounting contain nothing or null value if the Value not defined before
for now i create one handler method and this method, called after onChange Event fired on
<input onChange={(e) => this.getValue(category.id,e)} />
that element , this means when user start fill input onChange event handle function and update your state
getValue(id,e) {
let thisId = id-1;
let vs = this.state.c;
vs[thisId].value = e.target.value;
this.setState({
c:vs
});
let v = this.state.c[thisId];
console.log(v);
}
i create Pen in this address -> https://codepen.io/hamidrezanikoonia/pen/vRyJRx?editors=1111
you can check console , for more details ( open console tab in codepen )
and for more details , i create two method , the first fired when input (text) filled ( onChange event ) , and the other fired when clicked on button ( click event )

Categories

Resources