calculating total values from a JSON data in jsreport using JavaScript - javascript

I am new to jsreport. I have the following data and trying to calculate total salaries,
{
"company": [{
"Remy": {
"age": 32,
"employer": "emp1",
"salary": 20000
},
"Piet": {
"age": 35,
"employer": "emp2",
"salary": 50000
},
"Thando": {
"age": 32,
"employer": "emp3",
"salary": 20000
},
"Greg": {
"age": 33,
"employer": "emp4",
"salary": 70000
}
}]
}
I tried using the following code but I keep getting an error that company.forEach is not a function
function total(company) {
var sum = 0
company.forEach(function (i) {
sum += i.salary
})
return sum
}
I am getting the following error.
Report "Issue" render failed.
Error when evaluating engine handlebars for template anonymous
(because) "total" helper call failed
(because) company.forEach is not a function
(sandbox.js line 14:13)
12 | function total(company) {
13 | var sum = 0
> 14 | company.forEach(function (i) {
| ^
15 | sum += i.salary
16 | })
17 | return sum

This is a good time to use reduce:
const data = {
"company": [{
"Remy": {
"age": 32,
"employer": "emp1",
"salary": 20000
},
"Piet": {
"age": 35,
"employer": "emp2",
"salary": 50000
},
"Thando": {
"age": 32,
"employer": "emp3",
"salary": 20000
},
"Greg": {
"age": 33,
"employer": "emp4",
"salary": 70000
}
}]
}
const salaries = Object.values(data.company[0]).reduce((total, emp) => {
total = emp.salary + total;
return total;
}, 0)
console.log(salaries)
Have a look at the array reduce method for details, but whenever you hear 'calculating' on a list of items reduce isn't a bad option to have a look at to try to solve the issue

Related

How to write a javascript that calculates total sum per customer from json [duplicate]

This question already has answers here:
Applying group by and sum on array of objects in javascript
(3 answers)
Closed 4 months ago.
I'm still a beginner with javascript and node and I have a problem.
I have file which contains payment api and I need to calculate the total sum each customer owes.
File looks like this:
[
{
"paymentId": "fc3a34e6-885e-4baf-8c67-3eeb4c3cd945",
"customer": "Customer1",
"amountInEur": 97
},
{
"paymentId": "00320009-d2d2-43de-8ac3-a82bad36f718",
"customer": "Customer2",
"amountInEur": 51
},
{
"paymentId": "cd44a829-e915-4f85-95bf-fe82dcd5df15",
"customer": "Customer3",
"amountInEur": 57
},
{
"paymentId": "59c2405a-7fc2-435e-a9b1-3065f783869c",
"customer": "Customer2",
"amountInEur": 64
},
...and the list goes on. Customer may appear on the list several times. So I need to calculate how much each customer ows.
This is what I have so far
const fs = require("fs");
try {
const jsonString = fs.readFileSync("./logs.json", "utf8");
const data = JSON.parse(jsonString);
console.log(data);
} catch (err) {
console.log(err);
}
So I can get the data from the json file and I can even count the total amount, but how do I calculate total amount for each customer?
You can make use of the .reduce() to transform the array that you receive from running JSON.parse() into an object, where keys are customer string and values - how much do they owe, like so:
const array = [
{
"paymentId": "fc3a34e6-885e-4baf-8c67-3eeb4c3cd945",
"customer": "Customer1",
"amountInEur": 97
},
{
"paymentId": "00320009-d2d2-43de-8ac3-a82bad36f718",
"customer": "Customer2",
"amountInEur": 51
},
{
"paymentId": "cd44a829-e915-4f85-95bf-fe82dcd5df15",
"customer": "Customer3",
"amountInEur": 57
},
{
"paymentId": "59c2405a-7fc2-435e-a9b1-3065f783869c",
"customer": "Customer2",
"amountInEur": 64
},
];
const amountsByEachCustomer = array.reduce((amountsByEachCustomer, item) => {
// Initialize the amount to 0 when encounter customer for the first time in the loop
if (typeof amountsByEachCustomer[item.customer] === "undefined") {
amountsByEachCustomer[item.customer] = 0;
}
amountsByEachCustomer[item.customer] += item.amountInEur;
return amountsByEachCustomer;
}, {});
console.log(amountsByEachCustomer); // { Customer1: 97, Customer2: 115, Customer3: 57 }

facing an issue while getting the output of a DOM view

public total = []
public topScore: number
public studentStatus
public studentData: any[] = [
{
"name": "rajiv",
"marks": {
"Maths": 18,
"English": 21,
"Science": 45
},
"rollNumber": "KV2017-5A2"
},
{
"name": "abhishek",
"marks": {
"Maths": 43,
"English": 30,
"Science": 37
},
"rollNumber": "KV2017-5A1"
},
{
"name": "zoya",
"marks": {
"Maths": 42,
"English": 31,
"Science": 50
},
"rollNumber": "KV2017-5A3"
}];
this is my console output for total array
(3) [110, 84, 123]
totalScore(){
this.studentData.forEach(a => {
let res = a.marks.English + a.marks.Maths + a.marks.Science
this.total.push(res)
console.log(this.total)
});
}
this is my console output for subject wise marks array of a student and status if any subject < 20 "fail" else "pass"
**details.component.ts:68 (3) [43, 30, 37]
details.component.ts:72 Pass
details.component.ts:68 (3) [18, 21, 45]
details.component.ts:72 Fail
details.component.ts:68 (3) [42, 31, 50]
details.component.ts:72 Pass**
status(){
this.studentData.forEach(a => {
let sample = a.marks
let values = [];
for (var key in sample) {
values.push(sample[key]);
};
console.log(values);
this.studentStatus = values.find(b => b < 20) ? "Fail" : "Pass" console.log(this.studentStatus)
})
}
this is my console output for topScore value
details.component.ts:79 123
topper(){
this.topScore=Math.max(...this.total) console.log(this.topScore)
}
Here all the console outputs are showing correct but in the DOM View all the turns green color and all the status value is showing "pass". How to rectify this
When you inspect the DOM, do you see both?
<tr class="green">...</tr>
<tr class="green red">...</tr>
You aren't saying who has the top score, only that there is one. You need to distinguish which student has top score. Also, if you see both red and green in the class, it may have to do with how you have you css styles set up and which one will take precedence depending on if you have the .green class or the .red class listed first, that is if they both have the same css selector depth.
So. Either add a property on the student having topScore = true or false, or have another class that states what the top score is and who it is that has earned top score. From here, you can do something like
<tr *ngFor="let data of studentData" [ngClass]="{'green':topScore.name === data.name ,'red': data.marks.Maths < 20}">

unable to push and append data to the state using React js

here i state with data
state = {
Response: [
{
"id": "15071",
"name": "John",
"salary": "53",
"age": "23",
"department": "admin"
},
{
"id": "15072",
"name": "maxr",
"salary": "53",
"age": "23",
"department": "admin"
},
{
"id": "15073",
"name": "Josef",
"salary": "53",
"age": "23",
"department": "admin"
},
{
"id": "15074",
"name": "Ye",
"salary": "53",
"age": "23",
"department": "admin"
}
]
i am displaying these records in the table. In table u will see 10 records and there will be a button on top of table so if append button is pressed then 10 records has to be added on every button press and the data has to be same but it has to be appended using the below logic i am trying to set the state by pushing 10 records and trying to append it for ex if i have 1,2,3,4,5,6,7,8,9,10 if i press append 1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10 has to be apeended
appendEmployees() {
var reLoadCount = 1;
for (let i = 0; i < 10; i++) {
const myObj = {
id: 0,
name: '',
salary: 0,
department: ''
};
myObj.id = +this.setState.employee[i].id + (reLoadCount * 10);
myObj.name = this.setState.employee[i].name;
myObj.salary = this.setState.employee[i].salary;
myObj.department = this.setState.employee[i].department;
this.setState.employee.push(myObj);
}
reLoadCount++;
}
am i doing some thing wrong here
If I get this right you're trying to add 10 duplicates of the objects in the this.state.employee array, the only difference between these new objects and the existing ones is their id.
If that is the case, here is how you can do that:
appendEmployees() {
this.setState(prevState => {
// Get the biggest ID number.
const maxId = Math.max(...prevState.employee.map(e => parseInt(e.id)));
// create 10 new employees copies of the first 10.
const newEmployees = prevState.employee.slice(0, 10).map((e, i) => ({
...e,
id: (maxId + i + 1)
}));
// return/update the state with a new array for "employee" that is a concatenation of the old array and the array of the 10 new ones.
return {
employee: [...prevState.employee, ...newEmployees]
}
});
}
I've added some comments to the example to explain what it does.
The important thing is this.setState which is the function used to update the state, here, I've used it with a function as the first parameter (it works with objects as well), I've did that because it is the preferred way of generating a new state that is derived from the old state.

JavaScript Multidimensional Array - Object Linking

I am working with javascript multidimensional array.
Here is the scenario:-
I have a educational institution where user can take classes from any subject. Subjects are not fixed it could be vary. Now there is exam day so suppose there is PHP Lang faculty who will enter his subject name then student name and then marks. If student is enrolled himself for more then 1 subject so its marks will listed in same row.
for example Mr. Anand has enrolled for PHP and HTML and Mr. Deep has enrolled himself for Php only.
Additionally I also want to show minimum and maximum marks as well.
So on result day result card will
Name\Subject | PHP | HTML | Java
--------------------------------------
Anand | 80 | 60 | --
Deep | 70 | -- | --
Sachin | 55 | 56 | 45
so on ... | -- | -- | 80
--------------------------------------
Min Marks | 70 | 56 | 45
Max Mark | 80 | 60 | 80
I have created a multidimensional array but unable to reproduce code as per visual. I think I am doing something wrong.
Below is the code which I have created as of now :-
var data = [
["HTML", [{
"name": "Anand",
"marks": 90
}, {
"name": "Deep",
"marks": 79
}, {
"name": "Raman",
"marks": 34
}]],
["Php", [{
"name": "Anand",
"marks": 90
}, {
"name": "Ekam",
"marks": 40
}]]
]
for (var i = 0; i < data.length; i++) {
document.write("<h2> " + data[i][0] + " </h2>");
var secondLevelData = data[i][1],
secondLen = secondLevelData.length;
for (var j = 0; j < secondLen; j++) {
document.write(secondLevelData[j].name + " -- " + secondLevelData[j].marks + " <br/>");
}
}
Please help me to get the desired result. I am also working on it.
Thanks for your help!!
By changing the JSON we can achieve this. Also added jQuery and underscore libraries for DOM and array manipulations
JS Fiddle Link : https://jsfiddle.net/8Lb7x01u/3/
var data = [
{
"name": "Anand",
"score": [
{
"subject": "HTML",
"marks": 90
},
{
"subject": "Php",
"marks": 90
}
]
},
{
"name": "Deep",
"score": [
{
"subject": "HTML",
"marks": 79
}
]
},
{
"name": "Raman",
"score": [
{
"subject": "HTML",
"marks": 34
}
]
},
{
"name": "Ekam",
"score": [
{
"subject": "Php",
"marks": 40
}
]
}
];
var allScores = _.pluck(data,"score");
var allSubjects = _.groupBy(_.flatten(allScores),"subject");
var allStudents = _.pluck(data,"name");
var headerRow = $("<tr></tr>");
$("<th></th>").html("Name\\Subject").appendTo(headerRow);
for(var subject in allSubjects){
$("<th></th>").html(subject).appendTo(headerRow);
}
headerRow.appendTo(".scoreCard");
for(var i=0;i<allScores.length;i++){
var individualScores = _.groupBy(allScores[i],"subject");
var tr = $("<tr></tr>");
$("<td></td>").html(allStudents[i]).appendTo(tr);
for(var subject in allSubjects)
{
if(individualScores[subject]){
$("<td></td>").html(individualScores[subject][0].marks).appendTo(tr);
}else
{
$("<td></td>").html("...").appendTo(tr);
}
}
tr.appendTo(".scoreCard tbody")
}
renderMaxMin("max");
renderMaxMin("min");
function renderMaxMin(param){
var footerRow = $("<tr></tr>");
$("<td></td>").html(param+" marks").appendTo(footerRow);
for(var subject in allSubjects){
var marks = _.pluck(allSubjects[subject],"marks");
var value =(param === "max") ? _.max(marks) : _.min(marks);
$("<td></td>").html(value).appendTo(footerRow);
}
footerRow.appendTo(".scoreCard tfoot")
}
You are not using the markup in the right manner. You should form the correct markup first, in this case it would be tables.
Also, the way you are storing data could be improved by using associative arrays. It will help you to manage it and use it better as the size of data grows. Here is how you can do that :
var data = [{'HTML' :
[{"name":"Anand","marks":90,
{"name":"Deep","marks": 79},
{"name":"Raman","marks": 34}]
}],
{'PHP' :
[{"name":"Anand","marks": 90},
{"name":"Ekam","marks": 40}]
}]]

How to calculate the average value in a json data in javascript or underscore?

I know that underscore.js have max() and min() function in Collection Functions, but why does it not have avg() function?
I want to calculate the AvgValue in Math in these three student and the avgvalue which is less than 0 must be excluded. I can do it use for or foreach, but how to use underscore function or other js function like map or grep?
The json data is like this:
{ "Data": [
{ "StudentName": "SA",
"Math": {"AvgValue": 80, "MaxValue": 99, "MinValue": 60 },
"English": {"AvgValue": 76, "MaxValue": 80, "MinValue": 55 } },
{ "StudentName": "SB",
"Math": {"AvgValue": 75, "MaxValue": 88, "MinValue": 34 },
"English": {"AvgValue":98, "MaxValue": 100, "MinValue": 90 } },
{ "StudentName": "SC",
"Math": {"AvgValue": -1, "MaxValue": -1, "MinValue": -1 },
"English": {"AvgValue":-1, "MaxValue": -1, "MinValue": -1 } }
], "Total": 3, "AggregateResults": null, "Errors": null }
why does it not have avg() function?
A Javascript library author has to weigh utility of a feature against the cost it imposes on the size of the library, particularly if the library has a very general purpose.
The goal of Underscore is stated as:
It’s the answer to the question: “If I sit down in front of a blank HTML page, and want to start being productive immediately, what do I need?”
I think average is probably too easy to write and too infrequently needed to fit that description.
function mathAverage() {
function mathScores() {
return data['Data'].map(function (student) {
return student['Math']['AvgValue'];
});
}
function add(x, y) { return x + y; }
function sum(xs) { return _.reduce(xs, add); }
function average(xs) { return sum(xs) / xs.length;}
function nonnegative(x) { return x >= 0; }
return average(mathScores().filter(nonnegative));
}
You can get the array you want with the grades like this
var grades = data.Data
.map( function (s) { return s.Math.AvgValue })
.filter (function (n) {return n > 0})
// -> [ 80, 75 ]
Then use underscore or a simple for loop to calculate the average

Categories