Firebase realtime data in not getting added properly in scope variable angularjs - angularjs

This is firebase structure for categories2.
and this is for subcategories2.
To display data on screen I want $scope.Categories [] to be filled in this format.
[{
"id": "1",
"display_with": "7",
"image": "/images/salt_sugar.png",
"name": "Salt & Sugar",
"subcategories": [{
"scid": "1",
"scname": "Sugar Products"
},
{
"scid": "5",
"scname": "Tea"
}
]
},
.
.
.
.
]
Logic for filling $scope.Categories [].
$scope.Categories = [];
var categoriesRef = firebase.database().ref('categories2');
categoriesRef.on('value', function(snapshot) {
$scope.Categories = [];
var recvCategories = [];
recvCategories = snapshot.val();
for (var j=0; j<recvCategories.length; ++j){
var category = recvCategories[j];
//alert (category);
if (category != undefined){
var category_modified = {};
category_modified.id = category.id;
category_modified.display_with = category.display_with;
category_modified.name = category.name;
category_modified.image = category.image;
var subcategories = [];
for(var key in category.subcategories) {
var subcategoriesRef = firebase.database().ref('subcategories2/' + key);
subcategoriesRef.on('value', function(snapshot2) {
subcategories.push(snapshot2.val());
});
}
category_modified.subcategories = subcategories;
$scope.Categories.push(category_modified);
}
}
$scope.$apply();
});
As soon as data is available in want to display it on screen. so i am using $scope.$apply();
The problem is data is not displaying properly. but once i go to other controller and come back to same controller, everything displays as expected.
Why subcategories information is not adding up properly in $scope.Categories[]

