facing an issue while getting the output of a DOM view - javascript

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}">

Related

calculating total values from a JSON data in jsreport using 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

How to get this output from JSON in javascipt ny comparing student_id from mark_details and students_detail?

JSON Object:
{
"students_detail": [
{
"student_id": 1,
"name": "abc",
"roll_number": 10
},
{
"student_id": 2,
"name": "pqr",
"roll_number": 12
}
],
"subject_details": [
{
"subject_id": 1,
"subject_name": "math"
},
{
"subject_id": 2,
"subject_name": "english"
}
],
"exam_details": [
{
"exam_id": 1,
"exam_name": "Prelim"
}
],
"mark_details": [
{
"id": 1,
"exam_id": 1,
"subject_id": 1,
"student_id": 1,
"mark": 51
},
{
"id": 2,
"exam_id": 1,
"subject_id": 2,
"student_id": 2,
"mark": 61
}
]
}
Ouptut:
{
"student_mark_details": [
{
"abc": {
"roll_number": 10,
"Prelim": [
{
"subject_name": "math",
"mark": 51
}
]
},
"pqr": {
"roll_number": 12,
"Prelim": [
{
"subject_name": "english",
"mark": 61
}
]
}
}
]
}
i tried using loops and accesing student_id in both object and comparing them but code gets too messy and complex,is there any way i can use map() or filter() in this or any other method.
i have no idea where to start,my brain is fried i know im asking lot but help will be appreciated (any link/source where i can learn this is fine too)
Your output object really has a weird format: student_mark_details is an array of size 1 that contains an object that has all your students in it. Anyway, this should give you what you need. It is a format that you find often because it is a system with primary key and secondary key used a lot in databases.
The key to manage that is to start with what is at the core of what you are looking for (here, you want to describe students, so you should start from there), and then navigate the informations you need by using the primary/secondary keys. In JS, you can use the find() function in the case where one secondary key can be linked only to one primary key (ex: one mark is linked to one exam), and the filter() function when a secondary key can be linked to multiple secondary keys (ex: a student is linked to many grades).
I am not sure if this is 100% what you need because there are maybe some rules that are not shown in your example, but it solves the problem you submitted here. You might have to test it and change it depending of those rules. I don't know what your level is so I commented a lot
const data = {
"students_detail": [
{
"student_id": 1,
"name": "abc",
"roll_number": 10
},
{
"student_id": 2,
"name": "pqr",
"roll_number": 12
}
],
"subject_details": [
{
"subject_id": 1,
"subject_name": "math"
},
{
"subject_id": 2,
"subject_name": "english"
}
],
"exam_details": [
{
"exam_id": 1,
"exam_name": "Prelim"
}
],
"mark_details": [
{
"id": 1,
"exam_id": 1,
"subject_id": 1,
"student_id": 1,
"mark": 51
},
{
"id": 2,
"exam_id": 1,
"subject_id": 2,
"student_id": 2,
"mark": 61
}
]
}
function format(data) {
const output = {
"student_mark_details": [{}]
};
//I start by looping over the students_detail because in the output we want a sumary by student
data.students_detail.forEach(student => {
//Initialization of an object for a particular student
const individualStudentOutput = {}
const studentId = student.student_id;
const studentName = student.name;
//The rollNumber is easy to get
individualStudentOutput.roll_number = student.roll_number;
//We then want to find the exams that are linked to our student. We do not have that link directly, but we know that our student is linked to some marks
//Finds all the marks that correspond to the student
const studentMarkDetails = data.mark_details.filter(mark => mark.id === studentId);
studentMarkDetails.forEach(individualMark => {
//Finds the exam that corresponds to our mark
const examDetail = data.exam_details.find(exam => individualMark.exam_id === exam.exam_id);
//Finds the subject that corresponds to our mark
const subjectDetail = data.subject_details.find(subject => individualMark.subject_id === subject.subject_id);
//We then create a grade that we will add to our exam
const grade = {
subject_name: subjectDetail.subject_name,
mark: individualMark.mark
}
//We then want to add our grade to our exam, but we don't know if our output has already have an array to represent our exam
//So in the case where it does not exist, we create one
if (!individualStudentOutput[examDetail.exam_name]) {
individualStudentOutput[examDetail.exam_name] = [];
}
//We then add our grade to the exam
individualStudentOutput[examDetail.exam_name].push(grade);
});
//Now that we have finished our individual output for a student, we add it to our object
output.student_mark_details[0][studentName] = individualStudentOutput;
})
return output;
}
console.log(JSON.stringify(format(data)))

