clone

I recently discovered Firebase, and it’s changed everything.

If you haven’t heard of it, Firebase is a platform that allows you to store and sync data in realtime. It essentially gives you the functionality of a backend database, but presented in a much simpler format, as it is NoSQL, and only using front-end code.

You can create some surprisingly complex applications with it, so I decided to try and make something myself.
I am relatively a beginner with both AngularJS and Firebase, so I settled on making something simple, a clone of Designer News.

building a designer

You can actually see and use the application here, and view the code on github.

 

Project Overview

Although I can’t go through the entire application, I will share how I organised the data, and how some specific actions were handled.

 

The Data Structure

The structure of the data is incredibly important, and I spent a while trying to figure out the best way to do it so that I would have access to all the relevant data from certain controllers. In the end, I grouped the data into two main arrays – stories and users.

Each user in the user array has the following data –

- first_name
- last_name
- title
- email
- id (uid from Firebase login via email)
- karma
- posts
    - post
      - title
      - date
      - id (Firebase key for post under "stories" array)
- comments
    - comment
      - title (post title)
      - id (Firebase key for post under "stories" array)
      - date
      - comment (the text)

 

Each story in the stories array has the following data –

- title
- date
- url (null if description post)
- description (null if url post)
- category
- voteCount
- commentCount
- voters (an array with uid of each person who has voted on the post)
- comments
  - comment
      - date
      - text
      - voteCount
      - user
        - first_name
        - last_name
        - title
        - id (Firebase key for the user)
        - uid (uid from Firebase login via email)
      - voters (an array with uid of each person who has voted on the comment)

 

Creating a user

Creating a user is relatively simple with Firebase. There is a built in email and password authentication service, which handles everything for you. Creating a new user is as simple as writing –

var ref = new Firebase(FIREBASE_URL);

// Passing a "user" object
ref.createUser({  
  email: user.email,
  password: user.password
})

 

When the user is created, they are given a token, the “uid”. Along with the other information given by the user, I pass in the “uid” to a new user in the users array.

var ref = new Firebase(FIREBASE_URL + '/users');  
var users = $firebaseArray(ref);

// Passing a "user" object
users.$add({  
  uid: uid,
  first_name: user.first_name,
  last_name: user.last_name,
  title: user.title,
  email: user.email,
  karma: 0
});

 

This creates a connection between the user created by the Firebase authentication service, which is referenced by the uid, and the user in the users array, which is referenced by the array key.

When a user is created, we can check for the current user by looping through the users array and finding the user with the same uid as the current authorised user –

auth.$onAuth(function(authUser) {

  if (authUser) {

    users.$loaded().then(function(){
      angular.forEach(users, function(user) {
        if (user.uid == authUser.uid) {
          $rootScope.currentUser = user;
        }
      }); // end loop
   }); // end users.$loaded

  } // end if  

});

 

Adding a new story

When adding a new story, I had to make sure that I added the details to the “stories” array, but also to the story author’s posts in the “users” array.

Adding a new url story looked roughly like this –

var ref = new Firebase(FIREBASE_URL + '/stories');  
var stories = $firebaseArray(ref);

var userRef = new Firebase(FIREBASE_URL + '/users/' + $rootScope.currentUser.$id + '/posts');  
var thisUser = $firebaseArray(userRef);

$scope.addStory = function(story) {

  // Checks for errors go here

  // If no errors
  stories.$add({
    title: story.title,
    url: story.url,
    category: storyCategory, // custom function used to get category
    description: null,
    date: Firebase.ServerValue.TIMESTAMP,
    user: {
      first_name: $rootScope.currentUser.first_name,
      last_name: $rootScope.currentUser.last_name,
      title: $rootScope.currentUser.title,
      uid: $rootScope.currentUser.uid,
      id: $rootScope.currentUser.$id
    },
    commentCount: 0,
    voteCount: 0
  }).then(function(ref){

    thisUser.$add({
      title: story.title,
      date: Firebase.ServerValue.TIMESTAMP,
      id: ref.key()
    })

  });

}

 

Voting

The voting system, although a relatively small part of the application, had a lot of moving parts. It worked like this –

  • Check if user has voted by looping through the array of voters
  • If has voted, stop here
  • If not, allow voting
    • Add 1 to current voteCount
    • Add the current user to the list of voters on the post
    • Add 1 to the story author’s karma

 

$scope.upvote = function(story) {

  var thisStoryRef = new Firebase(FIREBASE_URL + '/stories/' + story.$id);
  var thisStory = $firebaseObject(thisStoryRef);

  var votersRef = new Firebase(FIREBASE_URL + '/stories/' + story.$id + '/voters');
  var voters = $firebaseArray(votersRef);

  var hasVoted = false;

  // Check if user has voted by looping through the array of voters
  voters.$loaded().then(function() {
    angular.forEach(voters, function(object, id) {
      if (object.$value == $rootScope.currentUser.uid) {
        hasVoted = true;
      }
    })

  }).then(function() {

    // If has voted, stop here
    if (hasVoted) {
      $scope.alertMessage = {
        message: 'You have already voted on this post!',
        type: 'warning'
      };

    // If not, allow voting
    } else {

      // Add 1 to current voteCount
      thisStory.voteCount++;
      thisStory.$save();

      // Add the current user to the list of voters on the post
      voters.$add($rootScope.currentUser.uid);

      var storyAuthorRef = new Firebase(FIREBASE_URL + '/users/' + story.user.id);
      var storyAuthor = $firebaseObject(storyAuthorRef);

      // Add 1 to the story author's karma
      storyAuthor.$loaded().then(function() {
        storyAuthor.karma++;
        storyAuthor.$save();
      })
    }

  }) // end .then from voters.loaded
}; 

 

More to do

This was just an insight into how I handled some of the functions of the application. If you want to check out the full code, you can view it on my github. I was playing around with the idea of making a screencast where I go through how I did everything. If that’s something you would be interested in, let me know.

Although the core functionality it works, it is definitely not production ready. I still have a lot of messages being logged to the console. In the future I want to work more on handling the error messages more effectively, especially related to authentication.

 


Editor’s Note: This post first appeared on Ire’s blog.

Read this next
More From TC
Features, long reads, My Life In Tech
16th October 2019

My Life In Tech is putting human faces to some of the innovative startups, investments and policy formations driving the technology sector across Africa. Obi Ozor may or may not be a red cap chief but his company, Kobo360, in just under two years, has become one of the leading technology logistics service providers across […]

My Life In Tech is putting human faces to some of the innovative startups, investments and policy formations driving the technology sector across Africa. From Bengaluru to Damascus, young people are swapping weekend fun activities with intensive classes under AI Saturdays’ community-driven Artificial Intelligence training programme. Now in more than 60 countries globally, the free-to-attend […]

AfCFTA, Business, Features, Government, Opinion, Policy, Politics
15th October 2019

The world is getting increasingly insular. Borders are getting shut and walls are being proposed. Migrant children are being locked in cages, denied such luxury as soaps and beds. Our former colonial overlords, the Brits as they’re affectionately known, are also at it again. Since 2016, they’ve contorted themselves into several unseemly shapes as they […]


TechCabal is a Big Cabal Media brand



Copyright © 2019
All rights reserved

Privacy & Terms