I am trying to create a multidimensional list from object full of arrays from a rest request in Javascript. The issue is my ability iterate over an array of objects. Can someone give me an example on how to turn this data structure into a JSX component?
I am trying to create a list that is wrapped in a div and looks like:
<div>
<lo>
<li>
<ul>
<li>Row Cell</li>
<li>Row Cell</li>
</ul>
</li>
<li>
<ul>
<li>Row Cell</li>
<li>Row Cell</li>
</ul>
</li>
</lo>
</div>
The data structure looks like this,
The function that is set in the React Component is the following,
createBodyDisplay(){
var ar = this.state.data.request.body;
var returnString = '';
for (var key in ar) {
console.log(ar);
if (ar.hasOwnProperty(key)) {
if(ar instanceof Array){
console.log('This is a test to see if there is an array');
} else if (ar instanceof Object){
for (var key1 in ar) {
if (ar.hasOwnProperty(key1)) {
console.log(ar[key1]);
}
}
console.log(ar);
} else {
console.log('Not sure what this is');
}
// returnString= returnString+'<div>';
/// var x = numbers.map(Math.sqrt)
// console.log(ar[key]);
// returnString= returnString+'</div>';
}
}
// console.log(returnString);
return returnString;
}
See sandbox here for live example: https://codesandbox.io/s/confident-heyrovsky-s0zg4
Assuming your data-structure looks something like:
const newData = {
dogs: [
{ type: "row-cell", value: "Golden" },
{ type: "row-cell", value: "Husky" }
],
cats: [
{ type: "row-cell", value: "Feline" },
{ type: "row-cell", value: "Hairless" }
]
};
We can use Object.entries() to cleanly create an array of arrays, for each key-value pair. Then use .map() to create our outer-ordered-list items. And within each group, we will use another .map() to create the unordered-list-items.
Working code:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
data: {}
};
componentDidMount() {
const newData = {
dogs: [
{ type: "row-cell", value: "Golden" },
{ type: "row-cell", value: "Husky" }
],
cats: [
{ type: "row-cell", value: "Feline" },
{ type: "row-cell", value: "Hairless" }
]
};
this.setState({
data: newData
});
}
createNestedLists = () => {
const { data } = this.state;
const lists = Object.entries(data).map(([type, arr]) => {
return (
<li>
<ul>
{arr.map(item => {
return (
<li>
{item.type} - {item.value}
</li>
);
})}
</ul>
</li>
);
});
return <ol>{lists}</ol>;
};
render() {
return <div>{this.createNestedLists()}</div>;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related
I have a bit of a dilemma.
In the save function I need to call a function renderMap that renders a dynamic google map. However I need to call it after the DOM has been rendered. I can't seem to find a solution for this. I realised you can't add a class to the save function with the React lifecycle so I am stopped. It does work for the edit function though. What are the possibilities?
import { __ } from '#wordpress/i18n';
import { registerBlockType } from '#wordpress/blocks';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { Component } from '#wordpress/element';
const renderMap = function() {
let googleMap = document.getElementById('google-map')
let map
map = new google.maps.Map(googleMap, {
center: { lat: 37.79406, lng: -122.4002 },
zoom: 14,
disableDefaultUI: true,
})
}
registerBlockType( 'splash-blocks/google-maps', {
title: __('Google maps locations', 'google-maps'),
icon: 'megaphone',
category: 'common',
keyword: [
__( 'Display Google maps locations' ),
],
atrributes: {
markers: {
type: 'object'
},
address: {
type: 'string',
default: 'xxxxxxxxx',
},
api_key: {
type: 'string',
default: 'xxxxxxxxx',
}
},
edit: class extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
renderMap()
}
render() {
const { attributes, setAttributes } = this.props
return (
<div id='google-map'>
</div>
)
}
},
save: props => {
const {
className,
attributes: { mapHTML }
} = props;
renderMap()
return (
<div id='google-map'>
</div>
)
}
})
i want to replace the values of the nested array object like the below one, when button is clicked it will replace the old values of the x indexed object and set the new values there.
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData:[
{
id:1,
title:"OldTitle1"
},
{
id:2,
title:"OldTitle2"
}
],
}
this.changeTab = this.changeTab.bind(this)
}
changeTab(){
const newData={
id=3,
title="New One"
}
//replace the above new data in the second object of nested array in state
}
render(){
return(
<button type="button" >Add</button>
)
;}
}
export default compo
the state should be like this after
tabsData:[
{
id:1,
title:"OldTitle"
},
{
id:3,
title:"New One"
}
]
Not able to comment as my rep is less than 50...based on an idea of what you need here is the code.
https://codesandbox.io/s/brave-lumiere-dh9ry?file=/src/App.js
const [data, setData] = React.useState([
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]);
const newData = { id: 3, title: "New One" };
const addData = () => {
const newArr = data;
newArr[1] = newData;
console.log("newArr>>>>", newArr);
setData([...newArr]);
};
You could do something like this...
import React from "react";
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData: [
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]
};
this.changeTab = this.changeTab.bind(this);
}
changeTab() {
const newData = {
id: 3,
title: "New One"
};
// Make duplicate since you can't mutatue state
let newTabData = [...this.state.tabsData];
const id = 2; // id to be removed
// CASE 1: If you want to maintain order
const index = newTabData.findIndex((data) => data.id === id);
if (index > -1) {
// replace oldData with newData
newTabData.splice(index, 1, newData);
} else {
// simply add newData at last
newTabData.push(newData);
}
// CASE 2: If order doesn't matter
// // remove oldData
// newTabData = newTabData.filter((data) => data.id !== id);
// // add new data at last
// newTabData.push(newData);
// finally update the state irrespective of any case
this.setState({ tabsData: newTabData });
}
render() {
return (
<div>
<button type="button">
Add
</button>
<button type="button" onClick={this.changeTab}>
Change
</button>
<br />
{JSON.stringify(this.state, null, 2)}
</div>
);
}
}
export default compo;
I'm using a template file that takes in data from a JSON and displays it as a list
JSON -
"items":[
{
"name":"a",
},
{
"name":"b",
},
{
"name":"c",
}
]
JS File
var items= this.props.data.items.map(function(items){
return <li key={items.name}><span className={items.name}></span><em>{items.name}</em></li>
})
//where it later gets rendered like so:
<div className="four columns main-col">
<div className="bars">
<ul className="items">
{items}
</ul>
</div>
</div>
However I want to modify the data, so that its more categorized, and will have nested objects
Example:
"categorizedItems":[
{
"type":"a",
"items":[
{
"name":"apple"
},
{
"name":"banana"
}
]
},
{
"type":"b",
"items":[
{
"name":"car"
}
]
}
]
So i thought, since it is a nested JSON object, I will need to map twice, so i tried the following:
var categories= this.props.data.categorizedItems.map(function(category){
var items= category.items.map(function(item){
return <li key={items.name}><span className={items.name}></span><em>{items.name}</em></li>
})
return <ul key={category.type}>{items}</ul>
})
//and i render it the same way
<div className="four columns main-col">
<div className="categories">
{categories}
</div>
</div>
However this gives me errors saying "Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead."
I dont understand how what I am doing (the nested mapping) is different from the original code (single mapping).
I resolved the errors in your code
Try this
import React from "react";
import "./styles.css";
const data = [
{
type: "a",
items: [
{
name: "apple"
},
{
name: "banana"
}
]
},
{
type: "b",
items: [
{
name: "car"
}
]
}
];
const categories = data.map((category) => {
const items = category.items.map(function (item) {
return (
<li key={item.name}>
<span className={item.name}></span>
<em>{item.name}</em>
</li>
);
});
return <ul key={category.type}>{items}</ul>;
});
export default function App() {
return (
<div className="four columns main-col">
<div className="categories">{categories}</div>
</div>
);
}
Here is sandbox link - https://codesandbox.io/s/nervous-noether-80ye9?file=/src/App.js:0-714
the problem in existing code.
Instead of
var categories= this.props.data.categorizedItems.map(function(category){
var items= category.items.map(function(item){
return <li key={items.name}><span className={items.name}></span><em>{items.name}</em></li>
})
return <ul key={category.type}>{items}</ul>
})
Try
var categories= this.props.data.categorizedItems.map(function(category){
var items= category.items.map(function(item){
return <li key={item.name}><span className={item.name}></span><em>{item.name}</em></li>
})
return <ul key={category.type}>{items}</ul>
})
I have a list of od dicts. It looks like this:
document.__moreComments = [
{ id: 2, author: '...', text: '...', date: '...' },
{ id: 1, author: '...', text: '...', date: '...' },
];
I want to sort my data by date and rendered it.
Firstly I want to create an object in the declaration and set it in state. Then sorting and represent changing data. I have a problem.
import React, { Component } from "react";
var addcomments = document.__moreComments;
class AdditionalComments extends Component {
constructor() {
super();
// this.state = addcomments
this.state = {
comments: addcomments.map(addcomment => [
addcomment.id,
addcomment.author,
addcomment.text,
addcomment.date
])
};
console.log(this.state);
}
changeMessage() {
let sortedComments = this.state.comments;
this.setState({
comments: sortedComments.sort((a, b) => a.date > b.date)
});
console.log(this.state.comments);
}
render() {
return (
<div>
<h1>hi Eugene {this.state.comments} </h1>
<button onClick={() => this.changeMessage()}>Click</button>
</div>
);
}
}
export default AdditionalComments;
I create dict of dict. And of course I want to know. Is it right to do what I do or I need another approach?
Thanks. I'm a beginner.
Sort sorts array in-place(that means it won't return new instance of array), that's the reason your array is not getting sorted. You should try below approach:
changeMessage() {
let sortedComments = [...this.state.comments].sort((a,b) => new Date(a.date) - new Date(b.date))
this.setState({
comments: sortedComments
}, () => {console.log(this.state.comments)});
}
How can I make a checkbox checked if a value exists in array of object in reactjs ?
I have tried using includes function but it is not working.
I have array of object in employeeUnder key -
My array is -
"employeeUnder": [
{
"_id": "5d1a0a8a09b9cb0034d01aaf",
"employ": {
"_id": "5d120eba60093e02248d6a81",
"name": "Sehzan"
}
},
{
"_id": "5d1a0a8a09b9cb0034d01ab0",
"employ": {
"_id": "5d120eba60093e02248d6a83",
"name": "Sumit"
}
},
{
"_id": "5d1a0a8a09b9cb0034d01ab1",
"employ": {
"_id": "5d120eba60093e02248d6a7c",
"name": "Hariom"
}
}
],
I have to check if -
this.state.allemployees._id === employeeUnder.employ._id then checkbox must be checked.
My Code for input checkbox is -
if (this.state.allemployees && this.state.allemployees.length > 0) {
return (this.state.allemployees.map((employee) =>
<tr key={employee.empmainid}>
<td>{employee.empname}</td>
<td>{employee.empid}</td>
<td><input onChange={this.handleCheckbox} getUsername={employee.empname} className="" type="checkbox" checked name={employee.empmainid} value={employee.empmainid} /></td>
</tr>))
}
Right now all the checkbox are checked because I didn't apply the condition.
I want if a value exists in array of object then it must be checked otherwise NO.
Checkout this sandbox: https://codesandbox.io/s/blissful-edison-bjh0s
We'll be working with two arrays here:
allEmployees (never mutate)
employeesUnder (always update)
We can dynamically change the data inside employeesUnder through checking/toggling the corresponding input tag.
Essentially, inside the onChange() event, we will pass the id associated with an employee, if the input was already checked, that means it was already in the employeesUnder array. So we will use that id, to filter that employee out. The opposite would occur if the id was not found inside the array. So we would add the employee to employeesUnder.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
employeesUnder: [
{
_id: "5d1a0a8a09b9cb0034d01aaf",
employ: {
_id: "5d120eba60093e02248d6a81",
name: "Sehzan"
}
},
{
_id: "5d1a0a8a09b9cb0034d01ab0",
employ: {
_id: "5d120eba60093e02248d6a83",
name: "Sumit"
}
},
{
_id: "5d1a0a8a09b9cb0034d01ab1",
employ: {
_id: "5d120eba60093e02248d6a7c",
name: "Hariom"
}
}
],
allEmployees: [
{
_id: "3ds8f8ds9d8fds9f8a9f8afaf",
employ: {
_id: "eworweokrkowekoo34324234",
name: "Woofers"
}
},
{
_id: "5d1a0a8a09b9cb0034d01aaf",
employ: {
_id: "5d120eba60093e02248d6a81",
name: "Sehzan"
}
},
{
_id: "5d1a0a8a09b9cb0034d01ab0",
employ: {
_id: "5d120eba60093e02248d6a83",
name: "Sumit"
}
},
{
_id: "5d1a0a8a09b9cb0034d01ab1",
employ: {
_id: "5d120eba60093e02248d6a7c",
name: "Hariom"
}
}
]
};
handleCheck = id => {
const { allEmployees, employeesUnder } = this.state;
const employeesUnderIds = employeesUnder.map(employee => employee._id);
if (employeesUnderIds.includes(id)) {
//remove employee from employeesUnder list
const newArrWithRemovedEmployee = employeesUnder.filter(employee => {
return employee._id !== id;
});
this.setState({
...this.state,
employeesUnder: newArrWithRemovedEmployee
});
} else {
//add employee to employeesUnder list
const employeeIndex = allEmployees.findIndex(
employee => employee._id === id
);
const newArrWithAddedEmployee = [
...employeesUnder,
allEmployees[employeeIndex]
];
this.setState({
...this.state,
employeesUnder: newArrWithAddedEmployee
});
}
};
createList = () => {
const { allEmployees, employeesUnder } = this.state;
const employeesUnderIds = employeesUnder.map(employee => employee._id);
return allEmployees.map(employee => {
return (
<div>
<label>{employee.employ.name}: </label>
<input
type="checkbox"
value={employee._id}
checked={employeesUnderIds.includes(employee._id)}
onChange={() => this.handleCheck(employee._id)}
/>
</div>
);
});
};
render() {
return <div>{this.createList()}</div>;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);