render nested arrays with react by display key only once - javascript

I have a nested array and I would like to render this array with JSX code such that key like array1 should be display once and the text should be displayed as list and then continue the same loop with the next array. I have tried using map function and for loop but could not achieve success.
sampleArray : [{"array1": [ {"text": "abc"},{"text": "def"}, {"text": "ghi"}],
"array2":[{"text": "efg"}, {"text": "fgh"}]]
Please suggest me map function to iterate over this array to render into JSX code. Thanks

Hey I don't know if you made a mistake in your object, but here are two versions of this implementation with your object and with my update:
Ignore typings did it in TypeScript
export const Test = ({ className }: Test) => {
const sampleArray = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
const sampleArray2 = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
},
{
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
return (
<>
{/* YOUR VERSION */}
<div>
{Object.keys(sampleArray[0]).map((key) => {
return (
<div>
<div id="title">{key}</div>
{sampleArray[0].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
{/* UPDATED VERSION */}
<div>
{sampleArray2.map((key) => {
const title = Object.keys(key)[0]
return (
<div>
<div id="title">{title}</div>
{key[title].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
</>
)
}

Related

How to map through array of objects and list each object in a card using javascript and react?

i have the data structure like below,
const item = {
id: '1',
orders: [
{
id: '1',
title: 'order-1',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
}
],
subItems: [
{
id: '1',
title: 'subitem-one',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '1',
title: 'subitem1-order-one',
status: 'new',
},
{
id: '2',
title: 'subitem1-order-two',
status: 'new',
},
]
},
{
id: '2',
title: 'subitem-two',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '2',
title: 'subitem2-order-one',
status: 'new',
},
},
I have to display each subitem name from above data in each card in a list.
below is how it should look in a list.
below is my code,
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
//how should i map the items data to loop through each subitem and display it as in the picture above.
);
}
I am not sure how to loop through each subitem and display its name in a card using javascript and react.
could someone help me with this. thanks.
Ciao, assuming that you are using Card component from material ui you could do something like:
import { Card, CardHeader} from '#material-ui/core';
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
items.subItems.map(el => {
<Card>
<CardHeader
title={el.title}
/>
</Card>
})
);
}
I'm assuming that Parent is a React functional component, so you can return the data in this way,
function Parent({items} : Props) {
return (
<div>
{
items.subItems.map(function (subItem) {
return <div>{subItem.title}</div>;
});
}
</div>
)
}
The template is shown below:
const Parent = () => {
const data = [...] // the data must be an array
return data.map(child => <Child data={child} />)
}

I have many checkbox it render as the description below I want to change the nested value its in blue circle in the pic

This is my state:
view screenshot
the part in the circle is the part of the state that I want to change
**This is my checkbox input **
{this.state.data.map((elm) => (
<div className={classes.rowContainer}>
<h3>{elm.name}</h3>
{elm.groupes.map((group) => (
<input
className={classes.checkBox}
name={elm.name}
groupes={group.groupName}
checked={group.value}
type='checkbox'
onChange={this.changeValue}
/>
))}
</div>
))}
This is the object passed to component:
const data = [
{
name: 'Créer un groupe',
groupes: [
{ name: 'commercial', value: true },
{ name: 'manager', value: false }
]
},
{
name: 'Détruire un groupe ',
groupes: [
{ name: 'commercial', value: false },
{ name: 'manager', value: false }
]
}
]
To update the specific boolean value for a given checkbox, you can make use of the .map() calls indexes from the arrays, and pass those to the onChange handler of the checkbox inputs to update the correct value in the state.
To update the state itself safely and without mutation, you'll need to deep copy the data array (using a round trip through JSON in this case), then update the right value using the indexes, then assign the new data to the state.
Here is a working snippet that illustrates how this works:
const data = [{
name: 'Créer un groupe',
groupes: [
{ name: 'commercial', value: true },
{ name: 'manager', value: false }
]
}, {
name: 'Détruire un groupe ',
groupes: [
{ name: 'commercial', value: false },
{ name: 'manager', value: false }
]
}];
class App extends React.Component {
constructor(props) {
super(props);
this.state = { data };
}
changeValue = (sectionIndex, groupIndex) => {
const dataCopy = JSON.parse(JSON.stringify(this.state.data));
const group = dataCopy[sectionIndex].groupes[groupIndex];
group.value = !group.value;
this.setState({ data: dataCopy });
}
render() {
return (
<div>
{ this.state.data.map((elm, i) => (
<div key={`${i}`}>
<h3>{elm.name}</h3>
{ elm.groupes.map((group, j) => (
<input key={`${i}${j}`} name={elm.name}
checked={group.value} type="checkbox"
onChange={() => this.changeValue(i, j)} />
)) }
</div>
)) }
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

Select JavaScript object from onClick event

I have a parent component that contains two arrays
newChoiceArray: [
{ id: 1, text: '1', questionId: 'favourite number?', value: '1' },
{ id: 2, text: '2', questionId: 'favourite number?', value: '2' },
{ id: 3, text: '3', questionId: 'favourite number?', value: '3' },
],
ChoiceArray: [
{ id: 4, text: 'red', questionId: 'favourite colour?', value: '1' },
{ id: 5, text: 'blue', questionId: 'favourite colour?', value: '4' },
],
}
I have a component that renders a button for each object inside of an array
const MultiChoiceQuestions = props => {
const { multiChoiceArray, handleClick } = props
return (
<div>
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} onClick={handleClick}>
{questionChoice.text}
</button>
)
})}
</div>
)
}
When I render my child component, I can pass an array as a prop
<MultiChoiceQuestions handleClick={this.testClick} multiChoiceArray={newChoiceArray} />
<MultiChoiceQuestions handleClick={this.testClick} multiChoiceArray={ChoiceArray} />
When I click the button, I want to see which object inside of that array is being selected.
testClick = event => {
event.preventDefault()
console.log(event.currentTarget)
}
Instead of outputting this <button type="button">3</button>
It should output this { id: 3, text: '3', questionId: 'favourite number?', value: '3' },
you can pass the object as button value, for example:
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} value={JSON.stringify(questionChoice)} onClick={handleClick}>
{questionChoice.text}
</button>
)
}
and then you can catch this, using property value from currentTarget:
testClick = event => {
event.preventDefault()
console.log(JSON.parse(event.currentTarget.value))
}
I don't know if is the best approach, but I know that works.
UPDATE
I was wondering about this question, will you use something else from event object ? else you can pass directly the item into the function:
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} onClick={() => handleClick(questionChoice)}>
{questionChoice.text}
</button>
)
}
// parent file
testClick = obj => {
console.log(obj)
}

