Phil_Smith Phil_Smith - 4 months ago 15
Javascript Question

AngularJS & Socket.IO - Return value from Service (emit here) to Controller is undefined || promises, asynchronicity

I don't get my code to work properly.

I'm developing an app with AngularJS including a connection to a backend server via socket.io. I'm working on a login which is intended to send an user's data to the server. The server is intended to respond with "valid" and the user's data (name, dateOfBirth, ...) if the sent data is correct (email and password). Elements are:


  • BackendService (Factory which executes emit to server)

  • AppController (Controller which calls the login function of BackendService)

  • Node.js Server (computes if the sent data is valid so that the user can be logged in)



The intention is that the login function in the Factory returns a "login code" which tells the controller if the login is correct. Unfortunately the function returns "undefined". During my research, I found out that it might be because of asynchronicity and promises. However, I couldn't apply the given information to my problem as the majority was about $http. In addition - if the structure of my code is in need of improvement, let me know!

Here's my code:

Node.js Server

socket.on('logincust', function (p1, fn) {
connection.query("SELECT Salt FROM Customer WHERE Email = ?", [p1.Email], function (err, data, fields)
{
if (err) {
throw err;
}
if (data.length > 0) {
var hash = crypto.createHash('sha256').update(p1.Password + data[0].Salt).digest('base64');
connection.query("SELECT LName,FName,Email,Telephone,Address,DateOfBirth FROM Customer WHERE Password = ?", [hash], function (err, data2, fields) {
if (err) {
throw err;
}
if (data2.length > 0) {
fn('valid', data2[0]);
}
else {
fn('invalidpassword', 'nodata')
}
})
}
else {
fn('invalidemail','nodata')
}
})
})


BackendService (Factory)

"use strict";

mobileClientApp.factory('BackendService', function() {

var mySocket = io.connect('http://thisLinkIsPrivate:8888/ns');

return {

login: function (pUserData) {
if (mySocket.connected) {
mySocket.emit('logincust', pUserData, function (resp, data) {

if (resp == "valid") {

var parsedData = JSON.stringify(data);
console.log(parsedData);

user.lName = parsedData.LName; // Fill userData
user.fName = parsedData.FName;
user.email = parsedData.Email;
user.phoneCallcenter = parsedData.Telephone;

console.info("Login successful.");

return 0;
}
else {
if (resp == "invalidpassword") {
return 1;
}
else if (resp == "invalidemail") {
return 2;
}
}
});
}
else { // Socket is not connected
console.warn("Socket not connected.);
user.fName = "Peter";
user.lName = "Offline";
return -1;
}
};


Angular Controller

$scope.doLogin = function() {

var user = {'Email': this.loginData.username, 'Password': this.loginData.password};
var isLoggedIn = BackendService.login(user); // 0 - logged in, 1 - invalid password, 2 - invalid email, -1 - socket not connected

console.log("BackendService.login(user): " + BackendService.login(user)); // is undefined!

console.log("isLoggedIn: " + isLoggedIn); // undefined!

if (isLoggedIn == 0 || isLoggedIn == -1) {

$location.path('/app/landing');
}
else {
$scope.errorMessage = "Invalid login data!";
}
};

Answer Source

Yes, the problem seems to be asynchrony. If you want to have access to results from login method you should pass a callback to it. Since after you called it, the next execution will be your console log and that will happen before your SQL query returns results.