2

I'm building an application in Angular with Firebase and one aspect of it is one-to-one chat. I'm querying Firebase to see if a chat room exists already between the user currently accessing the application and the user they are attempting to chat with. If it exists, I am trying to apply that room to the scope as the selected room. I'm using "Messages" service to run the query.

this.roomQuery = function(user1ID, user2ID) {
  roomsRef.orderByChild("user1").equalTo(user1ID).on("child_added", function(snapshot) {

    if (snapshot.val().user2 == user2ID) {
      self.selectedRoom = snapshot.key();
      console.log(self.selectedRoom);
    } else {
      self.selectedRoom = null;
    }


  })
}

and in my controller I am using:

$scope.$watch(
    function(){ return Messages.selectedRoom },

    function(newValue, oldValue) {
      $scope.selectedRoom = newValue;
    }
    )

This $scope.$watch method has worked for me with everything else and it seems to sometimes work in this case. The console log always prints out the correct value for Messages.selectedRoom, but the $scope.selectedRoom sometimes does not update. Any idea what is happening here? I'm very confused. If it's logging to the console properly, shouldn't it be updated in the scope?

David East
  • 31,526
  • 6
  • 67
  • 82
cassiusclay
  • 376
  • 1
  • 5
  • 19
  • I figure this has something to do with the Firebase data being loaded asynchronously, but I don't understand why Messages.selectedRoom would be updated in the service and not in the scope due to the watch. Should I be using `$loaded` in some fashion? – cassiusclay Dec 06 '15 at 22:52
  • If you always want the same two users to end up in the same room together, you can also consider basing the room name on the uids of those two users. The advantage of that approach is that you don't need to do a query to look up the room: the same users end up in the same room automatically. See this answer for an explanation of that concept: http://stackoverflow.com/questions/33540479/best-way-to-manage-chat-channels-in-firebase/33547123#33547123 . – Frank van Puffelen Dec 07 '15 at 00:47

2 Answers2

1

Angular's $digest is unaware of when a your Firebase query completes. You might find it easier to use AngularFire in this case.

this.roomQuery = function(user1ID, user2ID) {
  var query = roomsRef.orderByChild("user1").equalTo(user1ID);
  return $firebaseObject(query).$loaded();
};

this.roomQuery("1", "2")
  .then(function(data) {
    // do your check here
  });

The $firebaseObject() takes in a ref or a query and knows when to call digest on your behalf.

You might want to check out using resolve in the router to inject the roomQuery into the router, since it returns a promise with .$loaded().

David East
  • 31,526
  • 6
  • 67
  • 82
0

David got me to the solution I needed. For anyone with a similar issue, here is how I implemented it:

this.roomQuery = function(user1, user2) {
  var query = roomsRef.orderByChild("user1").equalTo(user1ID)

  return $firebaseArray(query).$loaded();
}

I used $firebaseArray instead of Object and in my controller:

$scope.getRoom = function() {
    Messages.roomQuery($scope.user1.id, $scope.user2.$id).then(function(data)
    {
      $scope.data = data;
      for(var i=0, len = data.length; i < len; i++){
        if (data[i].user2 == $scope.user2.$id) {
          $scope.selectedRoom = data[i].$id;
        }
      }
    }
    )
  }

Apologies for the variable names being a little confusing. I altered them for the sake of this post.

cassiusclay
  • 376
  • 1
  • 5
  • 19