react-sortablejs - Setting the 'onChange' method on an object with nested arrays

I'm using the react-sortablejs library.
When trying to move cards within the list. I get the error:
Cannot read property 'map' of undefined
I have a dense structure and it gets lost here. How to handle onChange so that I can see in the console that the order of the notes within the list has changed.
Demo here
import Sortable from 'react-sortablejs';
// Functional Component
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
console.log(order)
onChange(order);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
class App extends React.Component {
state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
},
{
id: "1oiwewedf098",
title: "ListItems3",
listItemsId: "1a49f25dsd8"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems4",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems5",
listItemsId: "1a49f25"
},
{
id: "1oiwewe098",
title: "ListItems6",
listItemsId: "1a49f25dsd"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems7",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems8",
listItemsId: "234a49f25"
},
{
id: "df098",
title: "ListItems9",
listItemsId: "1asd8"
}
]
}
]
}
};
render() {
const c = this.state.item['lists'].map(item => { return item.listItems});
return (
this.state.item['lists'].map(item => {
return (<div>
{item.title}
<SortableList
key={uniqueId()}
items={item}
onChange={(item) => {
console.log(item)
this.setState({item});
}}
>
</SortableList>
</div>)
})
)
}
};
Thanks in advance.
You have to update few changes in your code.
Update the SortableList function as below.
First pass data-id={val.id} in li and after that in onChange method you will receive the order with id. So based on that we are sorting the records.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
items.listItems.sort(function(a, b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
onChange(items);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val.id}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
Update the onChange event of App component.
onChange={(item) => {
let itemObj = {...this.state.item};
itemObj.lists.map(x=>{
if(x.id === item.id) x = item;
});
this.setState({itemObj});
}}
That's it!
Here is the working demo for you
https://stackblitz.com/edit/react-sortablejs-blzxwd
When remove the onChange event in the Sortable list, Its works.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};

React-Table not rendering data

