Display the count of array in ng-repeat using angularjs - angularjs

I have a JSON response which contains an array of data.
$scope.Load = function () {
$http.post(elasticSearchURL, { "aggs": { "By_type": { "terms": { "field": "Name" }, "aggs": { "By_color": { "terms": { "field": "Color" } } } } } }).
then(function (response) {
$scope.modelList = response;
}, function (response) {
});
}
I would like to display the count of each element in the JSON.
MyHtml Code
<div ng-repeat="fruits in modelList.data.hits.hits | unique : '_source.fruitsName' | orderBy:'_source.fruitsName' ">
{fruits._source.name.length}
</div>
My Json data will be like this
{"_id":"e-AB2","_version":1,"found":true, "_source":{"name":"Apple", "color":"red"}}},
{"_id":"e-AB2","_version":1,"found":true, "_source":{"name":"Apple", "color":"red"}}},
{"_id":"e-AB2","_version":1,"found":true, "_source":{"name":"Apple", "color":"red"}}}
It displays only the length of the fruitname "Apple" length:5. I want to display the array length of _source.name
I have tried {{$index.length}} but it showing the count as 1 since I am using "unique:" in the <div>
How it can be achieved in angularjs.
Thanks in advance

I think the easiest approach is create hashmap that contains the counts:
$scope.counts = {};
$http.post(elasticSearchURL, postData).then(function (response) {
$scope.modelList = response.data;
response.data.forEach(function (item) {
var source = item._source.name;
if (!$scope.counts.hasOwnProperty(source)) {
$scope.counts[source] = 0;
}
$scope.counts[source]++;
});
});
Then in the view you can use:
Count = {{counts[fruits._source.name]}}
$scope.counts will look like:
{ 'Apple':3, 'Orange':5}
What you probably want to do is map all the data to a different array in this same fashion and get rid of the unique filter since there is no way to do what you are asking directly in the view

Related

Angular 5 display result from JSON response

I am trying to access the "list" parameter in the following data set received from [Open weather map][1]. I basically need to access the list layer in the below set where I can get the temp parameter.
{
"cod":"200",
"message":0.0046,
"cnt":37,
"list":[
{
"dt":1518080400,
"main":{
"temp":297.81,
"temp_min":295.457,
"temp_max":297.81,
"pressure":1011.64,
"sea_level":1018.79,
"grnd_level":1011.64,
"humidity":71,
"temp_kf":2.35
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01d"
}
],
"clouds":{
"all":0
},
"wind":{
"speed":3.76,
"deg":322.502
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 09:00:00"
},
{
"dt":1518091200,
"main":{
"temp":298.03,
"temp_min":296.468,
"temp_max":298.03,
"pressure":1010.47,
"sea_level":1017.64,
"grnd_level":1010.47,
"humidity":65,
"temp_kf":1.57
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03d"
}
],
"clouds":{
"all":48
},
"wind":{
"speed":4.77,
"deg":315
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 12:00:00"
},
{
"dt":1518102000,
"main":{
"temp":294.89,
"temp_min":294.104,
"temp_max":294.89,
"pressure":1011.17,
"sea_level":1018.11,
"grnd_level":1011.17,
"humidity":77,
"temp_kf":0.78
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03d"
}
],
"clouds":{
"all":44
},
"wind":{
"speed":4.91,
"deg":287.002
},
"sys":{
"pod":"d"
},
"dt_txt":"2018-02-08 15:00:00"
}
]}
I am not sure as to how to go about it. I keep on getting this error "ERROR Error: Cannot find a differ supporting object"
I tried looping through it like below
this.http.get('http://api.openweathermap.org/data/2.5/forecast?id=3362024&APPID=bbcf57969e78d1300a815765b7d587f0').subscribe(data => {
this.items = JSON.stringify(data);
console.log(this.items);
for(var i = 0; i < this.items.length; i++){
this.min = this.items[i].dt;
console.log(this.min);
}
});
Try this. Make sure you import following import on top of the component
import 'rxjs/Rx';
or
import 'rxjs/add/operator/map'
getData(){
this.http.get('https://api.openweathermap.org/data/2.5/forecast?id=3362024&APPID=bbcf57969e78d1300a815765b7d587f0')
.map(res=>res.json()).subscribe(data => {
this.items = data;
console.log(this.items);
for(var i = 0; i < this.items.list.length; i++){
this.min = this.items.list[i].main;
console.log(this.min);
}
});
}
WORKING DEMO
Do console.log(data); and check what kind of data you are getting from API.
If you are getting JSON data from API, then do not do JSON.stringify(data);
If you are getting JSON contained in string then do JSON.parse();
After this you will get JSON in a variable and you can iterate it as follows
Also, do not post your api key in question , others can hit API using your api key
this.http.get('http://api.openweathermap.org/data/2.5/forecast?id=yourId&APPID=yourapikey')
.subscribe(data => {
var res = JSON.parse(data); //if you are getting JSON in a string, else do res = data;
for(var i = 0; i < res.list.length; i++){
console.log(res.list[i].main.temp);
}
});
Considering you are correctly getting json response:=>
One way is :
if you know response in advance and its basic structure is always same then:
you can create a model object similar to the json response and assign the json response to that object and access any values.
e.g.
export class TopLayer{
fieldName1: dataType;
fieldName2: Array<SecondLayer>;
}
export class SecondLayer{
fieldName1: datatype;
fieldName2: ThirdLayer;
}
export class ThirdLayer{
fieldName: datatype
}
another is: assign your json response to a var variable then access what you need:
e.g.
var x = response;
var list = x.list;
We can also do:
this.http.get("some-api-url")
.subscribe((response)=>{
for (let key in response) {
if (response.hasOwnProperty(key)) {
let element = response[key];
let singleData = {id: element.id, value: element.value};
this.dataArray.push(singleData);
}
}
},
(error)=>{
console.log(error)
});
When the response is like [{}, {}, ...]

