firepoll

2014 is going to be the year of the real time web and the combination of AngularJs and Firebase gonna be the shoehorn that will bring in to it a lot of developers.

While discussing this subject IRL last week, I realized I need to have a nice sample for a classic-basic web feature – with a real time twist. So I set down for a whole two hours and wrote this little sample app for real time polls.
What do you need real time polls for? Well, it can be really nice in a high traffic site, lets say a news site during the elections, and it can be a nice widget in any site, since it can take as little as 10 minutes to turn a poll app into a real time poll app.

Working sample @ http://directivemaker.info/firepoll/
Download code @ https://github.com/zivpug/firepoll

Firebase
Firebase
AngularJs
AngularJs

++++++++++++++++++++++++++++++++++++++++++++++++++++

Concept of Angularfire

Angularfire is your firebase service for AngularJs. After linking the required files, basically what you do is:
create a firebase object

    var myObject = new Firebase("https://MYFIREBASE.firebaseio.com/");

and your object is automagically linked to any other connected user at the same time. That’s all (well, basically).
So, if you have a poll object with the poll’s options, you just need to connect it to the firebase database, and you have a real time poll!

In this sample, there are a few minor complications due to the google charts api. Check out the remarks in the code to see what it took.

It's Alive!

++++++++++++++++++++++++++++++++++++++++++++++++++++

So what do we have here?

I took an angularJs google charts directive, and built a controller that turns it real time. In a real app the Firebase connection should be in a service, as such the poll creation methods, but here i flattened the architecture to make it simpler to read and understand (hopefully).

The dependencies are:

In the sample there are two parts – poll creation, and poll voting. Both are on the same view.
You can use any, and read the remarks in the code for the full info.

please note – since it’s a sample, there are no limitations, authentication or any other obstacle. In a real app you will add authentication and voting limitations. Both are done both in the clients side and on the server side using the firebase security rules. I may add a part about toughening and security rules, if there will be a demand.

HTML code for sample

Create a poll

                        

Create a poll

poll's question


Poll's answers

Option {{ $index+1 }}


Select a poll from the list

 

Select an existing poll

... Loading

Show the selected poll

   

Vote:


Other:

App Controller – where the job is done

