Two dimensions data, display no results - angularjs

I'm a beginner with angularJs
I have json data on two dimensions :
[
{
"nom": "Name 1",
"subventions": [
{
"beneficiaire": "ben\u00e9f Phipippe C mars 2015",
"montant": "7<span class='space'><\/span>898,99",
"annee": 1,
"trimestre": 4,
"infoAdditionnelle": "<p>info mars - 2015<\/p>\r\n<div id=\"nested_deluminate_fullscreen_workaround\" style=\"background-color: rgba(0, 0, 0, 0);\">\u00a0<\/div>"
},
{
"beneficiaire": "cvbcvbn",
"projet": "<p>cvnnncbcnbcbn<\/p>",
"circonscription": "456sdxfvxc",
"montant": "131,00",
"annee": 3,
"trimestre": 2,
"infoAdditionnelle": "<p>test<\/p>"
}
]
},
{
"nom": "Name 2",
"subventions": [
{
"beneficiaire": "pierre m",
"montant": "1<span class='space'><\/span>000,00",
"annee": 3,
"trimestre": 1,
"infoAdditionnelle": "<p>avtil 2015-16<\/p>"}
]
},
{
"nom": "Name 3",
"subventions": [
{
"beneficiaire": "bene pierre p avril 2015-16",
"montant": "1<span class='space'><\/span>222,00",
"annee": 3,
"trimestre": 1,
"infoAdditionnelle": "<p>p avril 2015-16<\/p>"
}
]
}
]
As you can see, there is an array of persons containing the field "nom" and "subventions", "subventions is also an array
I have filters by the fields "annee" and "trimestre", and what i want to do is when there's not result to display, to display a "no results" message
To calculate the number of results, i use this function
$scope.filterArray = function(resultsPersonnes) {
var data = resultsPersonnes.filter(function(prop) {
return prop.subventions[0].annee == $scope.annee.id;
});
if ($scope.myFilter.trimestre > 0) {
return data.filter(function(prop) {
return prop.subventions[0].trimestre == $scope.myFilter.trimestre;
});
} else {
return data
}
}
It's doesn't work for all the cases, you can see an example here http://plnkr.co/edit/9TbO0Hl9LziUS2B6AsAr?p=preview
If you click on "Juillet - septembre" in "Trimestre, i got one result, but the "no results" message is displayed!!!
do you see the error ? please help!
Thanks a lot

As you already guessed in your comment, you were checking only the first row. The fix is to check all rows, for example like this, using Array.some (which returns true if at least one item in array returns true for the function given as parameter)
Edit: the filtering needs to be updated into a single filter
$scope.filterArray = function(resultsPersonnes) {
var data = resultsPersonnes.filter(function(prop) {
return prop.subventions.some(function (subvention) {
var anneeMatches = subvention.annee == $scope.annee.id;
var trimestreMatches = true;
if ($scope.myFilter.trimestre > 0) {
trimestreMatches = subvention.trimestre == $scope.myFilter.trimestre;
}
return anneeMatches && trimestreMatches;
});
});
return data;
};
See working plunker

Related

Filtering JSON object to get the average of 2 objects