I just modified your fiddle. just check the following link https://jsfiddle.net/py3ofkyc/8/
function myFunction() {
var subcategories = [];
var subcategoriesRef = firebase.database().ref('subcategories2');
subcategoriesRef.on('value', function(snapshot2) {
subcategories = snapshot2.val();
var Categories = [];
var categoriesRef = firebase.database().ref('categories2');
categoriesRef.on('value', function(snapshot) {
var Categories = [];
var recvCategories = [];
recvCategories = snapshot.val();
_(recvCategories).forEach(function(value) {
var category = value;
if (category != undefined){
var category_modified = {};
category_modified.id = category.id;
category_modified.display_with = category.display_with;
category_modified.name = category.name;
category_modified.image = category.image;
var _subcategories = [];
for(var key in category.subcategories) {
var data = _.filter(subcategories, { 'scid': key });
_subcategories.push(data[0]);
}
category_modified.subcategories = _subcategories;
Categories.push(category_modified);
}
});
console.log(Categories);
});
});
}`

Related

Why is angular extend function not combining two json objects

I have JavaScript vars so that I can view what is going on underneath the hood, so to say.
The first two vars are displaying their respective objects just fine, but not the third, which is using angular.extend to combine two json objects retrieved from two different databases. One is a local db and the other is from a production db.
The common id between the two json is what I am trying to "merge"
JSON 1:
[{"ID": 1, "TITLE": "CSR", "PHONE": "555-555-1212", "FNAME": "JOHN", "LNAME": "SMITH"}]
JSON 2:
[{"ID": 1, "GROUP_MEMBER_ID": "1","GROUP_MEMBER_TYPE_ID":"4","GROUP_ID":"1"}]
The result that I would like to see:
[{"ID": 1, "GROUP_MEMBER_ID": "1","GROUP_MEMBER_TYPE_ID":"4","GROUP_ID":"1", "TITLE": "CSR", "PHONE": "555-555-1212", "FNAME": "JOHN", "LNAME": "SMITH"}]
I have been trying to use angular.extend to no avail:
// local json objects to view result sets
var mLocalJson = {};
var mProdJson = {};
var mCombinedJson = {};
var teamApp = angular.module('teamApp', [])
teamApp.controller('mainController', function($scope, $http) {
$scope.documentsLocal = [];
$scope.documentsProd = [];
$scope.documentsCombined = [];
$scope.loadDataLocal = function () {
$http.post("php/getTeamsLocal.php")
.then(function(resultLocal) {
$scope.documentsLocal = resultLocal.data;
mLocalJson = resultLocal.data;
});
};
$scope.loadDataProd = function () {
$http.post("php/getTeamsProd.php")
.then(function(resultProd) {
$scope.documentsProd = resultProd.data;
mProdJson = resultProd.data;
});
};
$scope.loadDataCombined = function(){
mCombinedJson = angular.extend($scope.documentsCombined, $scope.documentsProd, $scope.documentsLocal);
};
});
I have tried a for loop. I have tried the following:
$scope.loadDataCombined = function(){
mCombinedJson = angular.extend($scope.documentsCombined, mProdJson, mLocalJson);
};
No matter what I have tried mCombinedJson is NULL
The API is not returning a JavaScript object. It is returning a JavaScript array with contents of one JavaScript object.
Use angular.extend to combine the objects inside the array.
var array1 = [{"ID": 1, "TITLE": "CSR", "PHONE": "555-555-1212", "FNAME": "JOHN", "LNAME": "SMITH"}];
var array2 = [{"ID": 1, "GROUP_MEMBER_ID": "1","GROUP_MEMBER_TYPE_ID":"4","GROUP_ID":"1"}];
var combinedArray = [angular.extend(array1[0],array2[0])];
console.log(combinedArray);
<script src="//unpkg.com/angular/angular.js"></script>
I used for loops to solve my issue:
$scope.loadDataProd = function () {
$http.post("php/getTeamsProd.php")
.then(function(resultProd) {
$scope.documentsProd = resultProd.data;
mProdJson = resultProd.data;
for (var i = 0; i < mLocalJson.length; i++) {
for (var j = 0; j < mProdJson.length; j++) {
if (mLocalJson[i].TEAM_ID == mProdJson[j].TEAMM_ID) {
mCombinedJson.push([{
"TEAM_GROUP_ID": $scope.documentsLocal[i].TEAM_GROUP_ID,
"TEAM_GROUP_MEMBER_ID": $scope.documentsLocal[i].TEAM_GROUP_MEMBER_ID,
"TEAM_GROUP_DESC": $scope.documentsLocal[i].TEAM_GROUP_DESC,
"TEAM_GROUP_MEMBER_TYPE_DESC": $scope.documentsLocal[i].TEAM_GROUP_MEMBER_TYPE_DESC,
"TEAM_ID": $scope.documentsProd[j].TEAMM_ID,
"TEAMM_DESC": $scope.documentsProd[j].TEAMM_DESC,
"TEAMM_EMAIL": $scope.documentsProd[j].TEAMM_EMAIL,
"TEAMM_EXTENSION": $scope.documentsProd[j].TEAMM_EXTENSION,
"TEAMM_EZLYNX_USERNAME": $scope.documentsProd[j].TEAMM_EZLYNX_USERNAME,
"TEAMM_FAX": $scope.documentsProd[j].TEAMM_FAX,
"TEAMM_NAME": $scope.documentsProd[j].TEAMM_NAME,
"TEAMM_PHONE": $scope.documentsProd[j].TEAMM_PHONE,
"TEAMM_QUEUE": $scope.documentsProd[j].TEAMM_QUEUE,
"TEAMM_QUEUE_GROUP": $scope.documentsProd[j].TEAMM_QUEUE_GROUP,
"TEAMM_QUEUE_KILLED": $scope.documentsProd[j].TEAMM_QUEUE_KILLED,
"TEAMM_QUEUE_SENT": $scope.documentsProd[j].TEAMM_QUEUE_SENT,
"TEAMM_TYPE": $scope.documentsProd[j].TEAMM_TYPE
}]);
}
}
}
});
};
$scope.loadDataCombined = function(){
setTimeout(function(){
for (var i = 0; i < mLocalJson.length; i++) {
for (var j = 0; j < mProdJson.length; j++) {
if (mLocalJson[i].TEAM_ID == mProdJson[j].TEAMM_ID) {
mCombinedJson.push([{
"TEAM_GROUP_ID": mLocalJson[i].TEAM_GROUP_ID, // 1 - 7
"TEAM_GROUP_MEMBER_ID": mLocalJson[i].TEAM_GROUP_MEMBER_ID,
"TEAM_GROUP_DESC": mLocalJson[i].TEAM_GROUP_DESC, // Cereal Killers, Guns n Closes, etc...
"TEAM_GROUP_MEMBER_TYPE_DESC": $scope.documentsLocal[i].TEAM_GROUP_MEMBER_TYPE_DESC, // Director, Manager, Assistant Manager, Producer
"TEAM_ID": mProdJson[j].TEAMM_ID,
"TEAMM_DESC": mProdJson[j].TEAMM_DESC,
"TEAMM_EMAIL": mProdJson[j].TEAMM_EMAIL,
"TEAMM_EXTENSION": mProdJson[j].TEAMM_EXTENSION,
"TEAMM_EZLYNX_USERNAME": mProdJson[j].TEAMM_EZLYNX_USERNAME,
"TEAMM_FAX": mProdJson[j].TEAMM_FAX,
"TEAMM_NAME": mProdJson[j].TEAMM_NAME,
"TEAMM_PHONE": mProdJson[j].TEAMM_PHONE,
"TEAMM_QUEUE": mProdJson[j].TEAMM_QUEUE,
"TEAMM_QUEUE_GROUP": mProdJson[j].TEAMM_QUEUE_GROUP,
"TEAMM_QUEUE_KILLED": mProdJson[j].TEAMM_QUEUE_KILLED,
"TEAMM_QUEUE_SENT": mProdJson[j].TEAMM_QUEUE_SENT,
"TEAMM_TYPE": mProdJson[j].TEAMM_TYPE
}]);
}
}
}
}, 300);
$scope.lDc();
};
$scope.lDc = function(){
$scope.documentsCombined = mCombinedJson;
};

make value of one( key value pair )to be key of another in angular js

i am having a json response from which i wanted to create new json object
response = [
{Detail:"Reuters ID",keyName:"Reuters_ID"},
{Detail:"Parity One",keyName:"parity_one"},
{Detail:"Parity level",keyName:"parity_level"}
];
i wanted to achieve this after manipulating keys and value pair
lang_Arr =[
{Reuters_ID:"Reuters ID"},
{parity_one:"Parity One"},
{parity_level:"Parity level"}
];
i have tried doing it in two ways
1) in this getting error as unexpected tokken (.)
var Lang_arr =[];
angular.forEach(response, function(value, key) {
Lang_arr.push({value.keyName:value.Detail});
});
2) here getting unxepected token [
var Lang_arr =[];
angular.forEach(response, function(value, key) {
Lang_arr.push({value['keyName']:value['Detail']});
});
i have tried assigning the values seperatly too but it doesn't work there also
var Lang_arr=[];
var k ='';
var v ='';
var i = 1;
angular.forEach(response, function(value, key) {
k ='';
v ='';
i = 1;
angular.forEach(value,function(val,key){
if(i == 1 )
k = val;
if(i == 2)
v = val;
if(!empty(k) && !empty(v))
Lang_arr.push({k:v})
i++;
});
});
You can use javascript map function to map the objects to array
var response = [
{Detail:"Reuters ID",keyName:"Reuters_ID"},
{Detail:"Parity One",keyName:"parity_one"},
{Detail:"Parity level",keyName:"parity_level"}
];
var lang_Arr =[];
lang_Arr = response.map(function(o){
var obj = {};
obj[o.Detail] = o.keyName;
return obj;
})
console.log(lang_Arr)
With Angular forEach also you can achieve this functionality
var response = [
{Detail:"Reuters ID",keyName:"Reuters_ID"},
{Detail:"Parity One",keyName:"parity_one"},
{Detail:"Parity level",keyName:"parity_level"}
];
var modifiedArray = [];
angular.forEach(response, function(val, key) {
var res = {};
res[val.keyName] = val.Detail;
this.push(res);
}, modifiedArray);
console.log(modifiedArray)
Working Example in Fiddle
You have to assign it in the http call that gets the response
$htpp.get(....).then(function(response){
lang_arr = [];
response.forEach(function(obj){
var item = {obj.keyName : obj.detail};
lang_arr.push(item);
}

Angular nested loop promises

I'm trying to build a Cordova/angular app with a SQLite plugin to make it work offline but I'm having a lot of trouble with the promise and asynchronous of the query to the database this is my situation:
I have 5 table configured like this:
Table Pages with id, title, template_id and body
Table Menu with id and tag
Table PageMenus with id and page_id and menu_id to associate page and menu
Table MeniItems with id menu_id and body with the "actual" element in teach menu
Table template with id and tag to select the right view
for compatibility reason (I'm using the same code for the webapp and the mobile app and for the webapp I call my API while on mobile I download all the content on the device) I need to retrive the pages in this format:
{
"id": 1
"body": "Welcome to the homepage",
"title": "Homepage",
"template_tag": "tab",
"menus": [
{
"id": 3,
"tag": "home_menu",
"menu_items": [
{
"menu_id": 3,
"body": "Movie"
},
{
"menu_id": 3,
"body": "Restaurant"
},
{
"menu_id": 3,
"body": "Messages"
},
{
"menu_id": 3,
"body": "Systems"
}
]
},
{
"id": 62,
"tag": "user_menu",
"menu_items": [
{
"menu_id": 62,
"body": "About"
},
{
"menu_id": 62,
"body": "Updates"
},
{
"menu_id": 62,
"body": "Help"
},
{
"menu_id": 62,
"body": "Reset Password"
},
{
"menu_id": 62,
"body": "Report/ Feedback"
}
]
}
]
}
I'm already able to get the right format but my problem is that the controller tries to access the body of the menu before is resolved so I get error undefined this is the code I'm using in my factory at themoment:
return {
getHomePage: function() {
// other function
},
getPage: function(id) {
var results = $q.defer();
function request() {
var res = {};
var queryPage = "SELECT pages.id, pages.body, pages.title, templates.tag AS template_tag FROM pages JOIN templates ON pages.template_id = templates.id WHERE pages.id = ?";
$cordovaSQLite.execute(db, queryPage, [id]).then(function(page) {
res = page.rows.item(0);
res.menus = [];
var queryMenus = "SELECT menus.id, menus.tag FROM menus JOIN page_menus ON menus.id = page_menus.menu_id WHERE page_menus.page_id = ?";
$cordovaSQLite.execute(db, queryMenus, [res.id]).then(function(menus) {
for (var i = 0; i < menus.rows.length; i++) {
var menu = {
id: menus.rows.item(i).id,
tag: menus.rows.item(i).tag,
menu_items: []
};
var queryMenuItems = "SELECT * FROM menu_items JOIN menus ON menu_items.menu_id = menus.id where menus.id = ?"
$cordovaSQLite.execute(db, queryMenuItems, [menus.rows.item(i).id]).then(function(menu_items) {
for (var i = 0; i < menu_items.rows.length; i++) {
menu.menu_items.push(menu_items.rows.item(i));
}
});
res.menus.push(menu);
};
results.resolve(res);
});
});
};
request();
return results.promise;
},
getMedia: function(id) {
// other function
}
};
It's a good practice to chain promises the way:
getSomething: function(...) {
return requestReturningPromise1.then(function(resultOfPromise1) {
// Do something here (prepare next request,...)
return requestReturningPromise2;
}).then(function(resultOfPromise2) {
// Do something here (prepare next request,...)
return requestReturningPromise3;
}).then(function(resultOfPromise3) {
// Do something here (prepare next request,...)
return finalReturn;
});
}
Nesting is reduced, it's more readable and easy to debug.
So applying it to your code gives something like this:
getPage: function(id) {
var res = {};
var queryPage = "SELECT pages.id, pages.body, pages.title, templates.tag AS template_tag FROM pages JOIN templates ON pages.template_id = templates.id WHERE pages.id = ?";
return $cordovaSQLite.execute(db, queryPage, [id]).then(function(page) {
res = page.rows.item(0);
res.menus = [];
var queryMenus = "SELECT menus.id, menus.tag FROM menus JOIN page_menus ON menus.id = page_menus.menu_id WHERE page_menus.page_id = ?";
return $cordovaSQLite.execute(db, queryMenus, [res.id]);
}).then(function(menus) {
var menuPromises = [];
for (var i = 0; i < menus.rows.length; i++) {
var menu = {
id: menus.rows.item(i).id,
tag: menus.rows.item(i).tag,
menu_items: []
};
var queryMenuItems = "SELECT * FROM menu_items JOIN menus ON menu_items.menu_id = menus.id where menus.id = ?";
var menuPromise = $cordovaSQLite.execute(db, queryMenuItems, [menus.rows.item(i).id]).then(function(menu_items) {
for (var i = 0; i < menu_items.rows.length; i++) {
menu.menu_items.push(menu_items.rows.item(i));
}
return menu;
});
menuPromises.push(menuPromise);
}
return Promise.all(menuPromises);
}).then(function(menus) {
for (var i = 0; i < menus.length; i++) {
res.menus.push(menus[i]);
}
return res;
});
}
Note that in the code above, the service itself returns a promise so you have to consume it like this in your controller:
MyService.getPage(id).then(function(page) {
// here, bind the result page to your controller scope ...
});
This is what I end up doing (I post it even if I don't think will be really helpful for someone else because is heavily based on the structure of my DB):
var promisePage = $cordovaSQLite.execute(db, "SELECT p.*, t.tag AS template_tag FROM pages AS p JOIN templates AS t ON p.template_id = t.id WHERE p.id = ?", [id]);
var promiseMenus = $cordovaSQLite.execute(db, "SELECT m.* FROM menus AS m JOIN page_menus AS pm ON m.id = pm.menu_id WHERE pm.page_id = ?", [id]);
var promiseMenuItems = $cordovaSQLite.execute(db, "SELECT mi.* FROM menu_items AS mi JOIN menus AS m ON mi.menu_id = m.id JOIN page_menus AS pm ON pm.menu_id = m.id WHERE pm.page_id = ?", [id]);
return $q.all([promisePage, promiseMenus, promiseMenuItems]).then(function(data) {
var page = data[0].rows.item(0);
var menus = data[1];
var menuItems = data[2];
// here there is some boring code to construct the page
return page;
Simply instead of querying the db for menu and menu items after I got the page I query all three element in parallel and then do all the work in a $q.all.

creating a service which holds values to be updated later with separate controllers

I am trying to create a service which holds values that I want to be able to update from other controllers. It's a fake financial tracker which allows me to update the values in this service. I can't get it to work and I know I may be setting it up incorrectly. Can someone help me out with this?
My code:
(function () {
"use strict";
var Bkbank = angular.module('Bkbank' []);
Bkbank.controller('dashboardCtlr', function ($scope, dashboardSrvs) {
/*User Data*/
$scope.userName = dashboardSrvs.userName;
$scope.acctNum = dashboardSrvs.acctNum;
$scope.startDate = dashboardSrvs.startDate;
$scope.checkingsTotal = dashboardSrvs.checkingsTotal;
$scope.savingsTotal = dashboardSrvs.savingsTotal;
$scope.investTotal = dashboardSrvs.investTotal;
$scope.ouncesUpdate = dashboardSrvs.ouncesUpdate;
$scope.debtBalance = dashboardSrvs.debtBalance;
$scope.goldSpot = dashboardSrvs.goldSpot;
/*Section Titles*/
$scope.userTitle = dashboardSrvs.userTitle;
$scope.servicesTitle = dashboardSrvs.servicesTitle;
$scope.checkingsTitle = dashboardSrvs.checkingsTitle;
$scope.savingsTitle = dashboardSrvs.savingsTitle;
$scope.investTitle = dashboardSrvs.investTitle;
$scope.debtTitle = dashboardSrvs.debtTitle;
$scope.savingsUpdateTitle = dashboardSrvs.savingsUpdateTitle;
});
Bkbank.service('dashboardSrvs', function () {
/*User Data*/
this.userName = "Tim Willson";
this.acctNum = 554887;
this.startDate = "01/12/75";
this.checkingsTotal = "56458.00";
this.savingsTotal = "98187.00";
this.investTotal = "34143.00";
this.ouncesUpdate = "30";
this.debtBalance = "10000.00";
this.goldSpot = "1138.10";
/*Section Titles*/
this.userTitle = "User";
this.servicesTitle = "Financial Services";
this.checkingsTitle = "Checkings";
this.savingsTitle = "Savings";
this.investTitle = "Investments";
this.debtTitle = "debt";
this.savingsUpdateTitle = "Update Savings Account";
});
}());
I am not fully clear with the question you have asked but what I understood is you want to get/set attribute values into service so that updates available to all the consumer controller(s). In such scenario you can create service as e.g.
app.service('dashboardSrvs', function() {
var userName = "Tim Willson"; //Set some default Value
return {
get userName() {
return userName;
},
set userName(val) {
userName = val;
}
}
});
And inside the controller you can update the userName as -
testService.userName = 'Mike Tyson';
Angular merge to the rescue!
I advise you in advance to read this great article about Angular copy / extend / merge objects. Article link here
var demoApp = angular.module("demoApp", []);
demoApp.service("dashboardService", function () {
var configObj = {
"userData": {
"userName": "A",
"acctNum": "B",
"startDate": "C"
}
};
return configObj;
});
demoApp.controller("appController", function ($scope, dashboardService) {
// Override the new values of the service with a new object
var newConfigValues = {
"userData": {
"userName": "X",
"acctNum": "Z"
}
};
var newConfigObj = angular.merge({}, dashboardService, newConfigValues);
console.log(newConfigObj); // "userName": "X", "acctNum": "Z", "startDate": "C"
});
As you can see, you can override all or just some values. If you do the latter, the original values in your service will be kept.
JSFiddle here

Angular ng-repeat - limit results to timeframe

I have the following Model and would like to display the top voted over the last 24 hours
{
"_id": {
"$oid": "56abe20fabd3fa64187b5d21"
},
"user": {
"$oid": "56a1832a36dc3d0e00c7aa3f"
},
"title": "Intel Pentium i5 Quad-Core i5-6400",
"created": {
"$date": "2016-01-29T22:05:03.574Z"
},
"votes": 1
}
So basically limiting the ng-repeat to the created field within the last 24 hours.
Filter
angular.module('savings').filter('lessThan', function () {
return function(savings, requirement) {
var filterKey = Object.keys(requirement)[0];
var filterVal = requirement[filterKey];
var filtered = [];
if(filterVal !== undefined && filterVal !== ''){
angular.forEach(savings, function(saving) {
var today = new Date();
var date = new Date(saving.created.$date);
var diff = today - date;
diff = diff / (1000*60*60);
if(diff < filterVal) {
filtered.push(saving);
}
});
alert(filtered.length);
return filtered;
}
return savings;
};
});
Ive tried implement the answer below but it doesnt return any results.
Screenshot of resource.
I'll save you some time.. here is your filter.
app.filter('lessThan', function () {
return function(items, requirement) {
var filterKey = Object.keys(requirement)[0];
var filterVal = requirement[filterKey];
var filtered = [];
if(filterVal !== undefined && filterVal !== ''){
angular.forEach(items, function(item) {
var today = new Date();
var date = new Date(item.created)
var diff = today - date;
diff = diff / (1000*60*60)
if(diff < filterVal) {
filtered.push(item);
}
});
return filtered;
}
return items;
};
});
And call it like:
<div ng-repeat="item in items | lessThan: {'created':24}">
Here is a plunker.
EDIT: Based on the screenshot created property looks more like this:
"created": "2016-01-29T22:05:03.574Z"
I've edited the filter for this model

Resources