How i render checkboxes with nested array of objects - reactjs

I have a checkbox component which renders multiple day checkboxes. I need to print the values of the selected checkboxes. The sample given below looks like the one:
const [state, setState] = useState({
"firstName": "",
"lastName" : "",
"mobileNumber" : "",
"avalabilities": [{"availabilityId": "",
day: [
{
value: "sun",
name: "Sunday"
},
{
value: "mon",
name: "Monday"
},
{
value: "tue",
name: "Tuesday"
},
{
value: "wed",
name: "Wednesday"
},
{
value: "thur",
name: "Thursday"
},
{
value: "fri",
name: "Friday"
},
{
value: "sat",
name: "Saturday"
}
],
"isChecked": false,
"checked" : false,
"allChecked": false,
"error": null});
this is the console value given below
{firstName: '', lastName: '', mobileNumber: '', avalabilities: Array(1), …}
allChecked: false
avalabilities: Array(1)
0:
availabilityId: ""
day: (7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
[[Prototype]]: Object
length: 1
[[Prototype]]: Array(0)
close: false
disabled: false
error: null
firstName: ""
isChecked: false
isPending: false
lastName: ""
mobileNumber: ""
open: false
this is how I am trying to render the arrays
{(avalabilities || [{}]).map((av, index) => {
return (
<div key={av.availabilityId}>
<>
{av.day.map((item) => {
return (
<div>
<input
checked={item.checked || false}
onChange={() => handleChange3(item.value)}
type="checkbox"
/>
</div>
);
})}
</>
But the error on mapping with day array is coming below like this
are not valid as a React child (found: object with keys {value, name}). If you meant to render a collection of children, use an array instead.
const checkedHandler = (event) => {
setState(...)
//Well, here I don't know how change the particular value of the
array...}
Any help is highly appreciated.

If i'm correct you want to show values of each checkbox and save the respective checkbox value when we toggle any checkbox.
You have avalabilities array & in each object we have another day array. I render the all the avalabilities. Now when i toggle any checkbox, i pass three things to checkHandler:
e which is native event of checkbox
avIndex which is index of object in avalabilities array
index which is index of object in day array.
Now each day object, i set a key checked and store the value of that checkbox by getting the value from e.target.checked.
Hope this solve your problem
newState.avalabilities[avIndex].day[index].checked = e.target.checked;
import { useState } from 'react';
export default function App() {
const [state, setState] = useState({
firstName: '',
lastName: '',
mobileNumber: '',
avalabilities: [
{
availabilityId: '',
day: [
{ value: 'sun', name: 'Sunday' },
{ value: 'mon', name: 'Monday' },
{ value: 'tue', name: 'Tuesday' },
{ value: 'wed', name: 'Wednesday' },
{ value: 'thur', name: 'Thursday' },
{ value: 'fri', name: 'Friday' },
{ value: 'sat', name: 'Saturday' }
],
isChecked: false,
checked: false,
allChecked: false,
error: null
}
]
});
const checkedHandler = (e, avIndex, index) => {
console.log(e.target.checked, avIndex, index);
setState((prev) => {
let newState = { ...prev };
newState.avalabilities[avIndex].day[index].checked = e.target.checked;
return newState;
});
};
return (
<>
{state.avalabilities.map((av, avIndex) => (
<div key={av.availabilityId}>
{av.day.map((item, index) => (
<div key={index}>
<input
checked={item?.checked || false}
onChange={(e) => checkedHandler(e, avIndex, index)}
type='checkbox'
/>
<span>{item.name}</span>
</div>
))}
</div>
))}
</>
);
}

Related

How to set state in nested array of objects in ReactJs?

I have this object as a state in reactjs. I want to add another object inside the "childoptions: []" array which is nested inside the options array on button click.
How can I achieve this, pls help...
const [select1, setSelect1] = useState({
id: uuid(),
type: 'select',
properties: {
label: 'Select1',
options: [
// {
// id: uuid(),
// optionName: 'red 🔴',
// value: '',
// childOptions: [],
// },
// {
// id: uuid(),
// optionName: 'green 🟢',
// value: '',
// childOptions: [],
// },
// {
// id: uuid(),
// optionName: 'blue 🔵',
// value: '',
// childOptions: [],
// },
],
},
parentId: null,
});
This is achievable by copy the prevState in the new state with the new object inserted inside the options array.
A more detailed explanation could be found at https://stackoverflow.com/a/26254086/9095807
setSelect1((prevState) => {
return {
...prevState,
properties: {
label: 'Select1',
options: prevState.properties.options.map(obj => obj.id === id ? { ...obj, childOptions: [...obj.childOptions, newChildOptions] } : obj),
}
}
})

Select form field not populating with options from state in ReactJS

This is my select function
import React from "react";
const Select = ({ name, label, options, error, ...rest }) => {
return (
<div className="form-group">
<label htmlFor={name}>{label}</label>
<select {...rest} id={name} name={name} className="form-control">
<option value="" />
{options.map((option) => (
<option key={option.id} value={option.id}>
{option.name}
</option>
))}
</select>
{error && <div className="alert alert-danger">{error}</div>}
</div>
);
};
export default Select;
This is the component state
state = {
data: {
vat: "",
city: "",
country: "",
mobile_number: "",
address: "",
has_conference: false,
star_rating: "",
},
errors: {},
hotel_type: [],
};
This function to populate data in the hotel_type
populateHotel_Types = () => {
let hotel_type = [...this.state.hotel_type];
hotel_type = [
{ id: "hotel", value: "hotel", name: "Hotel" },
{ id: "apartment", value: "apartment", name: "Apartment" },
{ id: "villa", value: "villa", name: "Villa" },
];
this.setState({ hotel_type });
};
And Finally this is the render function
{this.renderSelect(
"hotel_type",
"Hotel Type",
this.state.hotel_type
)}
Render select function
renderSelect(name, label, options) {
const { data, errors } = this.state;
return (
<Select
options={options}
name={name}
value={data[name]}
label={label}
onChange={this.handleChange}
error={errors[name]}
/>
);
}
Now i am struggling to get the data populated in the renderselect function. I am quite new to react and i am actually assuming this might be a silly question therefore kindly bear with me. What could be wrong with this code. Please help. Thanks
I think in first place, you have a problem here:
populateHotel_Types = () => {
let hotel_type = [...this.state.hotel_type];
hotel_type = [
{ id: "hotel", value: "hotel", name: "Hotel" },
{ id: "apartment", value: "apartment", name: "Apartment" },
{ id: "villa", value: "villa", name: "Villa" },
];
this.setState({ hotel_type });
};
Here, you are filling hotel_type with your state. And below, you are redefining the array, so you will have just this 3 new objects. So should do this to have the full list:
populateHotel_Types = () => {
const hotel_type = [
...this.state.hotel_type,
{ id: "hotel", value: "hotel", name: "Hotel" },
{ id: "apartment", value: "apartment", name: "Apartment" },
{ id: "villa", value: "villa", name: "Villa" },
];
this.setState({ hotel_type });
};
I suspected this was a silly question and indeed it was. I was forgetting to run the function populateHotel_Types in the componentDidMount function. Therefore the state was not being updated appropriately. I am leaving this here so that any newbie like myself will get an answer to such a scenario

Select the table rows by default based on the data in antd table

I'm new to antd and I'm stuck at one place in my project. I want to check/select the checkboxes of rows by default based on the sourcedata or data.
for example if i have the datasource as
const data =
[
{
key: "1",
name: "John",
age: 22,
chosen: true,
working: null
},
{
key : "2",
name: "Jason",
age: 23,
chosen: false,
working: 'John'
}]
So based on datasource if any object has chosen key as true, I want to check/select the checkbox of those rows by default.
I can filter out the data array depending on the chosen key has the value true or not. But how to check the checkbox by default? Is there any prop for the antd table, which will take the array of filtered data and check/select the checkbox for those rows?
I tried to check the rows using checked attribute inside getCheckboxProps but when I use that in console I get a warning saying "Warning: [antd: Table] Do not set checked or defaultChecked in getCheckboxProps. Please use selectedRowKeys instead."
Below is the code which I'm currently using.
const data =
[
{
key: "1",
name : "John",
age : 22,
chosen: true,
working: null
},
{
key : "2",
name: "Jason",
age: 23,
chosen: false,
working: "John"
}
]
const fiterSelectedRows = data.filter(row => {
return row.chosen;
});
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(
`selectedRowKeys: ${selectedRowKeys}`,
"selectedRows: ",
selectedRows
);
},
getCheckboxProps: record => {
return {
disabled: record.working != null,
name: record.working
};
}
};
<Table rowSelection={rowSelection} columns={columns} dataSource={data}/>
Notice selectedRowKeys: data.filter(item => item.chosen).map(item => item.key). selectedRowKeys contain all keys of items, all items have keys in here will be checked by default.
You need to get all items that have chosen is true.
data.filter(item => item.chosen)
// [{key: '1', name: 'John Brown', ...},
// {key: '3', name: 'Joe Black', ...},
// {key: '4', name: 'Joe Black', ...}]
// all items have chosen is true
Then get all keys of this array.
data.filter(item => item.chosen).map(item => item.key)
// ['1', '2', '3']
// all keys of items have chosen is true
Exmample code:
Data
const data = [{
key: '1',
name: 'John Brown',
age: 32,
chosen: true,
address: 'New York No. 1 Lake Park',
}, {
key: '2',
name: 'Jim Green',
age: 42,
chosen: false,
address: 'London No. 1 Lake Park',
}, {
key: '3',
name: 'Joe Black',
age: 32,
chosen: true,
address: 'Sidney No. 1 Lake Park',
}, {
key: '4',
name: 'Disabled User',
age: 99,
chosen: true,
address: 'Sidney No. 1 Lake Park',
}];
Datatable
class App extends React.Component {
state = {
selectedRowKeys: data.filter(item => item.chosen).map(item => item.key), // Check here to configure the default column
loading: false,
};
start = () => {
this.setState({ loading: true });
// ajax request after empty completing
setTimeout(() => {
this.setState({
selectedRowKeys: [],
loading: false,
});
}, 1000);
};
onSelectChange = selectedRowKeys => {
console.log('selectedRowKeys changed: ', selectedRowKeys);
this.setState({ selectedRowKeys });
};
render() {
const { loading, selectedRowKeys } = this.state;
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
const hasSelected = selectedRowKeys.length > 0;
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button type="primary" onClick={this.start} disabled={!hasSelected} loading={loading}>
Reload
</Button>
<span style={{ marginLeft: 8 }}>
{hasSelected ? `Selected ${selectedRowKeys.length} items` : ''}
</span>
</div>
<Table rowSelection={rowSelection} columns={columns} dataSource={data} />
</div>
);
}
}
The author above said all the right things, I decided to share my experience. I have an array of objects with no key field (hello backend). Initially I filtered this array by a condition (depends on your task), for example, that the coin_symbol field === "WBNB". After filtering, I immediately use map to create a new array. Don't forget to make local state.
const [selectedRowKeys, setSelectedRowKeys] = useState()
setSelectedRowKeys(dashboardData?.filter(i => i.coin_symbol === 'WBNB').map(i => i.id))
Then, after digging in the table props, I saw a props defaultSelectedRowKeys, which takes an array. Further everything is simple - to this props assign value to our new array.
const rowSelection = { defaultSelectedRowKeys: selectedRowKeys, ...otherProps (like onChange, getCheckboxProps, etc.)
Another important thing - if you have, as I do, the data from the server go long, better not render a table, but rather, for example, some kind of loading text or a slider.
selectedRowKeys ? <YourTable dataSource={yourData} rowSelection={rowSelection}/> : <Loader/>
I hope it helps someone! (~ ̄▽ ̄)~

How to add dropdown values dynamically on onchange of another dropdown values in react js?

componentDidMount(){
this.setState({
values2:[{ name: 'Q1', id: 1 },
{ name: 'Q2', id: 2 },
{ name: 'Q3', id: 3 },
{ name: 'Q4', id: 4 }]
});
}
setQuarterData(){
var optionTemplate2 = this.state.values2.map(v => (
<option value={v.id} key={v.id}>{v.name}</option>
));
document.getElementById('quarter').innerHTML(optionTemplate2);
// document.getElementById('quarter').style.background="red";
console.log(optionTemplate2);
}
i am getting data in optionTemplate2 , but i unable to set in select
0: {$$typeof: Symbol(react.element), type: "option", key: "1", ref: null, props: {…}, …}
1: {$$typeof: Symbol(react.element), type: "option", key: "2", ref: null, props: {…}, …}
2: {$$typeof: Symbol(react.element), type: "option", key: "3", ref: null, props: {…}, …}
3: {$$typeof: Symbol(react.element), type: "option", key: "4", ref: null, props: {…}, …}
length: 4
proto: Array(0)
i want to set it here:-
<Form.Group>
<Form.Label>Quarters</Form.Label>
<Form.Control as="select" id="quarter">
</Form.Control>
</Form.Group>
class FirstComponent extends React.Component{
constructor(props){
super(props);
let todayDate = new Date();
this.state = {
finsclYear: [
{ name: '2014-2015', id: "2014-03-31"},
{ name: '2016-2017', id: "2016-03-31" },
{ name: '2017-2018', id: "2017-03-31" },
{ name: '2018-2019', id: "2018-03-31" },
{ name: '2019-2020', id: todayDate}
],
quarter:[ ],
chartData:chartData[0],
tableData: FilterTableCustom
};
this.setQuarterData=this.setQuarterData.bind(this);
this.changeData=this.changeData.bind(this);
}
setQuarterData(el){
let value=el.target.value;
let quarter;
let today = new Date(value);
let month=today.getMonth();
//calculating quarter for financial year
if(month<12 && month>2){
quarter = Math.floor(month / 3);
}
else{
quarter = Math.floor((month+12) / 3);
}
let list2=document.getElementById("quarter");
switch(quarter){
case 1:
this.setState({
quarter:[{ name: 'Q1', id: 1 } ]
});
break;
case 2:
this.setState({
quarter:[{ name: 'Q1', id: 1 },
{ name: 'Q2', id: 2 } ]
});
break;
case 3:
this.setState({
quarter:[{ name: 'Q1', id: 1 },
{ name: 'Q2', id: 2 },
{ name: 'Q3', id: 3 }]
});
break;
case 4:
this.setState({
quarter:[{ name: 'Q1', id: 1 },
{ name: 'Q2', id: 2 },
{ name: 'Q3', id: 3 },
{ name: 'Q4', id: 4 }]
});
break;
default :
null
}
}
changeData(){
this.setState({
chartData:chartData2[0],
tableData: FilterTableCustom2
});
}
render(){
const {tableData}=this.state;
const {chartData}=this.state;
console.log(tableData);
const {quarter} =this.state;
let finsclYearData = this.state.finsclYear.map(v => (
<option value={v.id} key={v.id}>{v.name}</option>
));
let quarterData="";
if(quarter.length!=0){
quarterData =quarter.map(v => (
<option value={v.id} key={v.id}>{v.name}</option>
));
}

how to access a particular object element in array

I have used a map function to using reduce and I got an array of objects.
How can I get a particular value in the "return"?
Below is the console output
{design job: Array(2)}
design job: Array(2)
0:
fullName: "Rakesh"
phoneno: "1111111111"
__proto__: Object
1:
fullName: "test user"
phoneno: "9176837787"
__proto__: Object
length: 2
__proto__: Array(0)
__proto__: Object
Below is my code
const list = appliedCandidates.reduce(
(appliedCandidate, { Title, fullName, phoneno }) => {
(appliedCandidate[Title] = appliedCandidate[Title] || []).push({
fullName: fullName,
phoneno: phoneno
});
return appliedCandidate;
},
{}
);
console.log(list);
return (
<div>
{Object.keys(list).map((item, i) => {
return (
<ul>
{item}
<li key={i}>{item.fullName}</li>
</ul>
);
})}
</div>
);
Assuming your data looks like this:
const jobs = {
"design job": [
{
fullName: "Rakesh",
phoneno: "1111111111"
},
{
fullName: "test user",
phoneno: "9176837787"
}
],
"another job": [
{
fullName: "Rakesh",
phoneno: "1111111111"
},
{
fullName: "test user 2",
phoneno: "9176837787"
}
]
};
Here's the code that returns the JSX to display all the jobs, and for each job, all the candidates:
return Object.entries(jobs).map(([title, candidates]) => (
<ul>
<h3>{title}</h3>
{candidates.map((c, i) => (
<li key={i}>{c.fullName}</li>
))}
</ul>
));
function iMGroot() {
let appliedCandidates = [{
Title: 'title-1',
fullName: 'fullName-1',
phoneno: 'phoneno-1'
},
{
Title: 'title-11',
fullName: 'fullName-11',
phoneno: 'phoneno-11'
},
{
Title: 'title-12',
fullName: 'fullName-12',
phoneno: 'phoneno-12'
},
{
Title: 'title-13',
fullName: 'fullName-13',
phoneno: 'phoneno-13'
}, {
Title: 'title-14',
fullName: 'fullName-14',
phoneno: 'phoneno-14'
}
]
const list = appliedCandidates.reduce(
(appliedCandidate, {
Title,
fullName,
phoneno
}) => {
(appliedCandidate[Title] = appliedCandidate[Title] || []).push({
fullName: fullName,
phoneno: phoneno
});
return appliedCandidate;
}, {}
);
console.log(list);
return ( `<div> ${Object.keys(list).map((item, i) => {
return (
`<ul>
${list[item].map(lItem=>{
return `
<li>${lItem.fullName}</li>
<li>${lItem.phoneno}</li>
`
})}
</ul>`
)
})}</div>`
);
}
console.log(iMGroot())
PS: see the return statement of function iMGroot.
Since definition of appliedCandidates is missing, I've filled it in the above function.

Resources