The Project
Chatterbox is a chatroom application that updates in realtime through the use of Angular and Firebase.
Tools
Javascript, Angular, UI-Router, jQuery, Firebase, AngularFire, Grunt, ngCookies, Bootstrap, Brackets, Ubuntu
The App
Upon loading the app for the first time, the user is prompted to enter a username. From there, they may click to enter any of the chatrooms listed in the left navbar to see messages for that room. Upon closing and/or reloading the page, cookies ensure the user remains logged in1 as their chosen username.
Process
The first task was to set up my Firebase database and associated service for facilitating CRUD operations. Using my RoomSrv
service, I was able to push new rooms to the database, as well as pull down an array of all available Rooms.
To allow users to create new chat rooms, I created a button to trigger a modal input box to appear, allowing users to name and create new chat rooms. This was accomplished using UI Bootstrap’s $uibModal
service.
Upon receiving user input, an $emit
and corresponding $on
function are used to facilitate communication between the ModalCtrl
and RoomCtrl
Controllers.
function ModalCtrl($scope, $uibModal){
...
modalInstance.result.then(
function(roomName){
$scope.$emit('createNewRoom', roomName);
}
);
};
}
}
function RoomCtrl($scope, RoomSrv, $cookies, $window){
...
$scope.$on('createNewRoom', function(event, args){
$scope.addRoom({name: args});
});
...
};
The next step was to allow messages to be posted in chat rooms. Upon creation, each message object was set up to be associated with the currently selected room via its $id
autogenerated by Firebase.
(function(){
function MessageCtrl($scope, MessageSrv, $cookies){
$scope.send = function(){
if($scope.messageContent !== ''){
MessageSrv.addMessage(
{
content: $scope.messageContent,
roomID: $scope.selectedRoom.$id,
sentAt: 'default',
username: $cookies.get('currentUser')
}
);
$scope.messageContent = '';
}
}
}
angular
.module('chatterBox')
.controller('MessageCtrl', ['$scope', 'MessageSrv', '$cookies', MessageCtrl]);
})();
Retrieving the messages to render to the view involves some unorthdox syntax, which was initially confusing:
RoomSrv.getMessages = function(id){
return $firebaseArray(firebaseRef.child('messages')
.orderByChild('roomID')
.equalTo(id));
}
Understanding this statement involves looking at the return types of each function. .child()
returns a Firebase reference to the object containing all messages. orderByChild()
returns a Query
with all messages ordered by roomID
. Finally equalTo()
filters the Query down further to only those messages with a matching roomID
. Finally $firebaseArray()
converts the final query into an array to be rendered to the View.```
What is peculiar is that the 2nd statement seems to both reorder the array 2 of results and passes a new array, with equalTo()
receiving the key to compare id
against. I can only assume that this was coded this way for some purpose such as optimization, but I would think retrieving queries using key/value pairs would make more sense:
var ref = firebaseRef.child('messages');
return $firebaseArray(ref[roomID][id]);
Nonetheless, with the display of messages and rooms out of the way, the next step was to set up Users. Upon loading the page for the first time, users are greeted with a Modal prompt asking for a username. This username is stored in a cookie using the ngCookies
service. To make this step manditory, the code the preventDefault()
function is used to prevent the Modal from being dismissed the the input field is empty.
$scope.$on('modal.closing', function(event, reason, closed){
if($scope.userName === ''){
event.preventDefault();
}
})
Finally, I added functionality to MessageCtrl
to allow users to post new messages into chat rooms associated with their username.
Outcome
This was a fairly straightforward project, and for me gave me a taste having a Frontend interacting with a non-Rails backend. Tripping up on the terminology for retrieving a message was a bit confusing, but appears to be relatively common with web development, as I have discovered. Given the diversity of toolsets and the “hacks” required in order to optimize functionality for a live web app, I have come to expect some things to initially defy conventional comprehension.
Annotations
1 Chatterbox uses only a rudimentary user system, not a complex system of authentication. This was done to limit the scope of the project to only its most valuable features.
2 Not a true Array, of course, but an object behaving as one in this context.