implementing socket.io on existing application - angularjs

My current application poll using MEAN stack and in controller I have a function vote() and API route defined as follow:
"/api/polls/pollID/pollChoiceID"
(ex. http://localhost:3001/api/polls/5587ad060a9e110816f9f1a8/5587ad060a9e110816f9f1a9)
I have the app working fine as it's but now I'm looking to implement socket.io on this app so that when client #2 connected and vote the voting result graph of client #1 will update in real time. I did some research about socket.io but I'm still stuck on implementing it.
For instance, in controller.js and inside the vote() I need to add:
socket.emit('send:vote', poll);
and over the routes/index.js I'll need to handle the socket.emit from controller so I wrap existing router.post codes with socket.on :
socket.on('send:vote', function(data){
router.post('/api/polls/:poll_id2/:poll_choice2', function(req, res)
{
//existing code here
}
}
However, Ii'm not sure if I'm taking the right steps so that they will work with my existing API route. Any inputs would be great! Thanks
/*
controller.js
*/
var voteObj = { poll_id1: pollSelected, choice1: pollChoiceSelected };
$scope.votedPollID = voteObj.poll_id1;
$scope.votedPollChoiceID = voteObj.choice1;
$scope.vote = function()
{
$http.post('/api/polls/' + $scope.votedPollID + '/' + $scope.votedPollChoiceID)
.success(function (data)
{
console.log(data);
$scope.poll = data;
})
.error(function(data) {
console.log('Error: ' + data);
})
/*
routes/index.js
*/
router.post('/api/polls/:poll_id2/:poll_choice2', function(req, res)
{
var testpollid = req.params.poll_id2;
var testpollchoiceid = req.params.poll_choice2;
var ipCounter = 0;
PollModel.findById({_id: req.params.poll_id2}, function(err, poll)
{
if(poll)
{
var choice = poll.choices.id(testpollchoiceid);
choice.votes.push({ ip: ip });
var ipCounter = ipCounter++;
poll.save(function(err, doc)
{
if(err)
{
return (err);
}
else
{
var theDoc = {
question: doc.question, id: doc._id, choices: doc.choices,
userVoted: false, totalVotes: 0
};
for(var i = 0, ln = doc.choices.length; i< ln; i++)
{
var choice = doc.choices[i];
for(var j= 0, jLn = choice.votes.length; j< jLn; j++)
{
var vote = choice.votes[j];
theDoc.totalVotes++;
theDoc.ip = ip;
if(vote.ip === ip)
{
theDoc.userVoted = true;
theDoc.userChoice = { _id: choice._id, text: choice.text };
}
}
}
poll.userVoted = theDoc.userVoted;
}
});
return res.json(poll);
}
else
{
return res.json({error:true});
}
});
});
});
});

Related

xmpp message not send to selected friend

