I have a simple form which has a couple of radio buttons that aren't checking. Each button has a change event attached, but still nothing changes. What can I do to not only capture their data, but signify that the input is selected?
The form
FormComponent = React.createClass({
propTypes: {
label: React.PropTypes.string,
onChange: React.PropTypes.func
},
handleEvent(e) {
let {onChange} = this.props;
console.log(e);
},
render() {
const {label} = this.props;
return (
<form className="lm-widget__form lm-flex-row">
<fieldset className="lm-flex-row__column lm-h-flex-50">
<RadioSet group='radio-group'
label={label}
radios={[
{
value: 'new',
checked: true,
changeEvent: this.handleEvent,
text: 'radio one'
},
{
value: 'old',
checked: false,
changeEvent: this.handleEvent,
text: 'radio two'
}
]}
/>
</fieldset>
</form>
)
}
});
The radio buttons
RadioSet = React.createClass({
propTypes: {
group: React.PropTypes.string.isRequired,
label: React.PropTypes.string,
radios: React.PropTypes.arrayOf(
React.PropTypes.shape({
value: React.PropTypes.string.isRequired,
checked: React.PropTypes.bool.isRequired,
changeEvent: React.PropTypes.func.isRequired,
text: React.PropTypes.string.isRequired
})
).isRequired
},
render: function () {
const {group, label, radios} = this.props;
const self = this;
if (label) {
return(
<div className="lm-widget-form__label">
<div className="small">{label}</div>
<div className="segment-controls">
{radios.map(function(radio, i){
return (
<div key={i} className="segment-controls__group-item">
<input type="radio"
name={self.props.group}
className="segment-controls__button"
id={`radio-${i}`}
value={radio.value}
checked={radio.checked}
onChange={radio.changeEvent}
/>
<label htmlFor={`radio-${i}`}
className="segment-controls__label">
<span className="segment-controls__label-text">
{radio.text}
</span>
</label>
</div>
);
})
}
</div>
</div>
)
}
else {
return (
<div className="segment-controls">
{this.props.radios.map(function(radio, i){
return (
<div key={radio.value} className="segment-controls__group-item">
<input type="radio"
name={self.props.group}
className="segment-controls__button"
id={`radio-${i}`}
value={radio.value}
checked={radio.checked}
onChange={radio.changeEvent}
/>
<label htmlFor={`radio-${i}`}
className="segment-controls__label">
<span className="segment-controls__label-text">
{radio.text}
</span>
</label>
</div>
);
})
}
</div>
);
}
}
});
So the issue is that you're telling the first radio button it's checked every time by passing true to it.
If we change your first bit of code to use setState this should work.
FormComponent = React.createClass({
getInitialState() {
return {
checkedIndex: 0
};
},
propTypes: {
label: React.PropTypes.string,
onChange: React.PropTypes.func
},
handleEvent(index, e) {
this.setState({
checkedIndex: index
});
let {onChange} = this.props;
console.log(e);
},
render() {
const {label} = this.props;
const radios = [
{
value: 'new',
checked: false,
changeEvent: this.handleEvent.bind(this, 0),
text: 'radio one'
},
{
value: 'old',
checked: false,
changeEvent: this.handleEvent.bind(this, 1),
text: 'radio two'
}
];
radios[this.state.checkedIndex].checked = true;
return (
<form className="lm-widget__form lm-flex-row">
<fieldset className="lm-flex-row__column lm-h-flex-50">
<RadioSet group='radio-group'
label={label}
radios={radios}
/>
</fieldset>
</form>
)
}
});
Also note we are using bind to maintain the this context of handleEvent and to pass in the proper index.
Related
I am just started on react and I have a challenge with implementing dynamic checkboxes. I have the checkbox items in a firestore collection and fetch them as an array which I store into something that looks like this:
const checkboxes = [
{
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
id: 'first',
value: false
},
{
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
id: 'second',
value: true
},
{
name: 'check-box-3',
key: 'checkBox3',
label: 'Check Box 3',
id: 'third',
value: false
},
{
name: 'check-box-4',
key: 'checkBox4',
label: 'Check Box 4',
id: 'fourth',
value: false
},
];
My form is in a class component and I render it like this
class CheckIn extends Component {
state = {
data1: ''
}
render() {
return(
<div>
{
checkboxes && checkboxes
.map(checkbox => {
return(
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
value = {checkbox.value}
onChange = {this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
)
})
}
</div>
)
}
}
I am not sure what to do in my handleCheck in order for the form to update state as true if it is checked and false it it is unchecked. For now, this only updates the checked ones and sends 'undefined'
handleCheck = (e) => {
this.setState({
[e.target.id] : true
})
}
Please help. Thanks
For checkbox type input, the value is checked not value.
This should work for you:
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
checked={checkbox.value}
onChange={this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
handleCheck = e => {
this.setState({
[e.target.id]: e.target.checked
})
}
Based on your needed in your comment on #ulou answer post
You need to set all checkboxs state false first after component is mounted
class CheckIn extends Component {
constructor() {
super();
state = {
data1: ''
}
}
componentdidmount(){
checkboxes.map(item => {
this.setState({
[item.id]: false
})
}
}
render() {
return(
<div>
{ checkboxes && checkboxes
.map(checkbox => {
return(
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
value = {checkbox.value}
onChange = {this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
)
})
}
</div>
)
}
}
I am currently facing a problem while i am working on reactJs. I have a reactstrap modal (https://reactstrap.github.io/components/modals/) where i am displaying checkbox items from an array from state. I want display only some of the options like option 1, option 4 and option 6 but not all, how can i hide other options in the view. Here is my code, can anyone help me how can i solve this problem please? And is there a good way to implement this checkbox to check and uncheck in a single or check/uncheck all.Please recommend me a good way like using jquery or anythin related to plain Js.
Help is appreciated. Thank You !
CodeSandBox Code: https://codesandbox.io/s/xj9ppwrq1z
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Modal,ModalBody,ModalFooter,ModalHeader,Button,Input,Label } from
"reactstrap";
class CheckBox extends Component{
constructor(props){
super(props);
this.state = {
checkboxModal: false,
checkBoxlists: [
{id:1, name: 'Option 1', isChecked: false},
{id:2, name: 'Option 2', isChecked: false},
{id:3, name: 'Option 3', isChecked: false},
{id:4, name: 'Option 4', isChecked: false},
{id:5, name: 'Option 5', isChecked: false},
{id:6, name: 'Option 6', isChecked: false}
],
};
}
toggleCheckBoxModal = () => {
this.setState({ checkboxModal : !this.state.checkboxModal });
}
// Handles check or uncheck only to a single flag
handleSingleChange = (e) => {
let checkBoxlists = this.state.checkBoxlists;
checkBoxlists.forEach( (item) => {
if(item.name === e.target.name ){
item.isChecked = e.target.checked;
}
});
this.setState({ checkBoxlists : checkBoxlists });
}
//Handle check/uncheck of all flag
handleAllChange = (e) => {
let checkBoxlists = this.state.checkBoxlists;
checkBoxlists.forEach( (item) => {
item.isChecked = e.target.checked;
});
this.setState({ checkBoxlists: checkBoxlists });
}
handleInput = (e) => {
this.setState({ [e.target.name] : e.target.value });
}
render(){
return(
<div>
<Button onClick={this.toggleCheckBoxModal}>Click to Open</Button>
<Modal isOpen={this.state.checkboxModal}>
<ModalHeader toggle={this.checkboxModal}></ModalHeader>
<ModalBody style={{ backgroundColor: "#4e5d6c", color: "#e1ebeb" }}>
<div style={{ margin: "5px 0px 25px 25px"}}><Input type="checkbox" onClick={ this.handleAllChange } value="checkedAll" /> Check/Uncheck All</div>
{this.state.checkBoxlists.map( item => {
return(
<ul key={item.id}>
<li >
<Input
// key={item.id}
type={"checkbox"}
name={item.name}
value={item.name}
checked={item.isChecked}
onChange={this.handleSingleChange}
/>
<Label>{item.name}</Label>
</li>
</ul>
)
})}
</ModalBody>
<ModalFooter>
<Button onClick={this.toggleCheckBoxModal}>Close</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
ReactDOM.render(<CheckBox />, document.getElementById('root'));
The method of the renderCheckboxes() will return checkboxes which you want. I created example array for that. Then use renderCheckboxes() in render()
You can completely remove the handleSinlgeChange() use that in handleAllChange().Like below
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import {
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Button,
Input,
Label
} from "reactstrap";
class CheckBox extends Component {
constructor(props) {
super(props);
this.state = {
allChecked:false,
checkboxModal: false,
checkBoxlists: [
{ id: 1, name: "Option 1", isChecked: false },
{ id: 2, name: "Option 2", isChecked: false },
{ id: 3, name: "Option 3", isChecked: false },
{ id: 4, name: "Option 4", isChecked: false },
{ id: 5, name: "Option 5", isChecked: false },
{ id: 6, name: "Option 6", isChecked: false }
]
};
}
toggleCheckBoxModal = () => {
this.setState({ checkboxModal: !this.state.checkboxModal });
};
// Handles check or uncheck only to a single flag
//Handle check/uncheck of all flag
handleAllChange = e => {
let checkBoxlists = this.state.checkBoxlists;
let allChecked = this.state.allChecked;
if (e.target.value === "checkedAll") {
checkBoxlists.forEach(item => {
item.isChecked = e.target.checked;
allChecked = e.target.checked
});
}
else checkBoxlists.find(item => item.name == e.target.name).isChecked = e.target.checked
this.setState({ checkBoxlists,allChecked });
}
handleInput = e => {
this.setState({ [e.target.name]: e.target.value });
};
renderCheckboxes = () => {
let wantedCheckboxes = [1, 4, 6];
return this.state.checkBoxlists.filter(cb => wantedCheckboxes.includes(cb.id))
.map(item => (
<ul key={item.id}>
<li>
<Input
// key={item.id}
type={"checkbox"}
name={item.name}
value={item.name}
checked={item.isChecked}
onChange={this.handleAllChange}
/>
<Label>{item.name}</Label>
</li>
</ul>
))
}
render() {
return (
<div>
<Button onClick={this.toggleCheckBoxModal} style={{ margin: "50px" }}>
Click to Open
</Button>
<Modal isOpen={this.state.checkboxModal}>
<ModalHeader toggle={this.checkboxModal} />
<ModalBody style={{ backgroundColor: "#4e5d6c", color: "#e1ebeb" }}>
<div style={{ margin: "5px 0px 25px 25px" }}>
<Input
type="checkbox"
onClick={this.handleAllChange}
value="checkedAll"
checked={this.state.allChecked}
/>{" "}
Check/Uncheck All
</div>
{this.renderCheckboxes()}
</ModalBody>
<ModalFooter>
<Button onClick={this.toggleCheckBoxModal}>Close</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
ReactDOM.render(<CheckBox />, document.getElementById("root"));
Hope it will help
I would create a function that returns an array of checkBoxLists containing only the items you want displayed at a time
filterOptions = () => {
checkBoxlists.forEach( (item) => {
if(item.id % 2 == 0) // example: only even options
// for 1, 4 6
if(item.id == 1)
newOptions.add(item)
elseif(item.id==4)
newOptions.add(item)
elseif(itemid==6)
newOptions.add(item)
};
return newOptions;
}
It's advice from a newbie but im just trying to help
I am trying to build a simple to-do app.
I store all my tasks in an array like this:
var TASKS = [
{
name: "Pay Bills",
completed: false,
id: 1,
},
{
name: "Go shopping",
completed: false,
id: 2,
},
{
name: "Pick up something",
completed: false,
id: 3,
},
{
name: "Drink Coffee",
completed: true,
id: 4,
},
];
and I want to list them in separated sections (todo/done) by passing boolean value as props to the listing component.
My component structure is here:
var Application = React.createClass({
propTypes: {
title: React.PropTypes.string,
},
getDefaultProps: function() {
return {
title: "Add item",
}
},
onTodoAdd: function(name) {
...
},
onRemoveTask: function(index) {
...
},
onCompletedTask: function(index) {
...
},
render: function() {
return (
<div className="to-do">
<Section title={this.props.title}>
<AddTodoForm onAdd={this.onTodoAdd} />
</Section>
<Section title="to-do">
<ListTasks initialTasks={TASKS} completedTasks={false} />
</Section>
<Section title="done">
<ListTasks initialTasks={TASKS} completedTasks={true} />
</Section>
</div>
);
}
});
and the listing component looks like this:
var ListTasks = React.createClass({
propTypes: {
initialTasks: React.PropTypes.array.isRequired,
completedTasks: React.PropTypes.bool.isRequired,
},
getInitialState: function() {
return {
tasks: this.props.initialTasks,
};
},
render: function() {
return (
<div>
{this.state.tasks
.filter(function(task, index, props) {
return task.completed === props.completedTasks;
})
.map(function(task, index) {
return(
<Task
name={task.name}
key={task.id}
completed={task.completed}
onCompleted={function() {this.onCompletedTask(index)}.bind(this)}
onRemove={function() {this.onRemoveTask(index)}.bind(this)}
/>
);
}.bind(this))}
</div>
);
}
});
but I canť pass the
completedTasks={true/false}
to the filter function with
props.completedTasks
is there anyone who can help please?
Thanks a lot.
The issues is within ListTasks component in render method.
The 3rd parameter of the Array.filter method is not the component props , is an array ( The array filter was called upon).
To fix this you can define a new variable (props) and you can access it within your inner function through lexical scoping
render: function() {
var props = this.props;
return (
<div>
{this.state.tasks
.filter(function(task, index) {
return task.completed === props.completedTasks;
})
.map(function(task, index) {
return(
<Task
name={task.name}
key={task.id}
completed={task.completed}
onCompleted={function() {this.onCompletedTask(index)}.bind(this)}
onRemove={function() {this.onRemoveTask(index)}.bind(this)}
/>
);
}.bind(this))}
</div>
);
}
I cannot figure out why my handleDelete function isn't running. When I click 'Delete' nothing at all happens.
In dev tools I see the value for the delete button is correct but onClick with it's attributes doesn't show up at all.
var MainContainer = React.createClass({
getInitialState: function(){
return {
name: 'JK_MNO',
friends: [], //friends is items
text: ''
}
},
handleChange: function(e){
//like the onChange function
this.setState({
text: e.target.value
});
},
handleSubmit: function(e){
e.preventDefault();
if(this.state.text !== '') {
var nextfriend = this.state.friends.concat([{
text: this.state.text, id: Date.now()
}]);
var nextText = '';
this.setState({
friends: nextfriend, text: nextText
});
}
},
handleDelete: function(e){
console.log(this.state.friends);
this.friends.splice (this.props.friend.id);
this.setState({
friends: friends
});
},
render: function(){
return (
<div>
<h3> Name: {this.state.name} </h3>
<ShowList friends={this.state.friends} />
<form onSubmit={this.handleSubmit} >
Enter Friends: <input className="friendInput" onChange={this.handleChange} value={this.state.text} />
</form>
</div>
);
}
});
var ShowList = React.createClass({
render: function() {
var createFriend = function(friend) {
return (
<li key={friend.id}>{friend.text} <button onClick={this.props.handleDelete} value={friend.id}>Delete</button> </li>
);
};
return <ul>{this.props.friends.map(createFriend.bind(this))}</ul>;
}
});
ReactDOM.render(<MainContainer />, document.getElementById('container'));
https://jsfiddle.net/USERALPHA32/bdc9trux/
Very close! You just need to pass your delete function down to ShowList as a prop:
Current:
<ShowList friends={this.state.friends} />
Suggested:
<ShowList friends={this.state.friends} handleDelete={this.handleDelete} />
I am new to ReactJS, have tried to get the value of the checked/selected checkbox and also date selection from the input type date. but could not able to achieve.
When I click on Generate Report button, you can see the console displaying the states. only the location is getting saved, not the other option.
Here are my functions to update the state values and initial state values:
getInitialState: function() {
return {
selectedLocation: locationList[0].value,
selectedServiceType: [],
selectedStDate:new Date(1446887898),
selectedEdDate:new Date(1446887898)
};
},
selectServiceType:function(e){
selectedTypes.indexOf(e.target.value)? selectedTypes.push(e.target.value):console.log('Already exists in array');
this.setState({
selectedServiceType: e.target.checked
})
},
changeHandler: function(e) {
this.setState({
selectedLocation: e.target.value
})
},
selectStDate: function(e) {
this.setState({
selectedDate: e.target.value
})
},
selectEdDate: function(e) {
this.setState({
selectedEdDate: e.target.value
})
},
The complete Demo here
JSFiddle
Many thanks
I've done refactoring, you can check it, Example
var FulfilmentReport = React.createClass({
getInitialState: function() {
return {
services: this.props.services,
location: this.props.locations[1].value,
startDate: this.formatDate(new Date(1446887898)),
endDate: this.formatDate(new Date(1446887898))
};
},
changeService: function (e) {
var services = this.state.services.map(function (service) {
service.checked = (service.value === e.target.value) ? !service.checked : service.checked;
return service;
});
this.setState({
services: services
});
},
handleChange: function(field, e) {
var data = {};
data[field] = e.target.value;
this.setState(data);
},
render: function() {
var buttonClasess = [
'right', 'mdl-button', 'mdl-js-button', 'mdl-button--raised',
'mdl-js-ripple-effect', 'mdl-button--colored'
].join(' ');
var services = this.state.services.map(function (service) {
return [
<label>{ service.name }</label>,
<input
type="checkbox"
name={service.value}
value={service.value}
checked={service.checked}
onChange={ this.changeService } />
];
}, this)
var locations = this.props.locations.map(function (location, index) {
return (<option key={index} value={ location.value }>{ location.name }</option>);
});
var elements = [{
label: <label>Location</label>,
data: <select
onChange={ this.handleChange.bind(this, 'location') }
value={ this.state.location }>{ locations }</select>
}, {
label: <label>Service Type</label>,
data: <div>{ services }</div>
},{
label: <label>Start Date</label>,
data: <input
type="date"
value={ this.state.startDate }
onChange={ this.handleChange.bind(this, 'startDate') } />
},{
label: <label>'End Date'</label>,
data: <input
type="date"
value={ this.state.endDate }
onChange={ this.handleChange.bind(this, 'endDate') } />
}];
elements = elements.map(function (element) {
return [element.label, element.data];
});
return (<div id="items">
<div>{ elements }</div>
<input type="button" value="Generate Report" onClick={ this.onItemClick } className={ buttonClasess } />
</div>);
},
onItemClick: function() {
this.state.services = this.state.services.filter(function (el) {
return el.checked;
}) ;
console.log( this.state );
},
formatDate: function (date) {
return date.toISOString().slice(0, 10);
}
});