angular chaining arrays of promises

I am building a website over a database of music tracks. The database is as follows :
music table contains musicid and title
musicrights table contains musicid and memberid
members table contains memberid and memberinfo.
I'm trying to build an array of objects in my database service, which each entry represents a track containing its rightholders (contains information aubout one rightholder but not his name) and their member info (contains name etc). The backend is sailsjs and the code is as follows :
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
The first array of promises seems to work as expected, but not the second one in getRightHolders. What is strange is that this function returns an array of one or two promises, which are rightHolders waiting for their memberinfo. But in the callback where I console.log the response, i get an array of one or two (as per the number of pushed promises) but this array's elements are arrays of 30 memberinfo instead of one memberinfo. I don't understand how this $q.all() call gets mixed with the previous-level $q.all.
The data structure is roughly like this
documents [ ] ($http => 30 responses)
music.musicid
music.rightHolders [ ] ($http => 1, 2, 3 responses)
rightholder.rights
rightholder.member ($http => 1 response)
member.memberinfo
Any help appreciated. Thank you !
UPDATE : Thank you for your answer, it worked like a charm. Here's the updated code, with also the migrate service which formats data differently (there is some database migration going on). I kept it out of the first example but your answer gave me this neat syntax.
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
I'm not quite sure how you're getting the result you describe, but your logic is more convoluted than it needs to be and I think this might be leading to the issues you're seeing. You're giving the getRightsHolders function the responsibility of returning the document and based on your comment above, it sounds like you previously had the getHolderMember() function doing something similar and then stopped doing that.
We can clean this up by having each function be responsible for the entities it's handling and by using .map() instead of for (please don't use for..in with arrays).
Please give this a try:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);

How can search JSON for a value key and return the nested data?

The below block is my JSON. The -KTYLrHDHt234rFDNHrm type hashes are generated by the supplied API of the client. I think they're using Firebase.
I am passing a query in the URL which contains the pageId for each of those nested objects.
Example https://cms.app.io/edit/Nike3243
But since the hash is auto generated how can I search through all the JSON and check if the pageId matches my Angular route and then only return the values of the same child.
{
"-KTYLrHDHtdq23423NHrm": {
"pageCreation": "10/8/2016, 14:14:22 PM",
"pageGallery": {
"slider_1_img": "http://",
"slider_2_img": "http://",
},
"pageId": "Nike13243",
"pageName": "Nike Campaign 1",
"store": "11"
},
"-KTYLrHDHtdqirFDNHrm": {
"pageCreation": "10/8/2016, 12:14:22 AM",
"pageGallery": {
"slider_1_img": "http://",
"slider_2_img": "http://",
},
"pageId": "Nike323243",
"pageName": "Nike Campaign 2",
"store": "12"
},
"-KTYLrHDHt234rFDNHrm": {
"pageCreation": "10/8/2016, 13:14:22 PM",
"pageGallery": {
"slider_1_img": "http://",
"slider_2_img": "http://",
},
"pageId": "Nike3243",
"pageName": "Nike Campaign 3",
"store": "13"
}
}
So I want to return only the data of Nike3243 but I want to return the store, the slider and the pageName. How can I do this since the KTYLrHDHt234rFDNHrm hash is something I will never know
cmsApp.controller('pages-edit', function ($scope, $http, $routeParams) {
var pageIdU = $routeParams.id;
$http.get(firebase_url+'cms/home.json'+randstatus).success(function(data) {
$scope.pages = data;
// this would be pageId = Nike3243
console.log(data.pageIdURI.pageName[pageId]);
});
});
Thanks
Assuming your object is called 'objTest', you could do something like this:
var strPageId = 'The page id to find', objFound;
for( var strKey in objTest ) {
var objTemp = objTest[strKey];
if ( objTemp['pageId'] == strPageId ) {
objFound = objTemp;
break;
}
}
if ( typeof objFound == "object" ) {
//Do something...object has been found!
}
I actually did this:
$.each(data, function (bb) {
var crossReference = data[bb].transId;
if (crossReference==pageIdUri) {
$scope.transNameEn = data[bb].transNameEn;
$scope.transNameArabic = data[bb].transNameArabic;
$scope.transCreation = data[bb].transCreation;
$scope.transModified = data[bb].transModified;
$scope.notes = data[bb].notes;
}
});
It may be easier for you to simply transform the data rather than perform this search over and over. You can loop through the data once and get it in the correct format.
I would do something like:
var recordLookup = {};
for (var id in records) {
var pageId = records[id].pageId;
recordLookup[pageId] = record[id];
recordLookup[pageId].originalId = id;
}
This way you can now easily look up any record by its page id. If you need to send the data back to the server in the original form you still have that original id and can do whatever you need to in order to get it in the proper format. This way you loop once or maybe twice, (once to make the lookup and once to revert at the end of your operation) rather than any time you need to get data out of your records.