Taking JSON data, grouping by a property, and aggregating using multiple aggregation functions

Here is a sample of JSON data of fruit weights and prices:
let fruitData = [{"fruit":"apple","weight":12,"price":1.80},
{"fruit":"apple","weight":15,"price":2.00},
{"fruit":"apple","weight":10,"price":1.60},
{"fruit":"banana","weight":22,"price":3.00},
{"fruit":"banana","weight":24,"price":3.20}]
If I want to group by the "fruit" property and return mean "weight" and "price" values for each fruit, what do I do to achieve this? The end result would be something like:
aggFruitData = [{"fruit":"apple","weight":12.3333,"price":1.8},
{"fruit":"banana","weight":23,"price":3.1}]
The big hope is that the data can still be in an easy to manipulate form like JSON following the transformation. I know that SQL provides a groupby method, but I'm wondering if that is more efficient or if using native JS is more effective. Ideally, this could be something that could be scaled up, such as including another property to group by (maybe like month sold/month price was recorded). I'm open to using either vanilla JS methods or a library/framework meant to parse in this way— I just want efficiency with the project's execution
Using vanilla js:
let fruitData = [{
"fruit": "apple",
"weight": 12,
"price": 1.80
},
{
"fruit": "apple",
"weight": 15,
"price": 2.00
},
{
"fruit": "apple",
"weight": 10,
"price": 1.60
},
{
"fruit": "banana",
"weight": 22,
"price": 3.00
},
{
"fruit": "banana",
"weight": 24,
"price": 3.20
}
];
const aggregated = Object.values(fruitData.reduce((current, item) => {
if (!current[item.fruit]) {
current[item.fruit] = {
...item,
count: 1
};
} else {
const i = current[item.fruit];
i.weight = (i.weight * i.count + item.weight) / (i.count + 1);
i.price = (i.price * i.count + item.price) / (i.count + 1);
i.count++;
}
return current;
}, {})).map(({
fruit,
weight,
price
}) => ({
fruit,
weight,
price
}));
console.log(aggregated);
// [ { fruit: 'apple', weight: 12.333333333333334, price: 1.8 },
// { fruit: 'banana', weight: 23, price: 3.1 } ]
You could also use the lodash library (_.groupBy etc) functions for this. Note that the last .map is to strip out the count field only, but you may actually find it useful to have that!

Convert object with nested objects into array of objects,re- groupped by inner object's keys