angular.module('firepollapp').controller('mainCtrl',function($scope, $firebase){


    // firebase
   // Set YOURAPP - to your firebase address
    var ref = new Firebase("https://YOURAPP.firebaseio.com/polls/");
    // Automatically syncs everywhere in realtime
    $scope.polls = $firebase(ref);

    // create basic objects
    $scope.selectedPoll = '';
    $scope.selectedPollOptions = [];
    $scope.load = true;

    /*
    Select a poll from the poll's list
    moveing the poll data to a separate object from the firebase object
    It gives more flexibility with it's construct and data types
    (for example - firebase will return values as string type, while google charts has to have them as numbers
        - note the parseInt on the values)
    It does adds a need to create a watcher for any incoming changes.

    Also, used a separate object for poll voting options ($scope.selectedPollOptions) for some more flexibility
    */

    // Loading poll from the list (in the firebase object)
    $scope.selectPoll = function(id){
        if (id){ // don't run on initial watch
            // hold selected polls id
            $scope.selectedPoll = id;
            // clean poll options object
            $scope.selectedPollOptions = [];
            // clean chart data
            chart1.data = [];
            // populate chart's title from the firebase object
            chart1.options.title = $scope.polls[id].name;
            // google charts require column names in the first dataset row.
            // will give some little pain later
            chart1.data.push(['option','value']);
            // populate chart.data with the values from firebase
            // don't forget to parseInt the values or it will not draw the chart
            for (i=0; i<$scope.polls[id].options.length; i++)
            {
                if ($scope.polls[id].options[i][0] && $scope.polls[id].options[i][1])
                {
                    // if you don't have a numeric value - reset the value
                    var val = parseInt($scope.polls[id].options[i][1]);
                    var option = [$scope.polls[id].options[i][0], val];
                    // push data from the firebase object to the chart data object
                    chart1.data.push(option);
                    // push the options from the firebase object to the poll options object
                    $scope.selectedPollOptions.push($scope.polls[id].options[i]);
                }
            }
            $scope.chart = chart1;
        }
    };

    // deep watch for the firebase object, to have the chart update in real time, when the object updates
    // needed to handle the object separation
    $scope.$watch('polls', function(){
        $scope.selectPoll($scope.selectedPoll);
    },true);


    // data loaded from firebase - angularfire event
    // use to switch the loader off
    $scope.polls.$on("loaded", function() {
           $scope.load = false;
    });



    // vote on poll
    $scope.vote = function(index){
        // calc new total
        // add +1 to index to compensate for first row in chart data not being poll options
        index ++;
        if (angular.isNumber(chart1.data[index][1] ))
        {
            newTotal = parseInt(chart1.data[index][1]) + 1;
        }
        else
        {
            newTotal = 1
        }
        // move index one back
        index--;
        // update value in the firebase object
        $scope.polls[$scope.selectedPoll].options[index][1] = newTotal;
        // save changes to the object and the remote firebase
        $scope.polls.$save();
    };


    // Add "other" option to selected poll
    $scope.addOther = function(){
        if ($scope.vote.optionOther){
            // add new option to the firebase object with 1 vote
            $scope.polls[$scope.selectedPoll].options.push([$scope.vote.optionOther, 1]);
            // save the firebase object - update firebase remote
            $scope.polls.$save();
            // clear the "other" form field
            $scope.vote.optionOther = '';
        }
    };


    //////   google chart basic object
    var chart1 = {};
    chart1.type = "PieChart";
    // chart options. use google chart reference for more info
    // pie chart: https://developers.google.com/chart/interactive/docs/gallery/piechart
    chart1.options = {
        title: '',
        chartArea:{left:30,top:30,width:"300",height:"300"},
        sliceVisibilityThreshold:0,
        displayExactValues: true,
        pieSliceText: 'percentage',
        width: 400,
        height: 300,
        is3D: true,
        slices: {}
    };


    ///  create poll - form methods
    // reset the form
    $scope.resetForm = function(){
        $scope.pollForm = {};
        $scope.pollForm.options = [];
    };
    // call one reset on load for object declaration
    $scope.resetForm();
    // Add a poll option to the creation form
    $scope.addPollOption = function(){
        $scope.pollForm.options.push(['', '0']);
    };
    // remove pull option from the form
    $scope.removeOption = function(index){
        $scope.pollForm.options.splice(index,1);
    };

    // Create a new poll
    $scope.pollCreate = function(){
        // add to poll to the Firebase object - this will update it at the server
        // check for empty options
        for (i=0; i<$scope.pollForm.options.length; i++){
            // make sure no empty options
            if (angular.isUndefined($scope.pollForm.options[i][0]) || $scope.pollForm.options[i][0]=='') {$scope.pollForm.options.splice(i,1)}
        }
        if ($scope.pollForm.name && ($scope.pollForm.options.length>0))
        {
            // add the new form to the firebase object. it will be updated automagically in firebase
            $scope.polls.$add($scope.pollForm);
            // reset the poll creation form
            $scope.resetForm();
        }
    };

});


Working sample @ http://directivemaker.info/firepoll/
Download code @ https://github.com/zivpug/firepoll

 

4 thoughts on “Firepoll – Real time poll app sample

  1. hi,

    i was able to setup the firebase hosting using the command line and the poll script is showing up under polls/index.html. however, atm i don’t have any polls added, and when i type in a new poll and click submit, the process is not going through. do you have any idea why this is not working?

  2. Hey,
    1. do you get any error in the console?
    2. in the controller – have you entered your firebase ID at the line:
    var ref = new Firebase(“https://YOURAPP.firebaseio.com/polls/”);

Leave a Reply

Your email address will not be published. Required fields are marked *