Checkboxes not working in react js - javascript

my check boxes are not getting checked, when created dynamically. I am not able to find the problem. Though, when I hard-code the values for check box id and label for, it just works.
var category_list = this.props.categories_list.map(function(name, i) {
// debugger
return (
<div className="group-chkbx list-group-item">
<input key={i+11} type="checkbox" id={name.category_id} name="category" />
<label htmlFor={name.category_id}>{name.name}</label>
</div>
)
});

After a lot of research one of my colleague helped me out with a solution. The htmlFor and id must be same, but cannot be only numeric. The Ids that I'm using are purely numeric. When I added alphabet as a prefix, it just started working like charm. Thanks all for showing interest and helping out here.

There's nothing that would set the checked prop on them, anyway. When should they be checked?
(Also, remember that components in arrays (such as what .map returns) should have unique key props.)

If your checkboxes are not getting checked, most probably is that some other functionality is preventing it.
Here and example of how to get the checkbox values:
class WithChecks extends Component {
constructor(props){
super(props);
this.getValue = this.getValue.bind(this);
}
getValue(e){
const chk = e.target;
console.log(chk.checked);
console.log(chk.value);
}
render() {
const arr = ['a', 'b', 'c', 'd'];
return (
<div>
{
arr.map((value, index) => {
return (
<div key={index}>
<input type="checkbox"
id={'chk' + index}
onChange={this.getValue}
name="category"
value={value} />
<label htmlFor={'chk' + index}>{value}</label>
</div>
);
})
}
</div>
);
}
}
Maybe this can help to clarify.

The checked property of the input will control whether it is checked. Usually I use local state (or something from global redux state to control what is checked). Little Example:
class Something extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: 0
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// Do Stuff
}
render() {
return (
<div>
{
this.props.categories_list.map(function(name, i) {
return (
<div className="group-chkbx list-group-item" key={i}>
<input checked={i === this.state.checked} onChange={this.handleChange} type="checkbox" id={name.category_id} name="category" />
<label htmlFor={name.category_id}>{name.name}</label>
</div>
)
});
}
</div>
);
}
}

Related

How to change value of all checkboxes in react?