I have the Following JavaScript Object JSON1
{
"1": {
"Average": 32.31,
"Count": 19,
"Sum": 32.6,
"Color": "red"
},
"2": {
"Average": 32.72,
"Count": 18,
"Sum": 32.96,
"Color": "blue"
},
"3": {
"Average": 31.4,
"Count": 18,
"Sum": 31.48,
"Color": "green"
}
}
and I want to convert into the following format using javascript ES6 methods. JSON2
[{
"title": "Average",
"val1": 32.31,
"val2": 32.72,
"val3": 31.4
}, {
"title": "Count",
"val1": 19,
"val2": 18,
"val3": 18
}, {
"title": "Sum",
"val1": 32.6,
"val2": 32.96,
"val3": 31.48
}, {
"title": "Color",
"val1": "red",
"val2": "blue",
"val3": "green"
}]
Object.keys(json1).forEach((item, index) => {
let statsList = [];
Object.keys(json1[item]).forEach(objItem => {
statsList.push({
title: objItem,
val1: boxObj[1][objItem],
val2: boxObj[2][objItem],
val3: boxObj[3][objItem]
});
});
console.log(statsList)
});
var json1 = {
"1": {
"Average": 32.31,
"Count": 19,
"Sum": 32.6,
"Color": "red"
},
"2": {
"Average": 32.72,
"Count": 18,
"Sum": 32.96,
"Color": "blue"
},
"3": {
"Average": 31.4,
"Count": 18,
"Sum": 31.48,
"Color": "green"
}
};
Object.keys(json1).forEach((item, index) => {
let statsList = [];
Object.keys(json1[item]).forEach(objItem => {
statsList.push({
title: objItem,
val1: boxObj[1][objItem],
val2: boxObj[2][objItem],
val3: boxObj[3][objItem]
});
});
console.log(statsList)
});
Here in the JSON1, the Number of objects can be any number. It has to format it Dynamically. In the JSON2, Instead of val1,val2 anything can be used uniquely identifiable keys in all the objects present in the array. I have tried using forEach, I was able to achieve it with static keys provided, and with the multiple looping statements. I just want with dynamic keys and avoiding multiple loops and I want to know what is the best and easiest way to do this formatting in Javascript. Advance Thanks for your help.
You may traverse source Object.values() with Array.prototype.reduce() to make up an object that will map each category to all possible values.
Then, you may Array.prototype.map() resulting Object.entries() to return an array of objects with desired structure:
const src = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}},
resultMap = Object
.values(src)
.reduce((r,o,i) => (
Object
.entries(o)
.forEach(([key,value]) =>
(r[key]=r[key]||{}, r[key][`value${i+1}`] = value))
,r),{}),
result = Object
.entries(resultMap)
.map(([name,{...values}]) => ({name,...values}))
console.log(result)
.as-console-wrapper{min-height:100%;}
If only unique items in each category are required, you may somewhat modify above solution, making use of Set():
const src = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}},
resultMap = Object
.values(src)
.reduce((r,o,i) => (
Object
.entries(o)
.forEach(([key,value]) =>
(r[key]=r[key]||(new Set()), r[key].add(value)))
,r),{}),
result = Object
.entries(resultMap)
.map(([name,values]) => ({
name,
...([...values].reduce((r,v,i) => (r[`value${i+1}`]=v, r),{}))
}))
console.log(result)
.as-console-wrapper{min-height:100%;}
You may see your data as a matrix: each row is a feature and each column a dimension
What you have is the data expressed a rows
And what you would like is the data expressed as columns
So what you want is the transpose of your matrix
Let's recall that taking the transpose can be done as: T[j][i] = M[i][j] forall i,j
In your case
for each index of row i in M
for each index of column j in M
// T[j] is your aggregated record
// i being the index of the row has to be renamed 'val'+i
// and you add the property: title: columnOfJ to record T[j]
T[j]['val' + i] = M[i][j]
T[j].title = col corresponding to index j
const M = {"1":{"Average":32.31,"Count":19,"Sum":32.6,"Color":"red"},"2":{"Average":32.72,"Count":18,"Sum":32.96,"Color":"blue"},"3":{"Average":31.4,"Count":18,"Sum":31.48,"Color":"green"}}
const T = []
Object.entries(M).forEach(([i, Mi]) => {
Object.keys(Mi).forEach((col, j) => {
T[j] = T[j] || {}
T[j].title = col // we just put the title before so it is the first entry in your record...
T[j]['val' + i] = Mi[col]
})
})
console.log(T)

Replace JSON Object Programmatically