I am working in mean stack application and now I required to make chatting module using the XMPP protocol.
I am new with XMPP,
I have used "node-xmpp-server" and "node-xmpp-client" in node js
and "Strophe.js" in angular js.
My code is as below:
app.js (server side file)
"use strict";
var express = require("express");
var https = require('https');
var http = require("http");
var fs = require('fs');
var app = express();
var xmppClient = require('node-xmpp-client');
var xmppServer = require('node-xmpp-server');
var AES = require("crypto-js/aes");
var CryptoJS = require("crypto-js");
/**
* #description all process variables
*/
require("./config/vars")(app);
var hostName = global.hzConfig.qualifiedHostName;
var config = require("./config/config.js")(app, express);
var friendsArr = [];
var server = null
var startServer = function(done) {
// Sets up the server.
console.log("start server.....");
console.log('xmpp server is listening on port ' + global.hzConfig.xmppServerPort + " on " + process.pid + ' !');
server = new xmppServer.C2S.BOSHServer({
port: global.hzConfig.xmppServerPort,
domain: 'localhost'
})
console.log("server");
console.log(server);
// On connection event. When a client connects.
server.on('connection', function(client) {
// That's the way you add mods to a given server.
// Allows the developer to register the jid against anything they want
console.log('connection');
client.on('register', function(opts, cb) {
console.log('REGISTER')
cb(true)
})
// Allows the developer to authenticate users against anything they want.
client.on('authenticate', function(opts, cb) {
console.log('server:', opts.username, opts.password, 'AUTHENTICATING')
if (opts.password === '') {
console.log('server:', opts.username, 'AUTH OK')
cb(null, opts)
} else {
console.log('server:', opts.username, 'AUTH FAIL')
cb(false)
}
})
client.on('online', function() {
console.log("client");
console.log(client.jid);
console.log('server:', client.jid, 'ONLINE');
friendsArr.push(client.jid);
console.log("friendsArr================>>>>>>>>>>>>>");
console.log(friendsArr);
//client.send(new xmppClient.Message({ type: 'chat' }).c('body').t("Hello there, little client."));
})
// Stanza handling
client.on('stanza', function(stanza) {
console.log(stanza);
console.log('server:', client.jid, 'stanza', stanza.toString())
var body = stanza.getChild('body');
var message = body.getText();
console.log("body===========>>>>>");
console.log(body);
console.log("message===========>>>>>");
console.log(message);
var from = stanza.attrs.from;
stanza.attrs.from = stanza.attrs.to;
stanza.attrs.to = friendsArr[0];
console.log("stanza.attrs");
var sendTo = "laxman#mailinator.com/";
friendsArr.map(function(obj) {
if (obj["user"] === "laxman") {
console.log(obj["_resource"]);
sendTo = sendTo + obj["_resource"];
}
});
//client.send(stanza)
// client.send(stanza)
//console.log("stanza.attrs.from");
//console.log(stanza.attrs.from);
console.log("sendTo++++++++++ ::::: " + sendTo);
var stanza = new xmppClient.Element('message', { to: sendTo, type: 'chat', 'xml:lang': 'ko' }).c('body').t('aaaaaMessage from admin1');
client.send(stanza);
console.log(stanza);
//client.send(new xmppClient.Message({to : sendTo, type: 'chat' }).c('body').t("Hello there, little client."));
})
// On Disconnect event. When a client disconnects
client.on('disconnect', function() {
console.log('server:', client.jid, 'DISCONNECT')
})
})
server.on('listening', function() {})
}
startServer();
message_service.js (clien side file)
(function() {
'use strict';
angular
.module("myApp")
.factory("HzXMPPService", ['$rootScope', '$cookies', '$location', 'HzServices',
function($rootScope, $cookies, $location, HzServices) {
console.log("*****************************************");
return {
OnConnectionStatus: function(conn, obj) {
console.log("conn");
console.log(conn);
console.log("Strophe.Status");
console.log(Strophe.Status);
this.OnConnected(conn);
},
OnConnected: function(conn) {
console.log("OnConnected call");
//Callback fired when availability status of your's or your friends changes.
conn.addHandler(this.OnPresenceStanza, null, "presence");
//callback fired while receiving message
conn.addHandler(this.OnMessageStanza, null, "message");
//callback fired when a friend/authorize request is received
conn.addHandler(this.OnSubscribeStanza, null, "presence", "subscribe");
//callback when your friend/authorize request is responded by another user.
conn.addHandler(this.OnSubscribedStanza, null, "presence", "subscribed");
//send presence to all who have added you to their contact list i.e., send online status to other clients. We are sending "available" status
//conn.send($pres());
},
OnPresenceStanza: function(stanza) {
console.log("OnPresenceStanza call");
var sFrom = $(stanza).attr('from');
console.log("sFrom");
console.log(sFrom);
var sBareJid = Strophe.getBareJidFromJid(sFrom);
console.log("sBareJid");
console.log(sBareJid);
var sTo = $(stanza).attr('to');
console.log("sTo");
console.log(sTo);
var sType = $(stanza).attr('type');
console.log("sType");
console.log(sType);
var sShow = $(stanza).find('show').text();
console.log("sShow");
console.log(sShow);
//OnSubscribeStanza();
//OnSubscribeStanza();
//sendAuthorizeRequest();
sendMessage();
return true;
},
//callback is also fired when other user is typing or paused.
OnMessageStanza: function(stanza) {
console.log("OnMessageStanza call");
console.log(stanza);
var STo = $(stanza).attr('to');
console.log("to");
console.log(STo);
var sType = $(stanza).attr('type');
console.log("sType");
console.log(sType);
var sBareJid = Strophe.getBareJidFromJid(STo);
console.log("sBareJid");
console.log(sBareJid);
var sBody = $(stanza).find('body').text();
console.log("sBody");
console.log(sBody);
if (sBody) {
console.log("A Message Received: " + sBody + " From " + STo);
}
return true;
},
OnSubscribeStanza: function(stanza) {
console.log("OnSubscribeStanza call");
if (stanza.getAttribute("type") == "subscribe") {
var from_id = stanza.getAttribute("from");
console.log("from_id");
console.log(from_id);
//send back authorize request to accept it.
conn.send($pres({ to: from_id, type: "subscribed" }));
}
return true;
},
OnSubscribedStanza: function(stanza) {
console.log("OnSubscribedStanza call");
if (stanza.getAttribute("type") == "subscribed") {
var from_id = stanza.getAttribute("from");
//send back confirm authorize request.
conn.send($pres({ to: from_id, type: "subscribed" }));
}
return true;
},
//make a friend request
sendAuthorizeRequest: function() {
conn.send($pres({ to: "rahul#mailinator.com", type: "subscribe" }));
},
//disconnect from XMPP server
disconnect: function() {
console.log("connected disconnect");
conn.flush();
conn.sync = true;
conn.disconnect();
},
//send a message.
sendMessage: function(conn, msg) {
console.log("Friends call .....");
console.log("conn.jid");
console.log(conn.jid);
//return false;
var message = $msg({ to: "laxman#mailinator.com", from: conn.jid, type: "chat" }).c("body").t(msg);
conn.send(message.tree());
},
onMessage: function(message) {
console.log('service message = ');
console.log(message);
return true;
},
createAccount: function() {
conn = new Strophe.Connection("localhost");
conn.register.connect("localhost", OnConnectionStatus, 60, 1);
}
}
}
]);
}());
For testing, I have used static user for sending a message to Laxman in the server side file.
My main issue is that message can not broadcast to my friends.

