1

I'm writing a web application with a message feature.

A Conversation in my app is defined as between 2 distinct users. For example if Adam had just created a profile and sent 1 message to Jane and a 3 messages to Jack. He would have 2 Conversations but 4 Messages total.

In the following code on Express side, I'm attempting to retrieve all the Conversations for a given user in the database. Once this is completed, send this data to the Angular controller side. What's the correct way to do this in api.js below, taking into account that JS is asynchronous?

public/javascripts/main_controller.js

var mainApp = angular.module('myApp', ['ngRoute', 'btford.socket-io', 'xeditable']);
...
mainApp.controller('MessagesController', function($scope, $http, userSessionService, socket, focus){
  console.log("MessagesController running");
  $scope.messageDisplay = '';
  $scope.username = userSessionService.getUserSession().username;

  $http({
      url: '/loadConversations', 
      // url: '/about', 
      method: "GET"
    })
    .success(function(response) {
      console.log("success with loadConversations: ", response);
      console.log(response[0].data);
    });
....
})

routes/api.js:

....

router.route('/loadConversations')
.get(isAuthenticated, function(req, res) {
var result = [];
  //Find Conversation with each and all distinct users
  for(var i = 0; i < req.user.conversations.length; i++){
Conversation.findOne({'_id': req.user.conversations[i]}, function(err, conversation){
  if(err){
    console.log(err);
  }
  if(conversation){
    var contactUsername = (conversation.initiatorUsername == req.user.username) ? conversation.responderUsername : conversation.initiatorUsername;
    var lastMessage = conversation.messages[conversation.messages.length-1].content;
    var dateOfMessage = conversation.messages[conversation.messages.length-1].date;
    var resultJSON = {contactUsername: contactUsername,
                            lastMessage: lastMessage,
                            dateOfMessage: dateOfMessage};
    result.push(resultJSON);

  } else {
    console.log("conversation not found!");
  }
  //Below is not working, where should I put res.json(result)?
  // if(result.length == req.user.conversations.length){
  //   res.json(result);
  // }
});

} });

jerryh91
  • 1,777
  • 10
  • 46
  • 77

1 Answers1

0

I'm not sure you even asked for this, but I think you should slightly rewrite your controller code.

In this example, a promise is being returned after$http(...). Instead of using .success I would recommend using .then. It's important to understand the difference between the two so I'll try to explain briefly. Here's the .success() method in angular source code:

promise.success = function(fn) {
// ...
promise.then(function(response) {
    fn(response.data, response.status, response.headers, config);
});
    return promise;
};

and here is their official documentation

.success the same as the .then except success will take the first argument of the successful call result, so you wouldn't have to write out response.data. It's sort of convenient, but if you ever use caching or want to chain other promises off of this it becomes a pain in the ass. Here's my alternative for you.

$http({
  url: '/loadConversations', 
  // url: '/about', 
  method: "GET"
})
.then(function(response) {
  // this is your success callback
  console.log("success with loadConversations: ", response);
  console.log(response[0].data);
}, function(error) {
  // if the service call doesnt return 200, we fire this
  console.log(error); 
});

This console log will be executed asynchronously in this implementation, and will be easier to maintain than using .success would be.

EDIT: for the routes/api.js, I think you just need to return the results array

if(result.length == req.user.conversations.length){
  return result;
}
Haymaker87
  • 519
  • 7
  • 18