I am trying to render some data in a react-table component however the data doesn't load. I have tested out with dummy data of the exact same format and it works fine. However when I make an API call and get data of the same format and push it to the list of data i'm passing to the react-table the table does not render it. Please help me identify the issue. Cheers
Setting up the columns:
columns: [
{
Header: "Employee ID",
accessor: "EmployeeID"
},
{
Header: "First Name",
accessor: "FirstName"
},
{
Header: "Last Name",
accessor: "LastName"
},
{
Header: "Date of Birth",
accessor: "DateOfBirth",
},
{
Header: "Status",
accessor: "Status",
},
{
Header: "Gender",
accessor: "Gender",
},
{
Header: "UpdatedDateUTC",
accessor: "UpdatedDateUTC",
}
]
What the data looks like:
{"EmployeeID":"63c571b3-bff0-4ce1-94f7-255c235580fa","FirstName":"Clive","LastName":"Thomas","Status":"ACTIVE","DateOfBirth":"/Date(697248000000+0000)/","Gender":"M","UpdatedDateUTC":"/Date(1533706298000+0000)/"}
My API call and how I'm saving the data item to state. (I console logged the value of the data I'm getting and it is in the correct format)
fetch('http://localhost:3100/employees')
.then((resp) => {
return resp.json()
})
.then((data) => {
let temp = this.state.posts;
temp.push(data.Employees[1])
this.setState({posts: temp})
console.log(this.state.posts)
})
.catch((error) => {
console.log(error, "catch the hoop")
})
The state and the 'posts' list storing the posts in state at bottom (with dummy data):
state = {
title: "Choose an Endpoint",
activeOrg: "Orginisation",
isExpanded: false,
activeLink: 0,
authLink:'',
response: '',
post: '',
responseToPost: '',
show: false,
modalContent:"",
token:'',
verifier:'',
org:'',
orginisations: [
{ id: 1, name: "ANU"},
{ id: 2, name: "Bar"},
{ id: 3, name: "FANG"},
{ id: 4, name: "Atlassian"}
],
list: [
{ id: 1, name: "Employees" },
{ id: 2, name: "Leave Applications" },
{ id: 3, name: "Pay Items" },
{ id: 4, name: "Payroll Calendars" },
{ id: 5, name: "Pay Runs" },
{ id: 6, name: "Pay Slips" },
{ id: 7, name: "Settings" },
{ id: 8, name: "Superfund Products" },
{ id: 9, name: "Timesheets" }
],
columns: [
{
Header: "Employee ID",
accessor: "EmployeeID"
},
{
Header: "First Name",
accessor: "FirstName"
},
{
Header: "Last Name",
accessor: "LastName"
},
{
Header: "Date of Birth",
accessor: "DateOfBirth",
},
{
Header: "Status",
accessor: "Status",
},
{
Header: "Gender",
accessor: "Gender",
},
{
Header: "UpdatedDateUTC",
accessor: "UpdatedDateUTC",
}
],
posts: [
{"EmployeeID":"63c571b3-bff0-4ce1-94f7-255c235580fa","FirstName":"Clive","LastName":"Thomas","Status":"ACTIVE","DateOfBirth":"/Date(697248000000+0000)/","Gender":"M","UpdatedDateUTC":"/Date(1533706298000+0000)/"}
]
}
Render function:
render() {
let myClass=""
let EndpointList = (
<div>
{this.state.list.map((i) => {
i.id === this.state.activeLink ? myClass="endpoint activeLink" : myClass="endpoint"
return <Endpoint
key={i.id}
name={i.name}
myClass={myClass}
clicked={(event) => this.handleClickEndpoint(i, i.id)}/>
})}
</div>
);
let orgContainer = ""
this.state.isExpanded ? orgContainer="orgItem expanded" : orgContainer="orgItem notExpanded"
let OrgList = (
<div className={orgContainer}>
{this.state.orginisations.map((o) => {
return <Orginisation
key={o.id}
name={o.name}
clicked={(event) => this.handleClickOrg(o,o.id)}
></Orginisation>
})}
</div>
);
var activeContent=<ReactTable columns={this.state.columns} data={this.state.posts} noDataText={"Loading..."}></ReactTable>
// const columns = Object.keys(this.state.data[0]).map((key, id)=>{
// console.log(key)
// return {
// Header: key,
// accessor: key,
// }
// })
return (
<Router>
<Route path='/' exact render={
() => {
return (
<div className='authenticateContainer'>
<a href={this.state.authLink} className='fill-div'>Click to Auntheticate</a>
</div>
)
}
}/>
<Route path='/home' render={
() => {
return (
<div>
<div className='sideBar'>
<div className='logoHolder'>
<img className='logo' alt='Logo' src={'./Assets/logo.png'}></img>
</div>
{EndpointList}
{OrgList}
<div style={{}} className="org button" onClick={this.expandOrg}>
<img className="orgLogo" alt='Logo' src={'./Assets/orgLogo.png'}></img>
{this.state.activeOrg}
</div>
</div>
<div className="container" id={this.state.title}>
{/* <button onClick={() => { this.setCredentials() }}>CLICK ME</button> */}
<div className="contentContainer">
<div className="head">
{this.state.title}
</div>
{activeContent}
</div>
</div>
</div>
)
}
} />
</Router>
);
}
}
Instantiating the react-table (also in render function above):
var activeContent=<ReactTable columns={this.state.columns} data={this.state.posts} noDataText={"Loading..."}></ReactTable>
I have also printed the dummy data that is successfully being inserted into the list as well as the API data which is not. As you can see they are clearly identical:
Not sure if this will resolve your issue, but IMO you should refactor this to be
fetch('http://localhost:3100/employees')
.then((resp) => {
return resp.json()
})
.then((data) => {
let temp = [...this.state.posts]
temp.push(data.Employees[1])
this.setState({
posts: temp,
data: data
})
console.log(this.state.posts) //this will not have the newest values yet, setState is async
})
.catch((error) => {
console.log(error, "catch the hoop")
})
It's not good practice to perform manipulations on react state
Why are you pushing Employees[1]? That would be the second record.

Categories