Cordova.writefile function doesn't run, but doesn't give an error

I'm making an ionic application. I have a function called scope.win() that's supposed to fire when a quiz is finished, and then update the JSON file to add that quiz to the number of finished quizzes but it doesn't run properly.It doesn't give off any error. The function just stops running at a certain point and the app keeps going and nothing is happening.
This is the controller's file
angular.module('controllers', ['services'])
.controller('MainCtrl', function ($scope, $state, data) {
$scope.$on('$ionicView.enter', function () {
data.create();
});
$scope.chapter = data.chapterProgress();
})
.controller("BtnClick", function ($scope, lives, data, $cordovaFile, $ionicScrollDelegate) {
var live = 3;
var clickedOn = [];
var numQuestions;
$scope.part2Cred = false;
$scope.part3Cred = false;
$scope.part4Cred = false;
$scope.part5Cred = false;
$scope.part6Cred = false;
$scope.part7Cred = false;
$scope.part8Cred = false;
$scope.part9Cred = false;
$scope.part10Cred = false;
$scope.partQCred = false;
$scope.setNumQuestions = function(num){
numQuestions = num;
}
$scope.updatelives = function (){
//grabs the element that is called liv then updates it
var livesOnPage = document.getElementById('liv');
livesOnPage.innerHTML = live;
}
$scope.wrong = function (event){
var selec = document.getElementById(event.target.id);
if(clickedOn.includes(selec)){}
else{
selec.style.color = "grey";
clickedOn.push(selec);
live = live - 1;
if(live == 0){
$scope.gameover();
}
else{
$scope.updatelives();
}
}
}
$scope.right = function (event,chapter, section){
var selec = document.getElementById(event.target.id);
if(clickedOn.includes(selec)){}
else{
selec.style.color = "green";
clickedOn.push(selec);
numQuestions = numQuestions - 1;
if(numQuestions === 0){
$scope.win(chapter, section);
}
}
}
$scope.gameover = function(){
alert("game over please try again");
live = 3;
$ionicScrollDelegate.scrollTop();
$scope.partQCred = false;
$scope.part1Cred = !$scope.part1Cred;
for(i = 0; i< clickedOn.length;i++){
clickedOn[i].style.color = "rgb(68,68,68)";
}
}
$scope.win = function (chapter, section) {
alert("Well Done");
var data = data.chapterProgress(); // It is at this point that the //function stops running without giving off any error.
alert("Good Job");
var sectionsComplete = data[chapter].sectionsCompleted;
var totalsection = data[chapter].totalSections;
if (section === totalSection) {
window.location.href = "#/chapter1sections";
return;
}
if (section > sectionsComplete) {
data[chapter].sectionsCompleted += 1;
var url = "";
if (ionic.Platform.isAndroid()) {
url = "/android_asset/www/";
}
document.addEventListener('deviceready', function () {
$cordovaFile.writeFile(url + "js/", "chapters.json", data, true)
.then(function (success) {
// success
alert("Json file updated")
window.location.href = "#/chapter1sections";
}, function (error) {
// error
});
});
}
}
});
Here is the Services file. It seems to run fine but it is referenced a lot in the problematic sections of code in the controllers so I figured it was necessary to put it here.
angular.module('services', [])
.service('lives', function () {
var live = 3;
return {
getlives: function () {
return live;
},
setlives: function (value) {
live = value;
}
};
})
.service('data', function ($cordovaFile, $http) {
var url = "";
if (ionic.Platform.isAndroid()) {
url = "/android_asset/www/";
}
return {
//Run this function on startup to check if the chapters.json file exists, if not, then it will be created
create: function () {
var init = {
"one": {
"sectionsCompleted": 0,
"totalSections": 4
},
"two": {
"sectionsCompleted": 0,
"totalSections": 1
}
};
$cordovaFile.writeFile(url + "js/", "chapters.json", init, false)
.then(function (success) {
// success
}, function (error) {
// error
});
},
chapterProgress: function () {
return $http.get(url + "js/chapters.json").success(function (response) {
var json = JSON.parse(response);
return json;
}, function (error) {
alert(error);
});
}
}
});
Thank You so much for the help and time.

