/ Angular

Firebase and Angular - The IM App

Lirt -- Learning in real time

I'm pretty much going to go through a play-by-play of my first impressions and learning process playing with Firebase. I saw a demo on it a year ago or so and have never got around to playing with it. I wanted to make a real-time chat app to use with friends just for fun and figured may as well start here.

PSA!! :

This is not a tutorial! Enter my mind at your own risk! This is pretty much how straight forward my thoughts are when learning something new. I jump around a lot, spew out random ideas, change my mind part way through, make fun of my terrible schema ideas. The limits are endless.

Firebase!

Heading over to firebase.com. Registration via google oauth (because why not). Up and running in legitimately no time.

Checking out this quickstart application...
https://www.firebase.com/tutorial/#tutorial/angular/0

A chat application! Go Figure -- how's that for relief. I guess I'll just make it more difficult and see if I can figure out how to change lobbies etc. Maybe force some validation or something?

To get this up and running using my npm and bower stuff...
cd /Projects/angular-firebase-chatter npm init

//spam enter

npm install --save http-server touch index.html

To get this thing up and running in a super easy fashion : add a start script to package.json. All my standalone develop apps use http-server so I'm not going to deviate here. In package.json under scripts add:

"start": "http-server -a localhost -p 8000 -c-1"

Now run npm start and you're up and running with a blank page on http://localhost:8000

Here is where I'm going to just go through the firebase 5min tutorial and put their code into my index.html. This next section is 100% from the link I provided earlier.

<!doctype html>
<html ng-app="myApp">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
    <script src="https://cdn.firebase.com/js/client/2.2.1/firebase.js"></script>
    <script src="https://cdn.firebase.com/libs/angularfire/1.0.0/angularfire.min.js"></script>
    <link rel="stylesheet" href="/resources/tutorial/css/example.css"/>
  </head>

  <body ng-controller="MyController">

    <!-- CHAT MARKUP -->
    <div class="example-chat l-demo-container">
      <header>Firebase Chat Demo</header>

      <div class="example-chat-toolbar">
        <label for="nameInput">Username:</label>
        <input ng-model="name" type="text" id="nameInput" placeholder="enter a username...">
      </div>

      <ul id="example-messages" class="example-chat-messages">
        <li ng-repeat="msg in messages">
          <strong class="example-chat-username">{{ msg.from }}</strong>
          {{ msg.body }}
        </li>
      </ul>

      <footer>
        <input ng-model="msg" ng-keydown="addMessage($event)" type="text" id="messageInput"  placeholder="Type a message...">
      </footer>
    </div>

    <script>
      var myApp = angular.module("myApp", ["firebase"]);

      myApp.controller("MyController", ["$scope", "$firebaseArray",
        function($scope, $firebaseArray) {
          //CREATE A FIREBASE REFERENCE
          var ref = new Firebase("https://h3ggyb3rnii.firebaseio-demo.com/");

          // GET MESSAGES AS AN ARRAY
          $scope.messages = $firebaseArray(ref);

          //ADD MESSAGE METHOD
          $scope.addMessage = function(e) {

            //LISTEN FOR RETURN KEY
            if (e.keyCode === 13 && $scope.msg) {
              //ALLOW CUSTOM OR ANONYMOUS USER NAMES
              var name = $scope.name || "anonymous";

              //ADD TO FIREBASE
              $scope.messages.$add({
                from: name,
                body: $scope.msg
              });

              //RESET MESSAGE
              $scope.msg = "";
            }
          }
        }
      ]);
    </script>
  </body>
</html>

Alright. There's a spot in there where you're supposed to put your url. I'm going to denounce it MAGIC_URL. so you can put your own stuff in there

So I'm going to create a variable called MAGIC_URL = ''; and reference it when we make a new firebase instance.

...
var MAGIC_URL = '';
var ref = new Firebase(MAGIC_URL);
$scope.messages = $firebaseArray(ref);
...

Now, I mean.. this thing is pretty much doing what I originally intended to set out and make. This was brutally efficient. My original plan was to use socket.io and couchdb to make this go. The websocket subscription with Firebase takes away any requirement to implement your own socket.io system. However, I'm curious about querying. I'm going to go ahead and make some design calls to my database and add in what I think could be a neat way to make a messaging app with multiple lobbies. I'm just going to let the user choose their lobby which means we could really have any number of available lobbies.

The plan:

{
  lobbies:{
    [lobby_name]:{
      messages:[
        {
          content:[string],
          from:[string],
          timestamp:[number]
        }
      ]
    }
  }
}

Pros: Straight to the point structure of the application.
Cons: So not typical RDMS. Firebase is a nosql database so this could work, minimal organization. I could see maintenance of this schema being chaotic.

  • How does one query in this thing? //parses docs --> No idea.
  • CouchDB Views!!@! MongoDb Queryies!!@! mapreduce? I'm so confused and not dealing with this right now. I'm going to just smash out my bad design.

Whatever. I'm going to just jump into it. I've got a very clear goal here and I'm planning on accomplishing it within the hour.

What do I need?
1: A lobby variable on the screen. Probably beside the username
2: A mechanism for updating my Firbease reference for the lobbies
3: Resetting my messages.

Here's what I'm doing:

index.html:

...
  <div class="example-chat-toolbar">
        <label for="nameInput">Username:</label>
        <input ng-model="name" type="text" id="nameInput" placeholder="enter a username...">
      </div>
      <div class="example-chat-toolbar">
        <label for="lobbyInput">Lobby:</label>
        <input ng-model="lobby" type="text" id="lobbyInput" placeholder="Choose a Lobby" ng-blur="changeLobby(lobby)">
      </div>
...

I thought of doing a $scope.$watch here but I didn't feel like handling a ng-debounce for delaying the trigger. ng-blur seemed asd though it would be good enough for me here. Instead I added a function called changeLobby and will call it once the user changes focus from the lobby to the messages section. I'm also

$scope.changeLobby = function(l){
  //Connect to a new lobby
  ref = new Firebase(MAGIC_URL+"/lobbies/"+l+"/messages");
  $scope.messages = $firebaseArray(ref);
}

Seriously. This works. Run the application and join the lobby Adele fans and start blasting out the lyrics to Hello. Then quickly switch to the pink floyd lobby and start blasting out some 'Is there anybody out there' so your friends don't judge you too hard.

You remember me saying that I wanted to add some timestamps and stuff to my messages. I guess that I should do that first. In the $scope.addMessage function, go ahead and rebuild the $scope.messages.$add function. I removed the message to make it easier to view, but that's just my style.

$scope.addMessage = function(e){
...
var name = $scope.name || "anonymous";
var message = {
  from: name,
  content: $scope.msg,
  timestamp: newDate().getTime()
};
$scope.messages.$add(message);

...
}

This is pretty much it. I wanted to make a chat app with multiple lobbies and here it is. That was literally 25 minutes worth of work and my job pays me to do stuff other than just learn so I should really get back to it! This just goes to show how simple or difficult your tasks can be depending on whether or not you're using the right tool for the job. I may come back later and add in some information on securing the database because the console keeps giving me a red ! for it but I have 0 idea how to go about it.

Keep in mind : I'm confident that this is not a good design but it got the job done. This is not secured at all and is pretty much just waiting for trolls to ruin your day.

Here's a GIST with the completed app:

Cheers, friends

Keep coding!