0

I am developing my app, and one of the features will be messaging within the application. What I did, is I've developed 'send message' window, where user can send message to other user. The logic behind it is as following:
1. User A sends message to User B.
2. Firebase creates following nodes in 'Messaging':
"Messaging"->"User A"->"User B"->"Date & Time"->"UserA: Message"
"Messaging"->"User B"->"User A"->"Date & Time"->"UserA: Message"

Here is the code that I am using for sending messages:

  sendMsg: function(receiver, content) {
    var user = Auth.getUser();
    var sender = user.facebook.id;
    var receiverId = receiver;
    var receiverRef = $firebase(XXX.firebase.child("Messaging").child(receiverId).child(sender).child(Date()));
    var senderRef = $firebase(XXX.firebase.child("Messaging").child(sender).child(receiverId).child(Date()));
    receiverRef.$set(sender,content);
    senderRef.$set(sender,content);
  },

(picture 1 in imgur album)

At the moment, I am trying to read the messages from the database, and sort them in according to date. What I've accomplished so far, is that I have stored the content of "Messaging/UserA/" in form of an Object. The object could be seen in the picture I've attached (picture 2).

http://imgur.com/a/3zQ0o

Code for data receiving:

getMsgs: function () {
    var user = Auth.getUser();
    var userId = user.facebook.id;
    var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
    var Messages = messagesPath.child(userId);
    Messages.on("value", function (snapshot) {
      var messagesObj = snapshot.val();
      return messagesObj;
    }, function (errorObject) {
      console.log("Error code: " + errorObject.code);
    });
  }

My question is: how can I read the object's messages? I would like to sort the according to the date, get the message and get the Id of user who has sent the message.

Thank you so much!

uksz
  • 16,691
  • 26
  • 76
  • 142
  • Can you add the relevant code of what you've already tried? Firebase's guide for AngularFire should contain enough information to at least get you started: https://www.firebase.com/docs/web/libraries/angular/guide/ – Frank van Puffelen Mar 17 '15 at 14:25
  • Hey Frank! Thanks for your answer and suggestions. I've added the code I have so far to the original post. So far I have one view in which user is able to send a message to another user (using their FB id). I am planning to add two more view: the list view (similar to what we see in Fb Messanger list), and chat view. In the list view, I want to list all the users with whom we chatted and the latest message sent. In the chat view, I want to include the standard chat view: left hand side the respondent messages with Profile picture from facebook, and right-hand-side belongs to users messages. – uksz Mar 17 '15 at 15:10
  • It's hard to tell what's going on in your code sample. Could you reproduce the issue in JSBin/Plunkr and share the link? Also, it looks like you're using a pre 1.0 version of AngularFire. I would suggest looking at the most recent version. – David East Mar 17 '15 at 16:04

1 Answers1

2

You seem to be falling for the asynchronous loading trap when you're reading the messages:

getMsgs: function () {
    var user = Auth.getUser();
    var userId = user.facebook.id;
    var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
    var Messages = messagesPath.child(userId);
    Messages.on("value", function (snapshot) {
      var messagesObj = snapshot.val();
      return messagesObj;
    }, function (errorObject) {
      console.log("Error code: " + errorObject.code);
    });
  }

That return statement that you have in the Messages.on("value" callback doesn't return that value to anyone.

It's often a bit easier to see what is going on, if we split the callback off into a separate function:

onMessagesChanged(snapshot) {
    // when we get here, either the messages have initially loaded 
    // OR there has been a change in the messages
    console.log('Inside on-value listener');
    var messagesObj = snapshot.val();
    return messagesObj;
},
getMsgs: function () {
    var user = Auth.getUser();
    var userId = user.facebook.id;
    var messagesPath = new Firebase("https://xxx.firebaseio.com/Messaging/");
    var Messages = messagesPath.child(userId);
    console.log('Before adding on-value listener');
    Messages.on("value", onMessagesChanged);
    console.log('After adding on-value listener');
  }

If you run the snippet like this, you will see that the console logs:

Before adding on-value listener
After adding on-value listener
Inside on-value listener

This is probably not what you expected and is caused by the fact that Firebase has to retrieve the messages from its servers, which could potentially take a long time. Instead of making the user wait, the browser continues executing the code and calls your so-called callback function whenever the data is available.

In the case of Firebase your function may actually be called many times, whenever a users changes or adds a message. So the output more likely will be:

Before adding on-value listener
After adding on-value listener
Inside on-value listener
Inside on-value listener
Inside on-value listener
...

Because the callback function is triggered asynchronously, you cannot return a value to the original function from it. The simplest way to work around this problem is to perform the update of your screens inside the callback. So say you want to log the messages, you'd do:

onMessagesChanged(snapshot) {
    // when we get here, either the messages have initially loaded 
    // OR there has been a change in the messages
    console.log('Inside on-value listener');
    var i = 0;
    snapshot.forEach(function(messageSnapshot) {
        console.log((i++)+': '+messageSnapshot.val());
    });
},

Note that this problem is the same no matter what API you use to access Firebase. But the different libraries handle it in different ways. For example: AngularFire shields you from a lot of these complexities, by notifying AngularJS of the data changes for you when it gets back.

Also see: Asynchronous access to an array in Firebase

Community
  • 1
  • 1
Frank van Puffelen
  • 418,229
  • 62
  • 649
  • 645
  • Thats great! Once I get back from work I will work on that, and I will let you know the result! Thanks again! – uksz Mar 17 '15 at 17:13