Find the identifier of a certain data set in firebase

I'm searching through clients invoices
These invoices are stored within the client json.
so...
clients: {
... : {
invoices: {
},
},
}
I'm doing this by this:
var ref = new Firebase(fbUrl+'/clients/'+client+'/invoices/');
ref.on("value", function(snapshot) {
var list = snapshot.val();
angular.forEach(list, function(item) {
if(item.settings.number == id)
{
console.log(item.id());
invoice.details = item;
}
})
});
Inside the "if" how do I get the unique id auto generated by Firebase? In your html your able to do $id typically.
Once you call snapshot.val(), you're just dealing with a Javascript object. See the documentation for angular.forEach. You just need to specify a second argument to the function.
angular.forEach(list, function(item, key) {
...
});

Node.js : control flow with forEach

I am trying to create array from database objects :
I have entity "group" wich hasMany "devices", I want to create array whit all groups and for each groups the list of his devices :
[
{
"group_id": “1”,
"name": “My_group”,
"devices_list": [1, 2, 18]
},
{
"group_id": “2”,
"name": “My_second_group”,
"devices_list": [3, 24]
}
]
I tried several ways like this :
Group.all(function (err, groups) {
var resJson = {};
groups.forEach(function(group, index){
group.devices(function(err, devices){
resJson[index] = group;
console.log(devices);
resJson[index].devices_list = devices;
//End of the loop
if (index == groups.length -1){
send({code: 200, data: resJson});
}
});
});
});
EDIT 1 :
I tried this way too :
var resJson = {};
groups.forEach(function(group, index){
group.devices(function(err, devices){
resJson[index] = group;
resJson[index].devices_list = [];
devices.forEach(function(device,index2){
resJson[index].devices_list.push(device);
});
//End of the loop
if (index == groups.length -1){
send({code: 200, data: resJson});
}
});
});
But finally, my resJson contains only empty groups (groups without device associated), the other groups are not visible. Thus my devices_list are all empty whereas the console.log(devices) display devices.
It seems that the "send" instruction is processed before the treatment of non-empty groups.
What is the rigth way to do this ?
Thank you for your time
Instead of tracking and using an index against the length of the list perhaps you could use an after type of construct. I really enjoy them and they're easy to integrate and serve the perfect purpose for doing something after a set number of times.
First, lets define an after function you can use.
var after = function(amount, fn) {
var count = 0;
return function() {
count += 1;
if (count >= amount) {
fn.apply(arguments);
}
};
};
That should work for you now, let's modify your code sample to use this.
var json = []; // To return, you originally wanted an array.
Group.all(function(err, groups) {
if (err) {
// Handle the error
} else {
var sendJson = after(groups.length, function(json) {
send({code: 200, data: json});
});
groups.forEach(function(group) {
group.devices(function(err, devices) {
if (err) {
// Handle the error...
} else {
group.devices_list = devices;
json.push(group); // This part is different, using this method you'll match the JSON you gave as your "goal"
}
// This is outside the if/else because it needs to be called for every group
// regardless of change. If you do not call this the exact number of times
// that you specified it will never fire.
sendJson(json);
});
}
});
Perhaps something like that might clear up your issue.

Resources