I want to change value of my checkboxes from true to false
var x = document.getElementsByClassName("checkbox")
for(let i=0; i<=x.length; i++) {
x[i].checked = false;
}
but when I try to do this I get an error: Cannot set properties of undefined (setting 'checked') because x is HTMLCollection and x[i] returns only
<input type="checkbox" class="checkbox">
so no 'checked' property.
How can I handle this?
Please either change the <= to < in the for loop
for(let i=0; i<x.length; i++) {}
Or make it to loop till length - 1
for(let i=0; i<=x.length - 1; i++) {}
The issue with how you're doing it is that you're not making use of the states in React.
This is how I would do it.
Set initial state of the checkboxes:
constructor(props) {
super(props);
this.state = {checked : false};
}
then pass the state into the checked property of the input:
<input type="checkbox" checked={this.state.checked} onChange={(e) => this.handleChange(e)} />
In the handleChange function update the state of the checkbox:
handleChange = (e) => {
this.setState({ checked: e.target.checked })
}
This should update all the checkboxes that have checked={this.state.checked}
Try this:
<input type="checkbox" checked={this.state.chkbox} onChange={this.handleChangeChk} />
Or you can check this question here briefly explained:
Set checkbox value in React JS
The problem is in the for loop. The condition should be i<x.length only.
var x = document.getElementsByClassName("checkbox")
for (let i = 0; i < x.length; i++) {
x[i].checked = false;
}
// below for testing purpose
for (let i = 0; i < x.length; i++) {
console.log(x[i].checked)
}
<input type="checkbox" class="checkbox">
It's best to use setState to manage the checkbox values - best to update the values here in the ShadowDOM as this part of what makes React is all about
Specific instructions on how to implement checkboxes and react can be found here --
http://react.tips/checkboxes-in-react-16/
If this is code in an React application as you're suggesting you shouldn't be mixing native element methods and React JS like that as React has its own way of particular way of updating the DOM.
You should store the status of the checkboxes in state, set their checked status to that state, and then call a function to update the state causing a re-render with that new state.
const { useState } = React;
function Example() {
const [ state, setState ] = useState(true);
function handleClick() {
setState(false);
}
return (
<div>
<input type="checkbox" checked={state} />
<input type="checkbox" checked={state} />
<input type="checkbox" checked={state} />
<input type="checkbox" checked={state} />
<button onClick={handleClick}>Uncheck the boxes!</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

How to set the value of inputs with ReactJS hooks?

I want to fill the inputs value of a form with default values once the modal is opened
I did it with pure javascript using document.getElementById(textId).value='some value as follow:
for(var i=0; i<details_data.length;i++){
let textId='text'+i;
let amountId='amount'+i;
document.getElementById(textId).value=details_data[i].text
}
This worked fine. but I want to know how to do it with React since I don't believe this is a best practice.
what i tried is to set the input value like this:
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
But this woudn't let me change the value of the input. it just set the default value, and when i type in the input the value woudn't change as I want.
This is my code
const [details_data,set_details_data]=useState([
{'text':'','amount':''}
])
// called this function on `onChange` and store the data in `details_data`
function details_handler(e){
let name=e.target.name;
let value=e.target.value;
details_data[this][name]=value;
set_details_data(details_data);
}
JSX:
(In my case user can add inputs as many as he wants,That's why I put the inputs in a the mapping loop)
{
details_data.map((el,index) => {
let textId='text'+index;
let amountId='amount'+index;
return (
<div key={index}>
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
<input name='amount' id={amountId} onChange={details_handler.bind(index)}/>
</div>
);
})
}
useEffect(() => {
if(detailsProps) {
set_details_data(detailsProps);
}
}, [detailsProps])
where your detailsProps (data from the api) will look something like this
detailsProps = [
{'text':'text1','amount':'100'},
{'text':'text2','amount':'200'}
]
onChange Function
const details_handler = (event, index) => {
const items = [...details_data];
items[index][event.target.name] = event.target.value;
set_details_data(items);
}
your view
{
details_data.map((el,index) => {
return (
<div key={index}>
<input name='text' value={el.text} onChange={(e) => details_handler(e, index)}/>
<input name='amount' value={el.amount} onChange={(e) => details_handler(e, index)}/>
</div>
);
})
}

Form is clearing blank inputs prev set data

I can't seem to figure out why my form clears prev data when submitting. I have an edit button that when clicked pops open a form. If I edit the name field but not the birthdate field, the name is changed and the birthdate blanks out. It may be a simple silly error but a 2nd set of eyes may help
class Card extends Component {
constructor(props) {
super(props);
this.state = {
dataEditingMode: false,
planetSelection: this.props.homeWorld,
}
}
onEditDeets() {
this.setState({
dataEditingMode: !this.state.dataEditingMode
});
}
onSaveDeets(element) {
element.preventDefault();
this.props.onSavingEditedDeets(
this.props.id,
this.refs.personName.value,
this.refs.personBirthday.value,
this.refs.personHomeWorld.value)
this.setState({
dataEditingMode: false
});
}
onEditPlanetSelection(event) {
this.setState({
planetSelection:event.target.value
});
}
render() {
let getHomeWorld = (planetID) => {
for (var i = 0; i < this.props.planetList.length; i++) {
if (this.props.planetList[i].id === planetID) {
return this.props.planetList[i].name;
}
}
return 'planet does not exist.'
}
let name = this.props.name;
let imageURL = this.props.imageURL;
let birthday = this.props.birthday;
let homeWorld = this.props.homeWorld;
let dataEditingForm;
if (this.state.dataEditingMode === true) {
dataEditingForm = <form
onSubmit={this.onSaveDeets.bind(this)}>
<span>Name: </span>
<input type="text" ref="personName" />
<span>Birthday: </span>
<input type="text" ref="personBirthday" />
<span>Homeworld: </span>
<select
value={this.state.planetSelection}
ref="personHomeWorld"
onChange={this.onEditPlanetSelection.bind(this)}
>
{this.props.planetList.map((planet)=>{
return <option
key={planet.id}
value={planet.id}
>
{planet.name}
</option>
})}
</select>
<button>Save Deets</button>
</form>
} else {
dataEditingForm = <div></div>
}
return (
<div className='card'>
<div className='card-content'>
<div className='card-name'>{name}</div>
<img src={imageURL} alt='profile'/>
<p>
<span>Birthday:</span>
<span>{birthday}</span>
</p>
<p>
<span>Homeworld:</span>
<span>{getHomeWorld(homeWorld)}</span>
</p>
<p>
<span>
<button type="button" onClick={this.onEditDeets.bind(this)}>Edit Card Deets</button>
</span>
</p>
{dataEditingForm}
</div>
</div>
);
}
}
export default Card;
Basically, you are updating your state based on the values of the form, irrespective of whether they are changed or not.
For a simple change, you can just set the default value of your input tags to the state
<span>Name: </span>
<input type="text" ref="personName" defaultValue="{name}" />
<span>Birthday: </span>
<input type="text" ref="personBirthday" defaultValue="{birthday}"/>
Also, in this case, I prefer performing edits like this based on the form state but depending on the scenario you would want to handle onChange.
For example, in a settings page, you might want certain toggles to be effective immediately. Then you should handle onChange and update the state directly.

generate unique array base on checkbox value

I have few checkbox, what I want is to build a unique array list base on the checkbox value, if the checkbox is checked, push it to the list, if the checked checkbox is already in the list, remove it from the list.
http://jsbin.com/bojinudelo/edit?js,console,output
What's the problem of my code below?
generateFilter = (e) => {
let temp = [];
temp = this.state.arr;
if(temp.indexOf(this.state.arr) > -1){
delete temp[e.target.name]
}else{
temp.push(e.target.name);
}
this.setState({arr:temp})
console.log(this.state.arr)
}
render() {
return (
<div>
<input onChange={this.generateFilter} type="checkbox" name="apple"/>
<input onChange={this.generateFilter} type="checkbox" name="samsung"/>
</div>
);
}
Reason is, you are checking the index of wrong item, Instead of checking the index of this.state.arr, check the index of e.target.value, as well as deleting in a wrong way.
temp is an array not an Object, so instead of using delete, you need to use the splice and pass the index of item.
Use this function:
generateFilter = (e) => {
let temp = this.state.arr.slice(),
index = temp.indexOf(e.target.name);
if(index != -1){
temp.splice(index, 1);
}else{
temp.push(e.target.name);
}
this.setState({arr:temp})
console.log(temp)
}
Check the working code: http://jsbin.com/tatakamobu/1/edit?js,console,output
Run this snippet:
class HelloWorldComponent extends React.Component {
constructor(props){
super(props);
this.state = {
arr: []
}
}
generateFilter = (e) => {
let temp = this.state.arr.slice(),
index = temp.indexOf(e.target.name);
if(index != -1){
temp.splice(index, 1);
}else{
temp.push(e.target.name);
}
this.setState({arr:temp})
console.log(temp)
}
render() {
return (
<div>
<input onChange={this.generateFilter} type="checkbox" name="apple"/>
<input onChange={this.generateFilter} type="checkbox" name="samsung"/>
</div>
);
}
}
ReactDOM.render(
<HelloWorldComponent />,
document.getElementById('react_example')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='react_example'/>

React autoFocus sets cursor to beginning of input value

I have a controlled input that has a value initially showing.
I have set that input to autoFocus but the cursor appears at the beginning of the input when I am wanting it to appear at the end. I understand this might be because the autoFocus is added before the value is but I'm not 100% sure.
What would be the best way to accomplish the cursor initializing at the end of the input field?
var Test = React.createClass({
getInitialState: function() {
return {
teamId: 'fdsfds'
};
},
render: function() {
return (
<input type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />
);
},
setTeamId: function(event) {
this.setState({ teamId: id });
},
});
ReactDOM.render(
<Test />,
document.getElementById('container')
);
https://jsfiddle.net/69z2wepo/34486/
One solution:
<input
type="text"
autoFocus
value={this.state.teamId}
onChange={this.setTeamId}
onFocus={function(e) {
var val = e.target.value;
e.target.value = '';
e.target.value = val;
}}
/>
https://jsfiddle.net/o3s05zz4/1/
Adaptation of this answer: https://stackoverflow.com/a/2345915/1589521
This actually works:
componentDidMount() {
const input = this.input;
const length = input.value.length;
input.focus();
input.setSelectionRange(length, length);
}
render() {
return (
<input ref={ref => this.input = ref} ... >
)
}
PS. If you need to support IE8 and below you'll need to use IE-specific checks.
This way the text of the input will be selected, ready to edit
<input
type="text"
defaultValue="Untitled"
autoFocus
onFocus={e => e.currentTarget.select()}
/>
Setting the input value inside componentDidMount seems to do the trick, but it feels like a hack:
componentDidMount: function(){
this.inputElement.value = this.state.teamId;
},
render: function() {
var that = this;
return <input ref={function(ref){that.inputElement = ref;}} type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />;
},
https://jsfiddle.net/yuk13tuu/
In TypeScript:
private inputDOM: HTMLInputElement | null;
public componentDidMount() {
if (this.inputDOM != null) {
this.inputDOM.value = '';
this.inputDOM.value = this.state.newRegionName;
}
}
public render() {
return <input ref={(ref: HTMLInputElement | null) => this.inputDOM = ref} type="text" autoFocus={true} value={this.state.inputValue} />;
}
Looks like the html attribute autofocus doesn't take any parameters to specify where the cursor should start. See mdn documentation.
Sitepoint has a great tutorial explaining your options for setting cursor position from within an input box.
As for the reacty side of things, you'll simply put your jQuery (or other cursor related code) in the componentDidMount lifecycle method.

Categories