Call multiple web api using Angular js one by one

I have a scenario in which there is 8 web api's called as :
#1
Sync Local DB from server DB (response will RETURN a List=> myList)
If (myList.Length > 0)
#1.1 Call web Api to Insert/Update Local DB
#2
Sync Server DB from Local DB (Request goes with a List=> myList)
If (myList.Length > 0)
#2.1 Call web Api to Insert/Update in Server DB (Response will RETURN a List=> newList)
If(newList.length > 0)
#2.2 Call web Api to Insert/Update in Local DB
I have two separate process For Head and Head Collection tables which synced with above process. So there is #3 and #4 scenario is also present.
I have call web api in the following manner...
syncHeadDataLogic();
syncHeadCollectionDataLogic();
I need that Head data should be synced first then HeadCollection data synced. But if there is no updated record for head then Head collection executed.
In my scenario my web apis called in any order but i need a order as I have described above. Kindly suggest me how I achieved this.
#Updated
//Sync Head
$scope.initializeController = function () {
if ($scope.online) {
//debugger;
syncHeadDataLogic();
syncHeadCollectionDataLogic();
}
};
function syncHeadDataLogic() {
HeadService.HeadSyncLocalDB(parseInt(localStorage.headRevision, 10), $scope.completeds, $scope.erroe);
};
$scope.SynServerDBCompleted = function (response) {
debugger;
$scope.HeadListForSync = response.HeadList;
var tempHeadCurrencyDetail = [];
if ($scope.HeadListForSync.length > 0) {
angular.forEach($scope.HeadListForSync, function (xx) {
xx.CurrencyId = xx.CurrencyServerId;
xx.Id = xx.HeadServerId;
angular.forEach(xx.HeadCurrencyDetail, function (yy) {
yy.CurrencyId = yy.CurrencyServerId;
yy.HeadId = xx.HeadServerId;
if (yy.Revision == -1)
tempHeadCurrencyDetail.push(yy);
});
xx.HeadCurrencyDetail = tempHeadCurrencyDetail;
});
var postData = { Revision: parseInt(localStorage.headRevision, 10), HeadList: $scope.HeadListForSync };
HeadService.SynServerDB(postData, $scope.completed, $scope.erroe);
}
else {
// alertsService.RenderSuccessMessage("There is no change in data after your last synchronization.");
}
};
$scope.requestErrorwer = function (response) {
debugger;
};
$scope.completed = function (response) {
debugger;
if (response.RevisionNo == localStorage.headRevision) {
syncHeadCollectionDataLogic();
// alertsService.RenderErrorMessage("There is newer version on the server. Please Sync from server first.", "MessageAlert");
}
else {
syncData(response);
}
};
$scope.completeds = function (response) {
debugger;
if (response.RevisionNo == localStorage.headRevision) {
syncHeadCollectionDataLogic();
// alertsService.RenderSuccessMessage("You are already working on the latest version", "MessageAlert");
}
else {
syncData(response);
}
//
var request = new Object();
HeadService.getAllHeadForRevision(request, $scope.SynServerDBCompleted, $scope.requestErrorwer);
};
$scope.erroe = function (response) {
debugger;
// alertsService.RenderErrorMessage("Data Synchronization Failed", "MessageAlert");
};
function syncData(data) {
debugger;
$scope.ReturnedRevisonNo = data.RevisionNo;
if (data.HeadList && data.HeadList.length > 0) {
var postData = { Revision: $scope.ReturnedRevisonNo, HeadList: data.HeadList, HeadRevision: $scope.ReturnedRevisonNo };
HeadService.AddUpdateHeadAfterSync(postData, $scope.cmpSync, $scope.Error);
}
else {
syncHeadCollectionDataLogic();
}
};
$scope.cmpSync = function (response) {
debugger;
localStorage.headRevision = $scope.ReturnedRevisonNo;;
alertsService.RenderSuccessMessage("The synchronization has been completed successfully.");
syncHeadCollectionDataLogic();
};
$scope.Error = function (response) {
debugger;
// alertsService.RenderErrorMessage(response.ReturnMessage);
// alertsService.SetValidationErrors($scope, response.ValidationErrors);
};
////////////Sync End
//Sync Head Collection
function syncHeadCollectionDataLogic() {
HeadService.HeadSyncLocalCollectionDB(parseInt(localStorage.headCollectionRevision, 10), $scope.completedCollections, $scope.erroeCollection);
};
$scope.SynServerDBCompletedCollection = function (response) {
$scope.HeadCollectionListForSync = response.HeadCollectionList;
if ($scope.HeadCollectionListForSync.length > 0) {
angular.forEach($scope.HeadCollectionListForSync, function (value, index) {
value.Id = value.HeadCollectionServerId;
angular.forEach(value.HeadCollectionDetails, function (v) {
v.CommittedCurrencyId = v.CommittedCurrencyServerId;
v.HeadId = v.HeadServerId;
v.WeightId = v.WeightServerId;
v.HeadCollectionId = value.HeadCollectionServerId; //change
angular.forEach(v.HeadCollectionAmountDetails, function (xx) {
xx.CurrencyId = xx.CurrencyServerId;
});
});
});
var postData = { Revision: parseInt(localStorage.headCollectionRevision, 10), HeadCollectionList: $scope.HeadCollectionListForSync };
HeadService.SynServerCollectionDB(postData, $scope.completedCollection, $scope.erroeCollection);
}
else {
// alertsService.RenderSuccessMessage("There is no change in data after your last synchronization.");
}
};
$scope.requestErrorwerCollection = function (response) {
};
$scope.completedCollection = function (response) {
if (response.RevisionNo == localStorage.headCollectionRevision) {
// alertsService.RenderErrorMessage("There is newer version on the server. Please Sync from server first.", "MessageAlert");
}
else {
syncDataCollection(response);
}
};
$scope.completedCollections = function (response) {
if (response.RevisionNo == localStorage.headCollectionRevision) {
// alertsService.RenderSuccessMessage("You are already working on the latest version", "MessageAlert");
}
else {
syncDataCollection(response);
}
var request = new Object();
HeadService.getAllHeadCollectionForRevision(request, $scope.SynServerDBCompletedCollection, $scope.requestErrorwerCollection);
};
$scope.erroeCollection = function (response) {
// alertsService.RenderErrorMessage("Data Synchronization Failed", "MessageAlert");
};
function syncDataCollection(data) {
$scope.ReturnedRevisonNo = data.RevisionNo;
if (data.HeadCollectionList && data.HeadCollectionList.length > 0) {
var postData = { Revision: $scope.ReturnedRevisonNo, HeadCollectionList: data.HeadCollectionList, HeadRevision: $scope.ReturnedRevisonNo };
HeadService.AddUpdateaHeadCollectionAfterSync(postData, $scope.cmpSyncCollection, $scope.ErrorCollection);
}
};
$scope.cmpSyncCollection = function (response) {
localStorage.headCollectionRevision = $scope.ReturnedRevisonNo;;
alertsService.RenderSuccessMessage("The synchronization has been completed successfully.");
$scope.initializeController();
};
$scope.ErrorCollection = function (response) {
// alertsService.RenderErrorMessage(response.ReturnMessage);
// alertsService.SetValidationErrors($scope, response.ValidationErrors);
}
//End
I need that Head data should be synced first then HeadCollection data synced. But if there is no updated record for head then Head collection executed.
What you need is chained promises. Try this (I'm giving you pseudocode for now):
HeadService.HeadData
|-----------------|
HeadCollection(headDataResult)
|------------------|
finalHandler(headCollectionResult)
|------------------|
HeadService.HeadData()
.then(HeadService.HeadCollection) // return or throw Err if headDataResult is empty
.then(finalHandler);
Here, the order of execution of the promises will be predictable, and sequential. Also, each promise will be returned the resolved value of the previous promise
AngularJS as you can see in the documentation here, uses Promises out of the box with the $http injectable. You can define a factory like so:
// Factory code
.factory("SampleFactory", function SampleFactory($http) {
var sampleFactoryObject = {};
sampleFactoryObject.getSomething = function() {
return $http.get('/someUrl');
}
sampleFactoryObject.getSomething.then(function resolveHandler(res) {
return res;
},
function rejectHandler(err) {
throw new Error(err);
});
sampleFactoryObject.getSomethingElse = function() {
return $http.get('/someOtherUrl');
}
sampleFactoryObject.getSomethingElse.then(function resolveHandler(res) {
return res;
},
function rejectHandler(err) {
throw new Error(err);
});
return sampleFactoryObject;
});
// Controller code
.controller('myController', function myController(SampleFactory) {
SampleFactory.getSomething()
.then(SampleFactory.getSomethingElse())
.then(finalHandler);
var finalHandler = function(resultOfGetSomethingElse) {
console.log(resultOfGetSomethingElse);
}
});

Lookup function dependant on a $resource

I need a lookup function to be used throughout my application that gets additional data when provided with an id.
My attempt was to create a service:
angular.module("myApp")
.factory("userResource", function($resource) {
return $resource("/api/users");
})
.service("usernameLookup", function(userResource) {
var query = userResource.query(function (data) {
var users = data;
};
return function (userId) {
// EDIT
// How could I wait here until users is populated (and cached) the
// first time this function is used?
var user = { userId: 0, username: "Unknown user" }
for (var i = 0; i < users.leng;th; i++) {
if (users[i].id == userId)
{
user = users[i];
break;
}
}
return user;
};
})
.controller("pageCtrl", function(usernameLookup) {
var vm = this;
vm.userList = [
{ userId: 0 },
{ userId: 1 }
];
for (var i = 0; i < userList.length; i++)
{
userList[i].username = usernameLookup(userList[i].userId);
}
});
(Code compressed and de-minification-proofed for brevity)
I know this is wrong since the users array might not be populated when the actual lookup happens, but I don't know how to make sure it is.
Any suggestions?
Make the users variable part of the service function:
.service("usernameLookup", function(userResource) {
var users = [];
var query = userResource.query(function (data) {
users = data;
};
What I ended up doing was:
angular.module("myApp")
.factory("userResource", function($resource) {
return $resource("/api/users");
})
.factory("usernameLookup", function(userResource) {
return function (user) {
var users = userResource.query(function () {
for (var i = 0; i < users.length; i++) {
if (users[i].id == user.userId)
{
user.username = users[i].username;
break;
}
}
}
};
})
.controller("pageCtrl", function(usernameLookup) {
var vm = this;
vm.administratorsOrSomething = [
{ userId: 0 },
{ userId: 1 }
];
for (var i = 0; i < administratorsOrSomething.length; i++) {
usernameLookup(administratorsOrSomething[i]);
}
});
I'm guessing this is more the JavaScript/AngularJS spirit of things which isn't always obvious for a c/++/# guy.
A working example with mock resources, faked latency etc can be found here
The simplest solution might just be to use scope.$watch, updating the user list whenever it changes. If you find this distasteful (too many $watch expressions can get messy), you can create a userListPromise and only call your usernameLookup when the promise resolves. I can give more specific advice if you show me how the userList is populated, but these should be starting points.
Edit: I think I see what you want now. I still think your best option is to return a promise. I know that sounds like a pain, but it's really not that bad. Plus, when you're relying on web requests to get your data you really can't guarantee you won't end up with a 500 or 404 if the server explodes. A robust SPA needs to assume that any web request might not work. So here is a starting point; note that I don't handle the case when the query promise is rejected.
angular.module("myApp")
.factory("userResource", function($resource) {
return $resource("/api/users");
})
.service("usernameLookup", function(userResource, $q) {
var query = userResource.query(function (data) {
var users = data;
};
return function (userId) {
return query.$promise.then(function(users){
var user = { userId: 0, username: "Unknown user" }
for (var i = 0; i < users.leng;th; i++) {
if (users[i].id == userId)
{
user = users[i];
break;
}
}
return user;
});
};
})
.controller("pageCtrl", function(usernameLookup) {
var vm = this;
vm.userList = [
{ userId: 0 },
{ userId: 1 }
];
for (var i = 0; i < userList.length; i++)
{
userList[i].username = usernameLookup(userList[i].userId);
}
});

accessing items in firebase

I'm trying to learn firebase/angularjs by extending an app to use firebase as the backend.
My forge looks like this
.
In my program I have binded firebaseio.com/projects to $scope.projects.
How do I access the children?
Why doesn't $scope.projects.getIndex() return the keys to the children?
I know the items are in $scope.projects because I can see them if I do console.log($scope.projects)
app.js
angular.module('todo', ['ionic', 'firebase'])
/**
* The Projects factory handles saving and loading projects
* from localStorage, and also lets us save and load the
* last active project index.
*/
.factory('Projects', function() {
return {
all: function () {
var projectString = window.localStorage['projects'];
if(projectString) {
return angular.fromJson(projectString);
}
return [];
},
// just saves all the projects everytime
save: function(projects) {
window.localStorage['projects'] = angular.toJson(projects);
},
newProject: function(projectTitle) {
// Add a new project
return {
title: projectTitle,
tasks: []
};
},
getLastActiveIndex: function () {
return parseInt(window.localStorage['lastActiveProject']) || 0;
},
setLastActiveIndex: function (index) {
window.localStorage['lastActiveProject'] = index;
}
}
})
.controller('TodoCtrl', function($scope, $timeout, $ionicModal, Projects, $firebase) {
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
var keys = $scope.projects.$getIndex();
console.log($scope.projects.$child('-JGTmBu4aeToOSGmgCo1'));
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("" + keys[0]);
});
// A utility function for creating a new project
// with the given projectTitle
var createProject = function(projectTitle) {
var newProject = Projects.newProject(projectTitle);
$scope.projects.$add(newProject);
Projects.save($scope.projects);
$scope.selectProject(newProject, $scope.projects.length-1);
};
// Called to create a new project
$scope.newProject = function() {
var projectTitle = prompt('Project name');
if(projectTitle) {
createProject(projectTitle);
}
};
// Called to select the given project
$scope.selectProject = function(project, index) {
$scope.activeProject = project;
Projects.setLastActiveIndex(index);
$scope.sideMenuController.close();
};
// Create our modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope
});
$scope.createTask = function(task) {
if(!$scope.activeProject || !task) {
return;
}
console.log($scope.activeProject.task);
$scope.activeProject.task.$add({
title: task.title
});
$scope.taskModal.hide();
// Inefficient, but save all the projects
Projects.save($scope.projects);
task.title = "";
};
$scope.newTask = function() {
$scope.taskModal.show();
};
$scope.closeNewTask = function() {
$scope.taskModal.hide();
};
$scope.toggleProjects = function() {
$scope.sideMenuController.toggleLeft();
};
// Try to create the first project, make sure to defer
// this by using $timeout so everything is initialized
// properly
$timeout(function() {
if($scope.projects.length == 0) {
while(true) {
var projectTitle = prompt('Your first project title:');
if(projectTitle) {
createProject(projectTitle);
break;
}
}
}
});
});
I'm interested in the objects at the bottom
console.log($scope.projects)
Update
After digging around it seems I may be accessing the data incorrectly. https://www.firebase.com/docs/reading-data.html
Here's my new approach
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
console.log(snapshot.val()['-JGTdgGAfq7dqBpSk2ls']);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
I'm still not sure how to traverse the keys programmatically but I feel I'm getting close
It's an object containing more objects, loop it with for in:
for (var key in $scope.projects) {
if ($scope.projects.hasOwnProperty(key)) {
console.log("The key is: " + key);
console.log("The value is: " + $scope.projects[key]);
}
}
ok so val() returns an object. In order to traverse all the children of projects I do
// Load or initialize projects
//$scope.projects = Projects.all();
var projectsUrl = "https://ionic-guide-harry.firebaseio.com/projects";
var projectRef = new Firebase(projectsUrl);
projectRef.on('value', function(snapshot) {
if(snapshot.val() === null) {
console.log('location does not exist');
} else {
var keys = Object.keys(snapshot.val());
console.log(snapshot.val()[keys[0]]);
}
});
$scope.projects = $firebase(projectRef);
$scope.projects.$on("loaded", function() {
// Grab the last active, or the first project
$scope.activeProject = $scope.projects.$child("a");
});
Note the var keys = Object.keys() gets all the keys at firebaseio.com/projects then you can get the first child by doing snapshot.val()[keys[0])

Resources