I fetch data from json and try to display one of the arrays in my componenet but I get an error that map is not a function, what do I do wrong? How to get only one array of two? Is it array I have in json or an object?
import React, { Component } from 'react';
class Customer extends Component {
constructor() {
super();
this.state = {
customers : []
};
}
componentDidMount() {
fetch('myURL')
.then(response => response.json())
.then(json => this.setState({ customers: json}))
}
render () {
return (
<div>
{this.state.customers && this.state.customers.map(cust => (
<div>
<h1>{cust.CustomerName}</h1>
</div>
)
})}
</div>
)
}
}
export default Customer;
And my JSON file has two arrays that looks like this:
{
"fields": [
{
"id": "Customer_ID",
"description": "Customer ID",
"type": "Key",
},
{
"id": "Customer_ID",
"description": "Customer ID",
"type": "Key",
},
],
"list_items": [{"Customer_ID":1,"CustomerName":"ABS","CustomerType":"DTS"},
{"Customer_ID":2,"CustomerName":"Giu Sto","CustomerType":"STD"}]
}
You did not asign the items to customers in state. You should do it like this
componentDidMount() {
fetch('myURL')
.then(response => response.json())
.then(json => this.setState({ customers: json.list_items}))
}
I hope this solves your problem
Edit:
this.setState({customers:json}) will change customers state to an object which is not itterable and have the value of your json file customers:{fields: [...],list_items: [...]} but you only want list_items to be assigned to customers that's why you should access list_items from json and assign it directly to customers this.setState({customers:json.list_items_}
try logging whether the array is present or not.
const my_json = {
fields: [
{
id: "Customer_ID",
description: "Customer ID",
type: "Key",
},
{
id: "Customer_ID",
description: "Customer ID",
type: "Key",
},
],
list_items: [
{ Customer_ID: 1, CustomerName: "ABS", CustomerType: "DTS" },
{ Customer_ID: 2, CustomerName: "Giu Sto", CustomerType: "STD" },
],
};
my_json.list_items.map(customer => console.log(customer.CustomerName))
Related
I have spent a good part of the day trying to replace arrays of an existing nested object but I can't figure out how to do it. This is my original object:
{
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
text: 'Website questions',
items: Array(11)
}
]
},
{
"id": "79e42d88-7dd0-4f70-b6b4-dea4b4a64ef3",
"title": "Blogs",
"questions": [
...
]
},
{
"id": "439ded88-d7ed0-de70-b6b4-dea4b4a64e840",
"title": "App questions",
"questions": [
...
]
}
]
}
I would like replace the question arrays in the original object or in a copy of it.
const newMenu = [
{id: '34bb96c7-1eda-4f10-8acf-e6486296f4dd', text: 'Website questions', items: Array(24)},
{id: '520c2d3f-6117-4f6a-904f-2477e3347472', text: 'Blog questions', item: Array(7)},
{id: '302b658a-9d8c-4f53-80f6-3f2275bfble', title: 'App questions', items: Array(14)}
]
I am trying to do this by its index but unfortunately it doesn't work.
webSections.sections.forEach((item, index) => {
return webSections.sections[index].questions, newMenu[index]);
}
Does anyone see what am I doing wrong?
The value returned from the callback passed to forEach will not be used anywhere.
If you want to avoid mutating the original object and update questions, you can use Array.prototype.map and object spread syntax.
const object = {
"id": "a8df1653-238a-4f23-fe42-345c5d928b34",
"webSections": {
"id": "x58654a9-283b-4fa6-8466-3f7534783f8",
"sections": [
{
"id": "92d7e428-4a5b-4f7e-bc7d-b761ca018922",
"title": "Websites",
"questions": [
{
id: 'dee6e3a6-f207-f3db-921e-32a0b745557',
...
const updatedObject = {
...object,
webSections: {
...object.webSections,
sections: object.webSections.sections.map((section, index) => ({...section, questions: newMenu[index]}))
}
}
If you just want to mutate the original object
object.webSections.sections.forEach((_, index) => {
section.questions = newMenu[index]
})
const newSections = myObj.webSections.sections.map((obj, index) => {
const newQuestions = newItems[index];
return {
...obj,
questions: [newQuestions],
};
});
console.log(newSections);
MyObj is the main object.
This shall produce the new sections array you can combine it with your main object I suppose...
#Ramesh Reddy has the most thorough answer.
The simplest way if you don't care about mutation is:
myObject.webSections.sections.forEach((section, index) => {
section.questions = newMenu[index].items;
})
You have used your 'forEach' with wrong syntax. Check MDN on how it's used.
How can I get and set the filter values programmatically using material-table?
I want users to be able to save filter configurations as reports and recall them as needed.
Get works with a hook on change:
onFilterChange={(filters) => {
console.log('onFilterChange', filters);
}}
result is an array of filter definitions per column, looks like:
[
// [...]
{
"column": {
"title": "Date",
"field": "file_date",
"type": "date",
"tableData": {
"columnOrder": 3,
"filterValue": "2020-11-10T15:20:00.000Z",
"groupSort": "asc",
"width": "...", // lots of css calc stuff... :(
"additionalWidth": 0,
"id": 4
}
},
"operator": "=",
"value": "checked"
}
]
setting the filter on mount could/should work with defaultFilter at each column definition.
There are two parts to this, the get and the set.
Get - handled through the use of the tableRef prop on the MaterialTable component
Set - handled through the defaultFilter value on a column object.
import MaterialTable from "material-table";
import React, { useRef } from "react";
import { tableIcons } from "./tableIcons";
const firstNameFilter = 'Neil'
function App() {
const tableRef = useRef<any>();
return (
<div>
<button onClick={saveFilters(tableRef)}>Filters</button> // GET OCCURS HERE
<MaterialTable
tableRef={tableRef}
icons={tableIcons}
columns={[
{ title: "First", field: "name", defaultFilter: firstNameFilter }, // SET OCCURS HERE
{ title: "Last", field: "surname" }
]}
data={[
{ name: "Neil", surname: "Armstrong" },
{ name: "Lance", surname: "Armstrong" },
{ name: "Bob", surname: "Hope" }
]}
options={{ filtering: true }}
title="Reports"
/>
</div>
);
}
function saveFilters(tableRef: React.MutableRefObject<any>) {
return function handler() {
const columns = tableRef?.current?.state.columns.map((column: any) => ({
field: column.field,
filterValue: column.tableData.filterValue
}));
console.log(JSON.stringify(columns, null, 2));
};
}
export { App };
I want to structure the data that I get from a server, so I can use the TreeView component from Material UI: https://material-ui.com/api/tree-view/
I'm fetching large amounts of data so I want to fetch child nodes from the server when the user clicks on the expand button. So
when the first node is expanded a HTTP request is sent to a server which returns all of the children of that node. When another node is expanded the children of that node is fetched etc.
On startup of the page I want to fetch the root node and its children. The JSON returned will look something like this:
{
"division": {
"id": "1234",
"name": "Teest",
"address": "Oslo"
},
"children": [
{
"id": "3321",
"parentId": "1234",
"name": "Marketing",
"address": "homestreet"
},
{
"id": "3323",
"parentId": "1234",
"name": "Development",
"address": "homestreet"
}
]
}
When expanding the Marketing node I want to make a HTTP call to fetch the children of this node. So I would get JSON like this:
{
"children": [
{
"id": "2212",
"parentId": "3321",
"name": "R&D",
"address": "homestreet"
},
{
"id": "4212",
"parentId": "3321",
"name": "Testing",
"address": "homestreet"
}
]
}
But I am confused on how to create such a data structure which can later be used my the TreeView component. How can I create such a structure?
For anyone still looking for a solution to this problem I've recently tackled it using a combination of the selected and expanded props in the TreeView API. See this Code Sandbox demo for an example of how to asynchronously load new children and expand their parent once they are loaded.
import React from "react";
import TreeView from "#material-ui/lab/TreeView";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import ChevronRightIcon from "#material-ui/icons/ChevronRight";
import TreeItem from "#material-ui/lab/TreeItem";
import TreeNode from "./TreeNode";
const mockApiCall = async () => {
return new Promise((resolve) => {
setTimeout(() => {
const nextId = Math.ceil(Math.random() * 100);
resolve([
{
id: `${nextId}`,
name: `child-${nextId}`,
children: []
},
{
id: `${nextId + 1}`,
name: `child-${nextId + 1}`,
children: []
}
]);
}, Math.ceil(Math.random() * 1000));
});
};
export default class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: [],
selected: "1",
tree: new TreeNode({
id: "1",
name: "src",
children: []
})
};
}
handleChange = async (event, nodeId) => {
const node = this.state.tree.search(nodeId);
if (node && !node.children.length) {
mockApiCall()
.then((result) => {
this.setState({ tree: this.state.tree.addChildren(result, nodeId) });
})
.catch((err) => console.error(err))
.finally(() => {
this.setState({
selected: nodeId,
expanded: [...this.state.expanded, nodeId]
});
});
}
};
createItemsFromTree = (tree) => {
if (tree.children.length) {
return (
<TreeItem key={tree.id} nodeId={tree.id} label={tree.name}>
{tree.children.length > 0 &&
tree.children.map((child) => this.createItemsFromTree(child))}
</TreeItem>
);
}
return <TreeItem key={tree.id} nodeId={tree.id} label={tree.name} />;
};
render() {
return (
<TreeView
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
selected={this.state.selected}
onNodeSelect={this.handleChange}
expanded={this.state.expanded}
>
{this.createItemsFromTree(this.state.tree)}
</TreeView>
);
}
}
I am trying to make this work for two days now. I am trying to show Tree data in Ag-grid in ReactJS using this article : https://www.ag-grid.com/javascript-grid-server-side-model-tree-data/
Maybe I missed something from their documentation. Please someone help.
Obviously their Tree data is an enterprise feature and I referred to their server side model.
Expected functionality :
Tree data feature with data from server.
Two modes : one time fetching all data
Or lazy loading for batch wise data
My JSON is as follows:
[{
"employeeId": 101,
"employeeName": "Erica Rogers",
"jobTitle": "CEO",
"employmentType": "Permanent",
"children": [{
"employeeId": 102,
"employeeName": "Malcolm Barrett",
"jobTitle": "Exec. Vice President",
"employmentType": "Permanent",
"children": [
{
"employeeId": 103,
"employeeName": "Leah Flowers",
"jobTitle": "Parts Technician",
"employmentType": "Contract"
},
{
"employeeId": 104,
"employeeName": "Tammy Sutton",
"jobTitle": "Service Technician",
"employmentType": "Contract"
}
]
}]
}]
And
Code:
import React, { Component } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/dist/styles/ag-grid.css';
import 'ag-grid-community/dist/styles/ag-theme-balham.css';
import 'ag-grid-enterprise';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
columnDefs: [
{ field: "jobTitle" },
{ field: "employmentType" }
],
matchGridData: [],
autoGroupColumnDef: {
headerName: "Model",
field: "model",
cellRenderer: 'agGroupCellRenderer',
cellRendererParams: {
checkbox: true
}
},
// indicate if row is a group node
isServerSideGroup: function (dataItem) {
return dataItem.group;
},
// specify which group key to use
getServerSideGroupKey: function (dataItem) {
return dataItem.MatchGroup;
}
}
}
render() {
return (
<div
className="ag-theme-balham"
style={{
height: '500px',
width: '600px'
}}
>
<AgGridReact columnDefs={this.state.columnDefs} rowData={this.state.matchGridData} rowSelection="multiple"
onGridReady={params => this.gridApi = params.api} treeData={true} isServerSideGroup={this.state.isServerSideGroup}
getServerSideGroupKey={this.state.getServerSideGroupKey}
rowModelType='serverSide'
>
</AgGridReact>
</div>
);
}
EDIT:
I have prepared a small test repository on Github dedicated to this issue and in this GridExampleGrouping.js is being rendered but not GridExampleTreeServer.js
: https://github.com/HarvestAdmin/test-grid
getMatchingData = e => {
fetch('/Matching/ResultGrid.aspx/GetMatchingData', {
method: 'POST',
body: JSON.stringify({ userId: this.state.userId, executionId: this.state.matchOrExecutionId, outputType: this.state.outputType, action: this.state.action }),
headers: {
"Content-Type": "application/json; charset=UTF-8",
"Accept": "application/json, text/javascript, */*; q=0.01",
"X-Requested-With": "XMLHttpRequest"
}
})
.then(response => {
return response.json();
}, error => {
return error.json();
})
.then(jsonResponse => {
var result = JSON.parse(jsonResponse.d);
console.log(result);
this.setState({ matchGridData: result.SearchResults.Table });
});
}
}
Pic 1 : The output in browser :
Pic 2 : The console for above output:
Pic 3 : Even after applying a Trial license given by Ag-grid :
Upon contacting Ag-grid support team on Trial license, they recommended that I should use px instead of % to set height and width of the DIV element that contains Ag-grid element.
For some reason, giving discreet values rather than a percentage works.
In my react application, I am implementing a tree view structure to display the api response in more readable format. I am using tree view-react-bootstrap for that.
import React from 'react';
import ReactDOM from 'react-dom';
import TreeView from 'treeview-react-bootstrap'
class Example extends React.Component {
constructor(){
super();
// SET YOUR DATA
this.state = {
data: [
{
text: "John Peter",
nodes: [
{
text: "ID: 11111",
nodes: [
{
text: "VIN"
},
{
text: "Policy Effective Date"
},
{
text: "Policy Expiration Date"
},
{
text: "Vehicle Make"
},
{
text: "Vehicle Model"
}
]
},
{
text: "ID: 123456",
nodes: [
{
text: "VIN"
},
{
text: "Policy Effective Date"
},
{
text: "Policy Expiration Date"
},
{
text: "Vehicle Make"
},
{
text: "Vehicle Model"
}
]
}
]
},
{
text: "Scott Brown"
}
]
}
}
render(){
return (
// RENDER THE COMPONENT
<TreeView data={this.state.data} />
);
}
}
export default Example
I am using dummy data for now but this is the format that I want my data to be displayed. The api response I have is "array of objects" and it is only in one level JSON format.
Sample response -
[
{
"id": "1234",
"name": "John Scott",
"vin": "45",
"make": "Toyota",
"model": "Etios"
},
{
"id": "4567",
"name": "James Scott",
"vin": "67",
"make": "Hyundai",
"model": "Etios"
}
]
If you see the response, I would like my key value to be printed in a tree structure.
Is there a way I can render this response to accommodate with treeview-react-bootstrap?
I am not sure if I need to use map function inside my render method to iterate and display the data and how will it work along.Can someone let me know if I am doing it right or is there any better way of doing it. thanks in advance.
You can transform the response something like this. Have just added a dummy response. Please check the following code and let me know if this helps:
import React from "react";
import ReactDOM from "react-dom";
import TreeView from "treeview-react-bootstrap";
import axios from "axios";
class Example extends React.Component {
constructor() {
super();
// SET YOUR DATA
this.state = {
data: []
};
}
componentDidMount() {
axios
.get("https://www.mocky.io/v2/5bb85d723000005f00f93bb6")
.then(data => {
let transformedData = data.data.map(d => {
return {
text: d.text,
nodes: [
{
text: "dummy 1",
nodes: []
}
]
};
});
this.setState({ data: transformedData });
});
}
render() {
return (
// RENDER THE COMPONENT
<TreeView data={this.state.data} />
);
}
}
ReactDOM.render(<Example />, document.getElementById("app"));
You can also see it in action here: https://codesandbox.io/s/73ryny9ywq?autoresize=1&hidenavigation=1