React sending array of objects as form Data - javascript

I have currently created a nodejs api where a user can send data about their career. They can send text and an uploaded image.
The data is sent as follows and I have been successful with sending via postman
{
"employee": "user",
"positionHeld": [{
"yearPostitionHeld": "1995 - 2000",
"positionHeldTitle": "Manager"
},
{
"yearPostitionHeld": "2000 - Present",
"positionHeldTitle": "Assocaite Manager"
}],
"address": "Company Address",
"responsibilities": ["Responsibility 1", "Responsibility 2", "Responsibility 3"]
}
I have created a front end page with ReactJS so the user can send the data as above by filling in input fields.
I set the user input via the useState Hook
const [formData, setFormData] = useState({
companyName: "",
year: "",
positionHeld: [
{
positionHeldYear: "",
positionHeldTitle: "",
},
],
address: "",
responsibilities: "",
});
via an onChange function
const onChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
I also hanle the file upload
const [fileData, setFileData] = useState();
const handleFilechange = (e) => {
setFileData(e.target.files[0]);
};
I first tried to send the data as the formData but the file/image always appeared in req.body and not req.file and therefore I was unable to obtain the file path.
As a solution to the file issue I then create a new formData const completeFormData = new FormData(); and appending this
const year = formData.positionHeldYear;
const title = formData.positionHeldTitle;
setFormData({...formData, positionHeld: {positionHeldYear: year, positionHeldTitle: title}})
completeFormData.append("companyName", formData.companyName);
completeFormData.append("year", formData.year);
completeFormData.append("positionHeld", formData.positionHeld); // this needs to send the array of objects
completeFormData.append("address", formData.address);
completeFormData.append("responsibilities", formData.responsibilities);
completeFormData.append("image", fileData);
I am unsure if it is possible to send an array of objects as the new FormData such as the
"positionHeld": [{
"yearPostitionHeld": "1995 - 2000",
"positionHeldTitle": "Manager"
},
{
"yearPostitionHeld": "2000 - Present",
"positionHeldTitle": "Assocaite Manager"
}],
When creating the new form data as above when the req.body comes to the backend the positionHeld displays as positionHeld: [object, Object] when doing a console log
How is it best to manage sending data with nest array of object strings and image uploads?
I might have gone down the wrong route with this, so hoping someone can point me in the right direction to send body and a file to confirm as my object
{
"employee": "user",
"positionHeld": [{
"yearPostitionHeld": "1995 - 2000",
"positionHeldTitle": "Manager"
},
{
"yearPostitionHeld": "2000 - Present",
"positionHeldTitle": "Assocaite Manager"
}],
"address": "Company Address",
"responsibilities": ["Responsibility 1", "Responsibility 2", "Responsibility 3"]
}

One way of sending an array in FormData is to serialize it:
completeFormData.append("positionHeld", JSON.stringify(formData.positionHeld));
Then, on the backend, you can parse it with JSON.parse().

We did it with ReactJS(front) and ASP.Net core(back) So the best way to do it is using FormData, We use an object like below that contains an array of objects, each object includes an array of images too,
{
CommodityID:xxxxx,
TotalWeight:xxxx,
CostOfCommodity:xxxx,
Prerequisites:[{
ProductId: xxxx,
DeliveryWeight: xxxxx,
ReleasedImagesUrl: [
multiple images file
]
},{
ProductId: xxxx,
DeliveryWeight: xxxxx,
ReleasedImagesUrl: [
multiple images file
]
}]
}
Actually, we send each item of the array separately like Prerequisites[0].DeliveryWeight and this is the point (pairs of name/value). please pay attention to the letters that in our case first characters of items were capital (this is important too)
const formData = new FormData();
formData.append("CommodityID", this.state.commodityId);
formData.append("TotalWeight", this.state.totalWeight);
formData.append("CostOfCommodity",this.state.costOfCommodity);
for (let i = 0; i < this.state.prerequisitesListTemp.length; i++) {
formData.append(
`Prerequisites[${i}].ProductId`,
this.state.prerequisitesListTemp[i].productId
);
formData.append(
`Prerequisites[${i}].DeliveryWeight`,
this.state.prerequisitesListTemp[i].deliveryWeight
);
for (
let j = 0;j < this.state.prerequisitesListTemp[i].releasedImagesUrl.length;j++
) {
formData.append(
`Prerequisites[${i}].ReleasedImagesUrl`,
this.state.prerequisitesListTemp[i].releasedImagesUrl[j]
);
}
}

Related

How can I format an excel file with empty rows to have nested arrays and match a JSON object that I need to render?