I'm doing an React assignment for school but I'm a bit stuck and I can't find the right answer.
I have a data file with the following data:
const students = [
{
"name": "Evelyn",
"assignment": "SCRUM",
"difficultyRating": 3,
"funRating": 4
},
{
"name": "Evelyn",
"assignment": "W1D1-1",
"difficultyRating": 3,
"funRating": 3
},
{
"name": "Evelyn",
"assignment": "W1D2-1",
"difficultyRating": 1,
"funRating": 3
}
]
This goes on, there are 10 student and different assignments. What I need to do is get the average of the difficultyRating and funRating per assignment and use this data in a Victory Graph to display. Victory is working but it's not displaying the average.
I have this function already which takes all the assignments and fills it with the other data but I don't know what to do in the next step, how can I make a new Array of objects that I can use in the Victory Chart which displays the average difficulty/funrating per assignment.
The code I have so far is this:
const groupByAssignment = (objectArray, property) => {
return objectArray.reduce(function (total, obj) {
let key = obj[property];
if (!total[key]) {
total[key] = [];
}
total[key].push(obj);
return total;
}, {});
}
let groupedAssignments = groupByAssignment(students, 'assignment');
In the Victory Graph the output looks like this now:
<VictoryBar
style={{
data: {
fill: "#ff0b03",
},
}}
barWidth={2}
data={props.data}
x="assignment"
y="difficultyRating"
/>
)}
What I need is a data piece that has every assignment with the difficulty/rating averaged from all 10 students.
The following will give the average values of fun rating and difficulty rating. I have added more entries as there was only one record for each assignment.
const students = [ { name: "Evelyn", assignment: "SCRUM", difficultyRating: 3, funRating: 4, }, { name: "Pqr", assignment: "SCRUM", difficultyRating: 4, funRating: 2, }, { name: "Evelyn", assignment: "W1D1-1", difficultyRating: 3, funRating: 3, }, { name: "Evelyn", assignment: "W1D2-1", difficultyRating: 1, funRating: 3, }, { name: "Abc", assignment: "W1D2-1", difficultyRating: 5, funRating: 4, }, ];
const groupByAssignmentWithAverage = (objectArray, property) => {
return objectArray.reduce(
(prevValue, { difficultyRating, funRating, [property]: key }) => {
// key is the value of in obj with property as data name
if (!prevValue[key]) {
// create a new entry for each assignment type
prevValue[key] = {
difficultyRatingAvg: difficultyRating,
funRatingAvg: funRating,
count: 1,
};
} else {
// get the previous count and average values
const {count, difficultyRatingAvg, funRatingAvg} = prevValue[key];
prevValue[key] = {
difficultyRatingAvg:
(difficultyRatingAvg + difficultyRating) /
(count + 1),
funRatingAvg: (funRatingAvg + funRating) / (count + 1),
count: count + 1,
};
}
return prevValue;
},
{}
);
};
let output = groupByAssignmentWithAverage(students, "assignment");
console.log(output);
My solution would be to seprate the objects with same assignment name, and then just find the average of that particular assignment by mapping over individual arrays of objects which we get from initial step.
result = students.reduce(function (r, a) {
r[a.assignment] = r[a.assignment] || [];
r[a.assignment].push(a);
return r;
}, Object.create(null));
console.log(result);
Now you can easily format data according to the graph package you are using.

Cumulative quantity of type X products in javascript

This is the case: Every order can contain many types, with different quantities. I want, for each order item, the total quantity for each type.
[{
"order" : 1,
"orderDetails" : [{
"quantity" : 10,
"product" : {
"productType" : "A"
},
"quantity" : 20,
"product" : {
"productType" : "A"
},
"quantity" : 10,
"product" : {
"productType" : "B"
}
}]
}]
this is my code, it does the job but I am trying to make it a bit more elegant, somehow. I am pretty sure there is redundant code there, I am not sure I am using reduce correctly
const orders = data.map(h => {
const newArray = [];
h.orderDetails_ = h.orderDetails.reduce(function(a, b, i) {
if (newArray[b.product.productType] == undefined) {
newArray[b.product.productType] = b.quantity;
return newArray;
} else {
newArray[b.product.productType] += b.quantity;
return newArray;
}
}, 0);
return h;
});
well, for anyone out there, this is the better and correct version
const orders = data.map(h => {
h.orderDetails_ = h.orderDetails.reduce((orderTotals, order) => {
orderTotals[order.product.productType] =
(orderTotals[order.product.productType] || 0) + order.quantity;
return orderTotals;
}, {});
return h;
});

array with objects containing array

Sorry guys if my way of asking the question in the title is not correct.
I am working on a project on react js and I am getting the data like this
[
{
"count": [
{
"1": 16
},
{
"1": 149
}
],
"day": "2019-08-27"
}
]
now this is my first time I am dealing with this kind of data and I really have no idea how can I show it like this I am really sorry guys I literally can't even show what I have tried because it does not seem relevant
[
{
count: 165
day:"2019-08-27"
}
}
Assuming the data you're getting is under a variable called data you could use reduce:
The below makes the assumption the count is always an array of objects with just 1 key called '1'.
const newData = data.map(datum => {
datum.count = datum.count.reduce((count, item) => {
return count + item['1']
}, 0)
return datum
})
You can try something like this:
let arr = [
// item
{
count: [
{
"1": 16
},
{
"1": 149
}
],
day: "2019-08-27"
}
];
arr.map(item => {
Object.keys(item).map(key => {
console.log(item[key])
// if item[key] is iterable
if(Array.isArray(item[key])) {
item[key].map(val => {
console.log(item)
})
} else {
console.log(item[key])
}
});
});
The concept is that for Objects you do a Object.keys().something and for an array you do a arr.map(item => ...)

