I am using material UI checkbox components inside a react component. I can’t get the basic checked/unchecked function working although I believe I did and checked everything. Anyone care to help? here’s the code:
class SplitEqually extends React.Component {
constructor(props) {
super(props);
let checked = this.props.contributors.map((contributor) => contributor.id)
this.state = {
checkedContributors: this.props.contributors,
checkedId: checked,
};
}
handleChange = (e, contri) => {
let checkedId = this.state.checkedId.includes(contri.id)
? this.state.checkedId.filter((id) => id !== contri.id)
: [...this.state.checkedId, contri.id];
console.log(checkedId)
let checkedContributors = this.state.checkedContributors.filter((contri) =>
checkedId.includes(contri.id)
);
this.setState(checkedId);
};
render() {
const { classes, contributors } = this.props;
const { checkedContributors, checkedId } = this.state;
return (
<div className={classes.splitUnequally}>
{contributors.map((contributor, i) => {
let { id, name } = contributor;
console.log(checkedId.includes(id));
return (
<div className={classes.list} key={id}>
<div className={classes.avatar}></div>
<FormControlLabel
labelPlacement="start"
control={
<Checkbox
onChange={(e) => this.handleChange(e, contributor)}
name={name}
checked={checkedId.includes(id)}
/>
}
label={name}
/>
</div>
);
})}
<br></br>
</div>
);
}
}
checkedContributors state variable is an array of object, each object defining one user with a unique id property.
CheckedId state variable is an array which contains unique id of only those users who are checked.
I was using the wrong syntax for setting the state. It should have been this.setState({checkedId}); and not this.setState(checkedId);. Correcting this resolved the issue
Related
I have 3 components. The first component is where I created the checkbox and it looks like this.
const RoutingEnginesChecker = ({
classes,
routingEngines,
selectedEngines,
setSelectedEngines,
}) => {
// Add/Remove checked item from list
const handleCheck = (event) => {
let updatedList = [...selectedEngines];
if (event.target.checked) {
updatedList = [...selectedEngines, event.target.value];
} else {
updatedList.splice(selectedEngines.indexOf(event.target.value), 1);
}
setSelectedEngines(updatedList);
};
return (
<div className={classes.checkList}>
<Typography className={classes.routingEnginesTitle} variant='subtitle1'>
Routing Engines:
</Typography>
<div className={classes.routingEnginesContainer}>
{routingEngines.map((item, index) => (
<div key={index}>
<input value={item} type='checkbox' onChange={handleCheck} />
<span>{item}</span>
</div>
))}
</div>
</div>
);
};
export default withStyles(styles)(RoutingEnginesChecker);
After that I have the index component where i call the checkbox.
const routingEngines = ['here', 'tomtom'];
const [selectedEngines, setSelectedEngines] = useState([]);
<RoutingEnginesChecker
InputProps={{ label: 'setselectEngine Label' }}
routingEngines={routingEngines}
selectedEngines={selectedEngines}
setSelectedEngines={setSelectedEngines}
Finnaly, I have the third component where I need to check the values from the checkbox.
I have tried importing the component of the checkbox. This is how my code looks.
const routingeEngines = RoutingEnginesChecker;
// check what engine is used
if (engine === routingeEngines) {
return iconHere;
}
return iconTomTom
}
;
The problem is that it always goes on the first if('here' value). I have also tried using index and includes. How can I check for the 2 values(here and tomtom)? Thank you!
I'm running into the issue where I have created a functional component to render a dropdown menu, however I cannot update the initial state in the main App.JS. I'm not really sure how to update the state unless it is in the same component.
Here is a snippet of my App.js where I initialize the items array and call the functional component.
const items = [
{
id: 1,
value:'item1'
},
{
id: 2,
value:'item2'
},
{
id: 3,
value:'item3'
}
]
class App extends Component{
state = {
item: ''
}
...
render(){
return{
<ItemList title = "Select Item items= {items} />
And here is my functional componenet. Essentially a dropdown menu from a YouTube tutorial I watched (https://www.youtube.com/watch?v=t8JK5bVoVBw).
function ItemList ({title, items, multiSelect}) {
const [open, setOpen] = useState (false);
const [selection, setSelection] = useState([]);
const toggle =() =>setOpen(!open);
ItemList.handleClickOutside = ()=> setOpen(false);
function handleOnClick(item) {
if (!selection.some(current => current.id == item.id)){
if (!multiSelect){
setSelection([item])
}
else if (multiSelect) {
setSelection([...selection, item])
}
}
else{
let selectionAfterRemoval = selection;
selectionAfterRemoval = selectionAfterRemoval.filter(
current =>current.id == item.id
)
setSelection([...selectionAfterRemoval])
}
}
function itemSelected(item){
if (selection.find(current =>current.id == item.id)){
return true;
}
return false;
}
return (
<div className="dd-wraper">
<div tabIndex={0}
className="dd-header"
role="button"
onKeyPress={() => toggle(!open)}
onClick={() =>toggle(!open)}
onChange={(e) => this.setState({robot: e.target.value})}
>
<div className="dd-header_title">
<p className = "dd-header_title--bold">{title}</p>
</div>
<div className="dd-header_action">
<p>{open ? 'Close' : 'Open'}</p>
</div>
</div>
{open && (
<ul className ="dd-list">
{item.map(item =>(
<li className="dd-list-item" key={item.id}>
<button type ="button"
onClick={() => handleOnClick(item)}>
<span>{item.value}</span>
<span>{itemSelected(item) && 'Selected'}</span>
</button>
</li>
))}
</ul>
)}
</div>
)
}
const clickOutsideConfig ={
handleClickOutside: () => RobotList.handleClickOutside
}
I tried passing props and mutating the state in the functional component, but nothing gets changed. I suspect that it needs to be changed in the itemSelected function, but I'm not sure how. Any help would be greatly appreciated!
In a function component, you have the setters of the state variables. In your example, you can directly use setOpen(...) or setSelection(...). In case of a boolean state variable, you could just toggle by using setOpen(!open). See https://reactjs.org/docs/hooks-state.html (Chapter "Updating State") for further details.
So you need to do something like below . Here we are passing handleChange in parent Component as props to the child component and in Child Component we are calling the method as props.onChange
Parent Component:
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
value :''
}
}
handleChange = (newValue) => {
this.setState({ value: newValue });
}
render() {
return <Child value={this.state.value} onChange = {this.handleChange} />
}
}
Child Component:
function Child(props) {
function handleChange(event) {
// Here, we invoke the callback with the new value
props.onChange(event.target.value);
}
return <input value={props.value} onChange={handleChange} />
}
I have an array of data that i map over and display on screen. i want to be able to do stuff to these dom elements when clicked. I've stored the refs in an array and now onclick i want to do something with the one that was clicked and something else with the rest.
So i thought of using es6 filter to remove the current one from a new array and then iterate over them. And then i'm free to do whatever i want with the item that was clicked.
However i can't get the filter to work. doesn't console anything.
https://codepen.io/_adamjw3/pen/MWWmGEg
class App extends React.Component {
constructor(props) {
super();
this.myRefs = [];
this.state = {
testData: [
"dave",
"pete",
"mark"
]
}
}
myActionHandler = key => {
const selectedDomElement = this.myRefs[key];
const filtered = this.myRefs.filter(item => item !== item);
filtered.forEach(function(entry) {
console.log("all but selected ne", entry);
});
};
render(){
return (
<div className="container">
{this.state.testData.map((item, key) => {
return (
<div key={key} >
<button onClick={() => this.myActionHandler(key)} ref={ref => (this.myRefs[key] = ref)} >
{item}
</button>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
It seems like your only issue is that you're filter function is wrong. It should use the selectedDomElement.
const filtered = this.myRefs.filter(item => item !== selectedDomElement);
I am pretty new to React, I have worked on react native before, so I am quite familiar with a framework. Basically I have an array of objects, lets say in contains 5 items. I populated views based on the amount of objects, so if there are 5 objects, my map function would populate 5 together with 5 inputs. My question is how can I get a value of each input?
Here is my code:
array.map(map((item, index) => (
<h1> item.title </h1>
<input value={input from user} />
)
You have to use the state and update the value with onChange manually
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: ''
}
}
handleInputChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
render () {
return (
<div>
<input value={this.state.value} onChange={(e) => {this.handleInputChange(e)}} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
A quick solution would be to use an array for all the input values.
const Inputs = ({array}) => {
const [inputs, setInputs] = useState([]);
const setInputAtIndex = (value, index) => {
const nextInputs = [...inputs]; // this can be expensive
nextInputs.splice(index, 1, value);
setInputs(nextInputs);
}
return (
...
array.map((item, index) => (
<div key={index}>
<h1>{item.title}</h1>
<input
value={inputs[index]}
onChange={({target: {value}) => setInputAtIndex(value, index)}
/>
</div>
)
...
);
}
Keep in mind here that in this case every time an input is changed, the inputs state array is copied with [...inputs]. This is a performance issue if your array contains a lot of items.
In React I'm creating a multiple choice questionnaire. Checkboxes are generated with the possible answers. When the user ticks the answers and reloads the page, the chosen answers' checkboxes do not retained their checked state.
The questions and answers are fetched from database as an array of objects on 1st load. The user can tick multiple checkboxes for a question. A 2nd array is created that includes all the multiple answers that user has chosen and sent to database has objects. On reload, this 2nd array is added to the state of the component as well as the 1st array.
Component
const Checkbox = ({ id, name, options, onChange }) => {
return (
<div className="checkbox-group">
{options.map((option, index) => {
<div key={index}>
<label htmlFor={id}>
<input
type="checkbox"
name={name}
id={id}
value={option}
onChange={onChange}
/>
{option}
</label>
</div>
}
</div>
);
}
class Form extends Component {
constructor(props) {
super(props);
this.state = {
questionnaire: [],
answeredQuestions: [],
formData: {},
};
this.handleChange = this.handleChange.bind(this);
}
async componentDidMount() {
// it doesn't matter how I fetch the data, could have been axios, etc...
let questionnaire = await fetch(questionnaireUrl);
let answeredQuestions = await fetch(answeredQuestionsUrl);
this.setState({ questionnaire, answeredQuestions });
}
render() {
return (
<div className="questionnaire-panel">
<h1>Quiz</h1>
{this.state.questionnaire.map((question, index) => {
return (
<div key={index}>
<Checkbox
options={questions.answers}
checked={// this where I'm stuck on what to do}
name="the-quiz"
id={`the-quiz_num_${index + 1}`}
onChange={this.handleChange}
/>
</div>
)
})}
</div>
);
}
handleChange(event) {
let target = event.target;
let value = target.value;
let name = target.name;
let chosenAnwersArray = [];
let chosenAnswer = {
answer: value,
checked: true,
};
if (this.state.questionnaire.includes(chosenAnswer)) {
newChosenAnwersArray = this.state.questionnaire.filter(q => {
return q.answer !== chosenAnswer.answer;
});
} else {
newChosenAnwersArray = [...newChosenAnwersArray, chosenAnswer];
}
this.setState(prevState => ({
formData: {
[name]: value,
},
answeredQuestions: newChosenAnwersArray
}));
}
}
I want to compare these 2 arrays that are in the this.state, that if the answers in the array2 are in array1 then check the corresponding checkboxes. Is there is a better way, please teach me!