I am facing an issue with an excel file. I receive some data from the DB and the user should be able to replace that data with a spreadsheet that looks like this:
This is how the data comes from the DB and how the excel file should be finally formatted:
"employers": [{
"id": "4147199311345513",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}, {
"id": "3763171269270198",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}]
So I need to take that spreadsheet and format it to look like that JSON above. All of this with Javascript/React.
This is what I have so far to format my excel file and render it:
const [excelData, setExcelData] = useState({ rows: [], fileName: "" });
const fileHandler = (event) => {
let fileObj = event.target.files[0];
ExcelRenderer(fileObj, (err, resp) => {
if (err) {
console.log(err);
} else {
let newRows = [];
let shiftRows = [];
console.log(resp.rows);
resp.rows.slice(1).map((row, index) => {
if (row && row !== "undefined") {
return newRows.push({
key: index,
employer: {
name: row[0],
description: row[1],
employerUrl: row[2],
employerUrlText: row[3],
shifts: shiftRows.push({ shift: row[2] }),
},
});
}
return false;
});
setExcelData({ rows: newRows, fileName: fileObj.name });
}
});
};
That console.log above (console.log(resp.rows)) returns this:
Where the first row are the headers of the excel file.
And the code above ends up like this and it should be exactly as the JSON I mentioned:
rows: [
{
key: 0,
employer: {
name: 'AT&T',
description: 'AT&T is a world premier employer with a bunch of stuff here and there.',
shifts: 1
}
},
{
key: 1,
employer: {
shifts: 2
}
},
{
key: 2,
employer: {
shifts: 3
}
},
{
key: 3,
employer: {
shifts: 4
}
},
{
key: 4,
employer: {
name: 'Verizon',
description: 'Verizon is a world premier employer with a bunch of stuff here and there.',
shifts: 5
}
},
{
key: 5,
employer: {
shifts: 6
}
},
{
key: 6,
employer: {
shifts: 7
}
},
{
key: 7,
employer: {
shifts: 8
}
}
],
fileName: 'EmployerChats.xlsx',
false: {
rows: [
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/0/link.png',
description: 'This is some text'
},
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/1/link.png',
description: 'This is some text'
}
]
},
I am using this plugin to help me render the excel file: https://www.npmjs.com/package/react-excel-renderer
Any ideas on what can I do to make format the spreadsheet data as the JSON?
Please notice those empty rows.
For example every time there is a new employer name, that's a new row or item in the array, then all of the columns and rows below and after Shift Name is a new nested array of objects. Hence, this file contains an array with a length of 2 and then it contains another array of items when it hits the Shift Name column.
Is it clear?
1st of all - you don't need to follow 'original', class based setState. In FC you can just use two separate useState.
const [rows, setRows] = useState([]);
const [fileName, setFileName] = useState("");
Data conversion
I know that you need a bit different workflow, but this can be usefull (common point - data structure), too - as conversion guide, read on.
You don't need to use ExcelRenderer to operate on data from db and render it as sheet. Converted data can be exported to file later.
You can just create array of array (aoa) that follows expected view (rows = array of row cells array). To do this you need very easy algorithm:
let newData = []
map over emplyers, for each (emp):
set flag let first = true;
map over shifts, for each (shift):
if( first ) { newData.push( [emp.name, emp.descr, shift.name, shift.timezone...]); first = false;
} else newData.push( [null, null, shift.name, shift.timezone...]);
setRows( newData );
Rendering
<OutTable/> operates on data and colums props - structures similar to internal state. 'datais ourrows, we only needcolumns` prop, just another state value:
const [columns, setColumns] = useState([
{ name: "Employer name", key: 0 },
{ name: "Employer description", key: 1 },
{ name: "Shift name", key: 2 },
// ...
]);
and finally we can render it
return (
<OutTable data={rows] columns />
Later
User can operate on sheet view - f.e. insert rows using setRows() or download this as file (XLSX.writeFile()) after simple conversion:
var ws = XLSX.utils.aoa_to_sheet( columns.concat( rows ) );
There is a lot of utils you can use for conversions - see samples.
Back to your needs
We have data loaded from db, data in aoa form, rendered as sheet. I don't fully understand format you need, but for your db format conversion is simple (opposite to above) - you can follow it and adjust to your needs.
let newEmployers = [];
let empCounter = -1;
// itarate on rows, on each (`row`):
rows.map( (row) => {
// new employer
if( row[0] ) {
newEmployers.push( {
// id should be here
"employerName": row[0],
"employerDescription": row[1],
"shifts": [
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
]
} );
empCounter ++;
} else {
// new shift for current employer
newEmployers[empCounter].shifts.push(
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
);
}
});
// newEmployers can be sent to backend (as json) to update DB

Unable to output useState to imported chart

I have a simple form where i will add a task and add the amount of minutes that task has taken, i am having trouble trying to get the chart which i have imported from 'Recharts' to see the state, it looks like the state is returning an empty array and my chart is not seeing the data.
The Recharts chart takes an array with an object inside with two values, example shown below
const data = [
{ name: "Group A", data: 400 },
{ name: "Group B", data: 300 },
{ name: "Group C", data: 300 },
{ name: "Group D", data: 200 },
{ name: "Group E", data: 278 },
{ name: "Test Data", data: 189 }
];
However after i have moved my state as props to the component and mapped the result to take the same names as input the charts is not displaying anything
(my mapped props)
const activityData = [
...props.pieData.map(el => ({
name: el.title,
data: el.amount
}))
];
I have put a simplified version on codesandbox to make it a little bit easier if anyone wants to see the output i'm getting
https://codesandbox.io/s/hidden-dew-676xc
Found the issue as soon as i posted this, the 'data' value which i had mapped in my props was getting outputted as a string, when the object was expecting a number

issue in fatching array of object through http request in patch value method

I am creating a mean stack project i want to display array of objects values in a edit form so the problem is when i recieve data from all tables from backend it will work fine and show data in forms but when any of table table data is not present http request patch value method dosnt work and it show a empty form
json structure
"data": {
"id": 7,
"location": "Bikaner",
"empId": "ct141",
"firstName": "mahendra",
"lastName": "chauhan",
"dateOfBirth": "1984-09-11",
"gender": "male",
"emp_Edus": [
{
"id": 2,
"university": "MGSU",
"degree": "bca",
"eduStart": "2012-06-06",
"eduEnd": "2015-06-02",
],
"emp_Pre_Job_Details": [
{
"id": 2,
"company": "I tech",
"designation": "Manager",
"preJobStart": "2016-08-11",
"preJobEnd": "2020-02-12",
}
],
"emp_Current_JobSta": [
{
"id": 2,
"jobStatus": "Contractual",
"start": "2020-02-02",
"end": "2023-02-02",
"jobTitle": "Manager",
"accessReq": "1",
"supervisor": "",
}
]
}
patch value request
loadEmpData(id)
{
const formData = new FormData();
formData.append("id", id);
console.log("formData" + formData);
this.cs.empprofile(id).subscribe(response => {
if (response.status == 1) {
this.empData = response.data;
this.empEdusData = response.data.emp_Edus;
this.empcurrentJob = response.data.emp_Current_JobSta;
this.empPreJobData= response.data.emp_Pre_Job_Details;
this.editEmpForm.patchValue({
photograph: response.data.photograph,
empId: response.data.empId,
firstName: response.data.firstName,
lastName:response.data.lastName,
gender: response.data.gender,
university: response.data.emp_Edus[0].university,
degree: response.data.emp_Edus[0].degree,
eduStart: response.data.emp_Edus[0].eduStart,
eduEnd: response.data.emp_Edus[0].eduEnd,
company: response.data.emp_Pre_Job_Details[0].company,
designation: response.data.emp_Pre_Job_Details[0].designation,
preJobStart:response.data.emp_Pre_Job_Details[0].preJobStart,
preJobEnd: response.data.emp_Pre_Job_Details[0].preJobEnd,
jobTitle: response.data.emp_Current_JobSta[0].jobTitle,
start: response.data.emp_Current_JobSta[0].start,
end: response.data.emp_Current_JobSta[0].end,
jobStatus: response.data.emp_Current_JobSta[0].jobStatus,
supervisor : response.data.emp_Current_JobSta[0].supervisor
});
In your case you are getting data from backend, you can verify it in the network it will be there.
In the patch you are trying to retrieve table data using 0 index as response.data.emp_Edus[0], but if the response doesn't have data in the 0'th index then it will throw an error.
what you need to do is! before retrieving particular table data, just verify whether emp_Edus is not null, and length > 0, then retrieve it. Same validation you need to do for other two tables.
try in the below way!
let myForm = {};
myForm = {
photograph: response.data.photograph,
empId: response.data.empId,
firstName: response.data.firstName,
lastName:response.data.lastName,
gender: response.data.gender
};
if(response.data.emp_Edus != null && response.data.emp_Edus.length>0){
myForm.university= response.data.emp_Edus[0].university;
myForm.degree= response.data.emp_Edus[0].degree;
myForm.eduStart= response.data.emp_Edus[0].eduStart;
myForm.eduEnd= response.data.emp_Edus[0].eduEnd;
}
if(response.data.emp_Pre_Job_Details != null && response.data.emp_Pre_Job_Details.length>0){
myForm.company= response.data.emp_Pre_Job_Details[0].company;
myForm.designation= response.data.emp_Pre_Job_Details[0].designation;
myForm.preJobStart=response.data.emp_Pre_Job_Details[0].preJobStart;
myForm.preJobEnd= response.data.emp_Pre_Job_Details[0].preJobEnd;
}
if(response.data.emp_Current_JobSta != null && response.data.emp_Current_JobSta.length>0){
myForm.jobTitle= response.data.emp_Current_JobSta[0].jobTitle;
myForm.start= response.data.emp_Current_JobSta[0].start;
myForm.end= response.data.emp_Current_JobSta[0].end;
myForm.jobStatus= response.data.emp_Current_JobSta[0].jobStatus;
myForm.supervisor = response.data.emp_Current_JobSta[0].supervisor;
}
});
this.editEmpForm.patchValue(myForm);

React/Redux Handling Two-Way Data

I'm struggling to properly organize my Redux Store and my React components to properly deal with two-way nested data.
Suppose I have a post model and a user model. Let's take an abstracted example:
const user = {
"id": "1",
"name": "user 1",
"posts": [...] // list of post objects
}
const post = {
"id": "1",
"title": "post 1",
"user": user
}
The problem is that I cannot load this data like this because it will cause an infinite recursion error. I have to omit either the posts from the user or omit the user from the posts.
Here's what I ideally need:
I need to have a single post page that displays the post user with all his info (id, name) and the user's list of posts with the post info (id, title) in the same screen all at once.
I use normalizr to normalize the data.
How would I go about loading the data?
As per Redux docs (https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape) you should avoid nesting objects.
The solution here would be to treat the data like it is a database. That means that you should store ids instead of objects.
In your example:
const user = {
"id": "1",
"name": "user 1",
"posts": ["1", "2", ...] // list of post objects IDs
}
const post = {
"id": "1",
"title": "post 1",
"userId": "1"
}
Normally you would only save post_ids in the user, and user_id in the post. normalizer schemas can be configured to deal with those relations.
What is the incentive of adding the user key in post? Having shared data within two related data structures is redundant. The only data you should have in post is the relevant data and the minimum amount of information you need to properly associate the user with his/her posts. I would imagine you would want to have the string name of the user in post, or an id number of the user inside each post object
const user = {
"id": "1",
"name": "user 1",
"posts": [...] // list of post objects
}
const post = {
"id": "1",
"title": "post 1",
"user": "user 1"
}
EDIT:
From your comment, I would make an array of all users. But with a post key that is only the ids of posts that are associated with that user. And another array of only posts. As before, have an identifier to correlate the two. After that, parse your frontend on an as needed basis.
const users = [
{ name: 'andrew', id: 10, postIds: [1,3,23,30]},
// ...more users
]
const posts = [
{ name: 'a post', id: 23, userId: 10 }
{ name: 'another post', id: 3, userId: 10 }
{ name: 'a third post', id: 2, userId: 3 }
// ...more posts
]
Technically, userId is optional, but it can be a nice-to-have to be able to identify a user when inspecting individual posts
EDIT:
Wow, I just scrolled down and saw nordus has the exact same proposal, before me. While it's nice to see we're on the same page, make sure he/she gets credit if you like the idea ;).

Elastic-search: How can i map json data having dynamic number of fields

I'm working on a application for that i need to map json data for storing in Elasticsearch. The number of fields in json data is dynamic.then how can i do mapping for this scenario.
mapping Snippet
var fs = uploadedFiles[0].fd;
var xlsxRows = require('xlsx-rows');
var rows = xlsxRows(fs);
console.log(rows);
client.indices.putMapping({
"index": "testindex",
"type": "testtype",
"body": {
"testtype": {
"properties": {
"Field 1": {
"type": "string"
},
"Field 3": {
"type": "string"
},
"Field 2":{
"type":"string"
} .....
//Don't know how many fields are in json object.
}
}
}
}, function (err, response) {
if(err){
console.log("error");
}
console.log("REAPONCE")
console.log(response);
});
This is my sample json data
//result of rows
[
{ Name: 'paranthn', Age: '43', Address: 'trichy' },
{ Name: 'Arthick', Age: '23', Address: 'trichy' },
{ Name: 'vel', Age: '24', Address: 'trichy' } //property fields
]
NOTE: The number of property fields are dynamic.
ES will always make its best efforts to infer the correct type for the fields in your documents that have no mapping defined and set sensible defaults.
A mapping is only necessary if you need to apply some special treatment to certain fields other than the set defaults, like specifying an indexing analyzer, a search analyzer, whether string fields need to be analyzed or not, specifying sub-fields with a different analyzer, etc.
If you don't need any of this, then you can let ES infer the mapping of your documents.

Categories