How to use IndexOf in a JSON array? It's returning -1

Let's say I'm searching this JSON array for the car model "Focus"
and I want to return its position in the array.
I think indexOf is returning a result of -1 because I'm not stopping the loop. I'm a beginner coder.
The reason I want to return its position is so I can return other results related to "Focus" such as "Ford" by simply knowing its position in the array.
var myObj, i, j, x = "";
myObj = {
"name":"John",
"age":30,
"cars": [
{ "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
{ "name":"BMW", "models":[ "320", "X3", "X5" ] },
{ "name":"Fiat", "models":[ "500", "Panda" ] }
]
}
for (i = 0; i < myObj.cars.length; i++) {
for (j in myObj.cars[i].models) {
x = myObj.cars[i].models[j];
a = x.indexOf("Focus");
document.getElementById("demo").innerHTML = a;
}
}
<p id="demo"></p>
Rather than deal with two different for-loops, use one and try to get the index of whatever each iteration. Test the value of x for -1 (meaning not found). If it isn't -1, that means it was found, and x is the index.
for (i = 0; i < myObj.cars.length; i++) {
x = myObj.cars[i].models.indexOf("Focus");
if (-1 != x) {
document.getElementById("demo").innerHTML = x;
break;
}
}
The break breaks the for-loop so in the case of collision you'll just get the first valid index.
Edit
As a side-note I thought I'd mention what your problem really was: Your indexOf() call is returning a value, but you aren't checking it for -1 values. In your original code, if you tested that a != -1 it would only confirm a == "Focus" and not give you any details on its index. In the end, for a minimal edit, you would need to do
if (-1 != a) {
document.getElementById("demo").innerHTML = j;
}
which is equivalent to
if ("Focus" == x) {
...
}
First i would parse the json with JSON.parse method.
Attention: I am using ECMAScript 6 (ES6) Feature here to use multiline strings. This is not supported by older browsers.
Then i would make use of the Array Prototype functions like map() and find() to first map the index of all models with 'Focus' to a new array and then take the first where the index is 0 or higher. indexOf() Returns -1 when the element your looking for does not exist.
var json = `{
"name": "John",
"age": 30,
"cars": [
{ "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
{ "name":"BMW", "models":[ "320", "X3", "X5" ] },
{ "name":"Fiat", "models":[ "500", "Panda" ] }
]
}`
var myObj = JSON.parse(json)
var focusIndex = myObj.cars.map(c => c.models.indexOf('Focus')).find(i => i >= 0)
document.getElementById("demo").innerHTML = focusIndex
<p id="demo"></p>

Return an array from an Ember computed property

I have two related models - Task and Requirement. Requirements can be one of 3 types (Part, Tool, Material). A Task can have several requirements including several of the same type.
Task A
Requirement 1 (Part)
Requirement 2 (Part)
Requirement 3 (Tool)
Requirement 4 (Material)
Requirement 5 (Tool)
When viewing a single Task I want to group the list of requirements by type in a sort of summary view.
Task A
Parts Requirements (2)
Tooling Requirements (2)
Materials Requirements (1)
I have a computedProperty mostly functioning in my TaskController but I can't seem to get it to return back the array of requirement summaries that I'm building. All the fixture data is setup properly for both models (I can iterate each requirement and show it in the template with no issues).
Here are the models
Task model
App.Task = DS.Model.extend({
name: DS.attr()
requirements: DS.hasMany('requirement', { async: true})
});
Requirement model
App.Requirement = DS.Model.extend({
task_id: DS.belongsTo('task'),
type: DS.attr(),
description: DS.attr(),
quantity: DS.attr()
})
Here is the controller:
App.TaskController
App.TaskController = Em.ObjectController.extend({
requirementSummary: function () {
var self = this,
results = [];
self.get('requirements').then(function(requirements) {
var arrRequirements = requirements.get('content');
var parts = {
name: 'Parts',
description: '',
count: 0,
css_class: 'fa-cog'
},
tools = {
name: 'Tools',
description: '',
count: 0,
css_class: 'fa-wrench'
},
materials = {
name: 'Materials',
description: '',
count: 0,
css_class: 'fa-tint'
};
arrRequirements.forEach(function (requirement) {
if (requirement._data.name == 'Part') {
parts.description += requirement._data.description + ' (' + requirement._data.quantity + ')<br>';
parts.count++;
} else if (requirement._data.name == 'Material') {
materials.description += requirement._data.description + ' (' + requirement._data.quantity + ')<br>';
materials.count++;
} else if (requirement._data.name == 'Tooling') {
tools.description += requirement._data.description + ' (' + requirement._data.quantity + ')<br>';
tools.count++;
}
});
if (parts.description !== '') {
parts.description = parts.description.replace(/(<br>\s*)+$/);
} else {
parts.description = "No Parts requirements found";
}
if (materials.description !== '') {
materials.description = materials.description.replace(/(<br>\s*)+$/);
} else {
materials.description = "No Materials requirements found";
}
if (tools.description !== '') {
tools.description = tools.description.replace(/(<br>\s*)+$/);
} else {
tools.description = "No Tooling requirements found";
}
results.pushObject(parts);
results.pushObject(tools);
results.pushObject(materials);
});
return results;
}.property()
});
Currently it returns back the empty results array because it is waiting on the self.get promise to fulfill. If I return the result of self.get('requirements').then(...) then it returns the promise, not the results array and Ember isn't happy because it's not an array. What I want is for it to return back the populated results array.
The closest question I've found is here but it either doesn't solve the issue or I'm missing something.
You'll need to be using requirementSummary using an observable pattern, or after it's finished resolving.
Additionally this is not required due to requirements already being an iterable field:
var arrRequirements = requirements.get('content');
And you should be using a getter to get a property, not going to ._data.property
requirement.get('description')
Add this to your task template and you should see it populate (asynchronously):
{{#each requirement in requirementSummary}}
Name: {{requirement.name}} - Total: {{requirement.total}}
{{/each}}
The routes all seem to be working as well as the fixtures - I can use {{#each requirement in requirements}} and list each individual requirement with no issues. Just having the problem of generating the summarized property and accessing it after it's computed.
from routes/application_routes.js
this.resource( 'tasks', function () {
this.resource( 'task', { path: ':task_id' }, function () {
this.resource( 'task_requirements', { path: 'requirements' } );
} );
} );
from routes/task_routes.js
// List Tasks
App.TasksRoute = Em.Route.extend({
model: function () {
return this.store.find('task');
}
});
// Task Detail Route
App.TaskRoute = Em.Route.extend({
model: function(params) {
return this.store.find('task', params.task_id);
}
});
// Task Requirements Route
App.TaskRequirementsRoute = Em.Route.extend({
beforeModel: function () {
this.set('task', this.modelFor('task'));
}
});
Fixtures
// SAMPLE TASK FIXTURE.
App.Task.FIXTURES = [
{
"id": 1,
"name": "Test Task #1",
"description": "This is a test task. There are many like it but this one is mine.",
"requirements": [ 1, 2, 3, 4 ]
}
];
// SAMPLE REQUIREMENT FIXTURE
App.Requirement.FIXTURES = [
{
"id": 1,
"task_id": 1,
"type": "Part",
"description": "This is a Part requirement",
"quantity": 4
},
{
"id": 2,
"task_id": 1,
"type": "Part",
"description": "This is a Part requirement",
"quantity": 1
},
{
"id": 3,
"task_id": 1,
"type": "Material",
"description": "This is a Material requirement",
"quantity": 3
},
{
"id": 4,
"task_id": 1,
"type": "Tool",
"description": "This is a Tooling requirement",
"quantity": 1
}
];

Resources