I'm looking for the most effective way to replace a JSON Object in a file.
20150628 - Update at the bottom of this post
Here's the scenario:
I have a bunch of JSON files (many) and in these files are large chunks of JSON (sometimes 20-30K lines of it). These are configurations for various testing routines we have. Recently, a change was required to change an object from this:
"createdAt": {
"year": 2014,
"month": 11,
"dayOfMonth": 24,
"hourOfDay": 2,
"minute": 22,
"second": 54
}
to a format like this:
"createdAt":"2015-05-12T21:14:51Z"
Let's even make this easier. I want to replace all of the createdAt and updatedAt fields in my JSON object (which there can be many) with:
"createdAt":"2015-05-12T21:14:51Z"
or
"updatedAt":"2015-05-12T21:14:51Z"
There are NUMEROUS (100's of these) objects in each file, with different values for the fields. I need to go through and replace every createdAt and updatedAt object with the new format. The date's do not matter. I can have them be anything.
I can do this by hand, but it will literally take me a day or two to do of full time work (I know, I tried to do one file and after 1/2 hour I gave up, it was taking way too long).
How can I do this programmatically?
Regex? Sed? Something else?
Final note: I only need to do this once. After that, I won't need to do it again.
Thanks for any tips!
Example JSON: (Just imagine the real one is 30,000 lines!) :)
{ "products": [
{
"displayOrder": 3,
"product": {
"foo": "bar",
"createdAt": {
"year": 2014,
"month": 11,
"dayOfMonth": 24,
"hourOfDay": 2,
"minute": 22,
"second": 54
},
"description": "Fizz Bin",
"id": "8765309",
"modelNumber": "call-it",
"name": "Boom",
"price": {
"amount": 100,
"currency": "USD"
},
"type": "Active",
"updatedAt": {
"year": 2015,
"month": 1,
"dayOfMonth": 27,
"hourOfDay": 19,
"minute": 33,
"second": 25
}
}
},
{
"displayOrder": 4,
"product": {
"foo": "barx",
"createdAt": {
"year": 2013,
"month": 1,
"dayOfMonth": 4,
"hourOfDay": 3,
"minute": 2,
"second": 5
},
"description": "Fizzy Stuff",
"id": "876511111",
"modelNumber": "zoom-zoom-1000",
"name": "Zoom Zoom 1000",
"price": {
"amount": 1000,
"currency": "USD"
},
"type": "Active",
"updatedAt": {
"year": 2011,
"month": 5,
"dayOfMonth": 25,
"hourOfDay": 15,
"minute": 35,
"second": 55
}
}
}
]
}
UPDATE 20150628
For those wondering, here's the gulpfile I wrote to accomplish exactly what I wanted. It is based off of the accepted answer. It will recursively search the tree for what I'm looking for an replace it when found. Its not the prettiest thing in the world, but it did exactly what I needed and saved me a couple weeks of manual time. Total time to process all my files? Under 100ms. Amazing.
var gulp = require('gulp');
var change = require('gulp-change');
function searchTreeForDates(obj) {
if(typeof(obj) === 'object') {
for (var key in obj) {
if (typeof(obj[key]) === 'object' && (key === 'createdAt' || key === 'updatedAt')) {
obj[key] = "2015-06-29T00:53:00Z";
} else {
obj[key] = searchTreeForDates(obj[key])
}
}
}
return obj;
}
function updateDate(content) {
var obj = JSON.parse(content);
obj = searchTreeForDates(obj);
return JSON.stringify(obj);
}
gulp.task('change', function() {
return gulp.src('*.json')
.pipe(change(updateDate))
.pipe(gulp.dest('changed/'))
});
Here is an initial stab. You implement your own "date parsing logic." It requires you to install gulp. And save this in a gulpfile.js . You would need to possibly loop over all the properties that are "date" objects. But that logic isn't that hard.
var gulp = require('gulp');
var change = require('change');
function translateDate(dateField){
return dateField.A + dateField.b + ...;
}
function updateDate(content) {
var obj = JSON.parse(content);
//loop over the obj properties and call the below
// for the ones you want to change.
obj.dateField = translateDate(obj.dateField);
return JSON.stringify(obj);
}
gulp.task('change', function() {
return gulp.src('**/*.json')
.pipe(change(updateDate))
.pipe(gulp.dest('changed/'))
});
Why not manually?
function formatDate(dateObject){
var formattedDate =
dateObject['year']+'-'+
dateObject['month']+'-'+
dateObject['dayOfMonth']+'T'+
dateObject['hourOfDay']+':'+
dateObject['minute']+':'+
dateObject['second']+'Z';
}
var jsonArray = {...};
for(var key in jsonArray){
for(var i = 0; i < jsonArray[key].length; i++){
jsonArray[key][i]['createdAt'] = formatDate(jsonArray[key]['createdAt']);
jsonArray[key][i]['updatedAt'] = formatDate(jsonArray[key]['updatedAt']);
}
}
Open each file, change the property with a convert function and then save the new JSON:
function changeDate(obj) {
var newObject = obj.year + '-' + obj.month + '-' + obj.dayOfMonth + 'T' + obj.hourOfDay + ':' + obj.minute + ':' + obj.second;
return newObject;
}
// here you open the file and stores it's content in the products variable.
for (var i = 0; i < products.length; i++) {
var product = products[i];
product.product.createdAt = changeDate(product.product.createdAt);
product.product.updatedAt = changeDate(product.product.updatedAt);
}
// .. now you need to save the modified json

Categories