Posts

, , , ,

Comparing Angular 1 & Angular 2 Through Building a Pomodoro Timer

Modern web development offers an incredible variety of tools, libraries, and frameworks to build web sites/applications. As of 2016, jQuery, React, Angular, and Vue are the most popular front-end libraries/frameworks in use. They can all be used to build and accomplish similar things, but in different ways. What are the advantages/disadvantages of each? How does each approach vary? What do the new tools of React, Vue, and Angular 2 offer that Angular 1, jQuery, and vanilla JS didn’t?

In part 1 of the series, we saw the similarities and differences between javascript and jQuery while building the same pomodoro app and we also discussed the advantages and disadvantages of each. In part 2 of the series, we will see how to use angular 1 and angular 2 to build the same pomodoro timer and we will discuss the difference in approaches taken by the two frameworks.

Explore Angular Courses

What is a pomodoro timer?

The pomodoro timer is an easy-to-use productivity method. Using this method, you work in 25 minute spurts with 5 minute breaks in between. Many people find it helpful for helping them focus and work on tasks during the day.

pomodoro timer

Project Overview

In this tutorial, first we will create a pomodoro timer using Angular 1. Then, we will re-create the same pomodoro timer using Angular 2.

Here is how the final version of pomodoro timer built using Angular 1 looks like :

See the Pen Pomodoro Timer : : Angular1.5 by Raj Gupta (@rajdgreat007) on CodePen.

Here is how the final version of pomodoro timer built using Angular 2 looks like :

See the Pen Pomodoro Timer : : Angular2 by Raj Gupta (@rajdgreat007) on CodePen.

Our pomodoro timer shows minutes, seconds, and gives simple control buttons. It’s a simple timer but can give enormous productivity gains if used right.

Building the Pomodoro Timer : Angular 1

Let’s first write the html code to create various elements of the pomodoro timer.

<div id="pomodoro-app">
<div id="container">
<div id="timer">
<div id="time">{{toDoubleDigit(minutes)}}
:
{{toDoubleDigit(seconds)}}</div>
<div id="filler"></div>
</div>
<div id="buttons"><button id="work">Work</button>
<button id="shortBreak">Short Break</button>
<button id="longBreak">Long Break</button>
<button id="stop">Stop</button></div>
</div>
</div>

Angular 1 has MVC(Model, View, Controller)/MVVM(Model, View, ViewModel) architecture. The model represents data (eg. javascript objects) of the application. The view is how we can display the data to user. Since Angular 1 supports two way data binding, any change in the model will automatically update the view and vice versa. The controller consists of the code that controls the interaction between model and view.

By setting ng-app=“pomodoroApp”, we are marking the corresponding div (with id pomodoro-app) as the root element of the Angular application. “pomodoroApp” is the name of the angular module that we will define later in javascript code. By setting ng-controller=“pomodoroController”, we are attaching a controller function (will be defined later) to the view. The controller function will consist of variables and functions needed for the view. ng-click defines the function (defined in controller) that will be executed when the corresponding button is being clicked. We will be using a background filler that will keep increasing as time progresses.

Let’s apply css to the above markup.

#container{
border:1px solid #333;
border-radius :20px;
width:400px;
margin:20px auto;
padding:20px;
text-align:center;
background : #333;
}

#timer{
color:#f00;
font-size:50px;
margin:10px auto;
border : 5px solid red;
border-radius:50%;
width:200px;
height:200px;
overflow:hidden;
position:relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor:default;
}

#time{
margin-top:70px;
z-index : 1;
position:relative;
}

/*
filler width is set to 200px (i.e. equal to width of the timer) so that it completely covers the timer in background. The height is initially set to 0px and it increases as timer progresses to give background fill effect.
*/

#filler{
background : #ddffcc;
height: 0px;
width: 200px;
position:absolute;
bottom:0;
}

#buttons button {
background:#4da6ff;
border:none;
color:#fff;
cursor:pointer;
padding:5px;
width:90px;
margin:10px auto;
font-size:14px;
height : 50px;
border-radius : 50px;
}

#buttons button#shortBreak{
background : #0c0;
}

#buttons button#longBreak{
background : #080;
}

#buttons button#stop{
background : #f00;
}

Now, let’s make the pomodoro app functional by adding the following javascript :

var app = angular.module("pomodoroApp", []);
/* Define a module named pomodoroApp*/

/* Defind the angular component*/
app.component('pomodoroComp', {
bindings: {},
templateUrl: '/componentGrid.html',
controller : ['$interval',function(interval){

var self = this;
self.started = false;
/* 
started variable stores the state of the timer. If it is true, it means that some task (work, short break, long break) is going on with pomodoro timer. If it is false, it means that the pomodoro is not yet started or it is stopped (by clicking stop button)
*/

self.minutes = 25;
/*
minutes variable stores current minute which is displayed in the pomodoro. 
*/

self.seconds = 0;
/*
seconds variable stores current second which is displayed in the pomodoro.
*/

self.fillerIncrement = 200/(self.minutes*60);
/*
fillerIncrement variable stores the value by which fillerHeight should increase.
*/

self.fillerHeight = 0; 
/*
fillerHeight variable stores the height of the background filler. Initially it is set to 0. As soon as a pomodoro task starts, its height starts increasing (by a value which is stored in fillerIncrement variable) and it keeps increasing till that particular task ends. On click of stop button, it is again set to 0.

*/


/*
resetVariables function will be called for each of the actions (work, Short Break, Long Break, Stop) to set the value of variables to values corresponding to that particular action
*/

self.resetVariables = function(mins, secs, started){
self.minutes = mins;
self.seconds = secs;
self.started = started;
self.fillerIncrement = 200/(self.minutes*60);
self.fillerHeight = 0;
}

/* handler to be called when user clicks ‘Work’ button */
self.startWork = function(){
self.resetVariables(25, 0, true);
};

/* handler to be called when user clicks ‘Short Break’ button */
self.startShortBreak = function(){
self.resetVariables(5, 0, true);
};

/* handler to be called when user clicks ‘Long Break’ button */
self.startLongBreak = function(){
self.resetVariables(15, 0, true);
};

/* handler to be called when user clicks ‘Stop’ button */
self.stopTimer = function(){
self.resetVariables(25, 0, false);
};

self.timerComplete = function(){
self.started = false;
};

/*
intervalCallback function is called each second, updates the values of minutes and seconds variables and reflect the updates in timer
*/
self.intervalCallback = function(){ 
if(!self.started) return false;
if(self.seconds == 0) {
if(self.minutes == 0) {
self.timerComplete();
return;
}
self.seconds = 59;
self.minutes--;
} else {
self.seconds--;
}

self.fillerHeight += self.fillerIncrement;
};

/* 
toDoubleDigit function converts a number to double digit. If num is single digit (0-9), it is prepended with a ‘0’ and resulting string is returned. If num is double digit, it is returned as such. This function is needed as we want to display ’05’ instead of ‘5’ in timer 
*/
self.toDoubleDigit = function(num){
return num < 10 ? '0' + parseInt(num,10) : num;
};


/*
Init method initializes the timer using $interval function such that a callback function (intervalCallback) is called after every second
*/

self.$onInit = function(){
self.interval = interval( self.intervalCallback, 1000);
/*
$onInit is automatically called when component is initialized. interval variable stores the reference id of the currently running interval. If we need to clear the interval, we will need this variable. Although in the demo, we are not clearing the interval, it’s always a good idea to clear the interval at some point.
*/


};

}]
});

Inside the view, we are using {{toDoubleDigit(minutes)}} to display current minutes in double digits. It is bound to $scope.minutes variable in controller. Thus, as soon as the value of $scope.minutes changes, the changed value is immediately reflected in the view. Same thing happens for seconds and filler height display.

Building the Pomodoro Timer : Angular 2

Now we’re going to build this exact same app using Angular 2.

Angular 2 uses the concept of components which could be considered as Angular 1 directives that are associated with their own template. Let’s go ahead and create the pomodoro app using Angular 2 component. For Angular 2, the angular team has chosen TypeScript over JavaScript. Typescript is a superset of JavaScript and created by Microsoft. So, we will be writing code in TypeScript for the pomodoro app.

html :

Loading…

Note : The following external javascript libraries are required to be added to the page (For the demo, they are already added in copepan settings):

https://npmcdn.com/core-js/client/shim.min.js
//cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.8/Reflect.min.js
//cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.37/system.js
//code.angularjs.org/2.0.0-beta.0/Rx.umd.js
//code.angularjs.org/2.0.0-beta.0/angular2-polyfills.js
//code.angularjs.org/2.0.0-beta.0/angular2-all.umd.dev.js
**typescript :**

/* Import Component object from ng.core */
const {Component} = ng.core;

/* Import Bootstrap object from ng.platform.browser */
const {bootstrap} = ng.platform.browser;

/* Component decorator is used to add metadata to the typescript class*/
@Component({
/*
selector defines the name of the tag which is used to add the component on html page
*/
selector : 'pomodoro-app',

/*
styles defines the css associated with the component
*/
styles : [`
#container{
border:1px solid #333;
border-radius :20px;
width:400px;
margin:20px auto;
padding:20px;
text-align:center;
background : #333;
}

#timer{
color:#f00;
font-size:50px;
margin:10px auto;
border : 5px solid red;
border-radius:50%;
width:200px;
height:200px;
overflow:hidden;
position:relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor:default;
}

#time{
margin-top:70px;
z-index : 1;
position:relative;
}

#filler{
background : #ddffcc;
height: 0px;
width: 200px;
position:absolute;
bottom:0;
}

#buttons button {
background:#4da6ff;
border:none;
color:#fff;
cursor:pointer;
padding:5px;
width:90px;
margin:10px auto;
font-size:14px;
height : 50px;
border-radius : 50px;
}

#buttons button#shortBreak{
background : #0c0;
}

#buttons button#longBreak{
background : #080;
}

#buttons button#stop{
background : #f00;
}

`],

/*
template defines the markup associated with the component
*/
template : `

{{toDoubleDigit(minutes)}}
:
{{toDoubleDigit(seconds)}}
 
Work
Short Break
Long Break
Stop
`
})

class AppComponent{
/*
All the variables and functions below have same meaning as described in Angular 1 pomodoro code.
*/
constructor(){
this.started = false;
this.minutes = 25;
this.seconds = 0;
this.fillerIncrement = 200/(this.minutes*60);
this.fillerHeight = 0;
this.init();
}
resetVariables(mins, secs, started){
this.minutes = mins;
this.seconds = secs;
this.started = started;
this.fillerIncrement = 200/(this.minutes*60);
this.fillerHeight = 0;
}
startWork(){
this.resetVariables(25, 0, true);
};
startShortBreak(){
this.resetVariables(5, 0, true);
};
startLongBreak(){
this.resetVariables(15, 0, true);
};
stopTimer(){
this.resetVariables(25, 0, false);
};
timerComplete(){
this.started = false;
}
intervalCallback(){
if(!this.started) return false;
if(this.seconds == 0) {
if(this.minutes == 0) {
this.timerComplete();
return;
}
this.seconds = 59;
this.minutes--;
} else {
this.seconds--;
}
this.fillerHeight += this.fillerIncrement;
};
toDoubleDigit(num){
return num < 10 ? '0' + parseInt(num,10) : num;
};
init(){
self = this;
this.interval = setInterval( function(){
self.intervalCallback.apply(self);
}, 1000);
};
}

/* Bootstrapping the component */
bootstrap(AppComponent, []);

The Angular team has made a lot of changes in Angular 2. It would not be an anomaly to say that they completely revamped the framework and build it from scratch. The reason for doing so many changes was to remove the bad parts of Angular 1 and to take advantage of new features of ECMAScript6 (the new version of JavaScript). Let’s explore the most prominent changes made in Angular 2 and reason behind them.

Controller and scope are completely eliminated from Angular 2. Angular 2 is more focused towards Component based development and object orientation (because of typescript). Web applications nowadays have become too complex. Angular team chose to use web components in Angular 2 because other than providing encapsulation and reusability, web components manages the complexity of the application by providing isolation. Every component is independent of other components and can be used as such by simply importing it on a page. Each component has its own template and styles that will apply only to that particular component. It means that the css will not bleed out of the component. The same is not possible with Angular 1 as the CSS is applied on page level. We can even create custom elements with Angular 2 that could be reused as such or could be extended by other users.

As mentioned earlier, Angular 2 team has chosen typescript for writing code in Angular 2 . The choice is inspired from following facts :

  1. Typescript easily integrates with most of the already existing javascript libraries and existing javascript code. So, we need not worry about legacy code.
  2. Using typescript adds lot of advantages to the framework which includes optional static typing and support for object oriented features like inheritance and interfaces. Static typing allows the type checking during the compilation. An interface define a set of functionality as a contract. When the interface is implemented, all the members of the interface must be implemented. Traditional javascript support prototype-based inheritance which is not completely object oriented. Typescript supports object oriented class based inheritance which goes pretty well with other object oriented features.
  3. Typescript adds type support to javascript. It means that the bugs that are caused by false assumption of a variable being of certain type can be detected while compilation. The same is not possible with javascript as it is dynamically typed.
  4. Typescript is far better than core javascript in managing the complexity of large projects.

Angular 1 implements two-way data binding by dirty-checking method and use watchers to watch the model/view for changes. Higher number of data bindings means higher number of watchers and hence higher performance degradation. Angular 2 doesn’t come with built in two-way data binding, although even in Angular 2, we can create directives that support two-way data binding. Angular 2 primarily uses unidirectional tree based change detection which boosts performance. Although we are not using two way data binding in Angular 1 pomodoro app, its worth mentioning that it is considered to be one of the bad parts of Angular 1 and thus it is removed from Angular 2.

Explore Angular Courses

Because of the optimisations mentioned above, Angular 2 is considered to be 5 times faster as compared to Angular 1 (as per ng-conf [https://ti.to/ng-conf/2016/en]).

In Angular 1, the bootstrapping of the app could be done by using ng-app or by calling the bootstrap function. In Angular 2, it can only be done by calling the bootstrap method.

Angular 1 uses $interval which is Angular’s wrapper for window.setIntervalfunction. As specified in code, the callback function is executed after every 1000 ms. Intervals created by $interval service must be explicitly destroyed because they are not destroyed automatically after the controller scope is destroyed. $interval is not available in Angular 2, thus we can either use javascript’s setInterval orObservable.interval method of Angular 2.

Conclusion

We created two pomodoro apps, one using Angular 1 and other using Angular 2. The app built using Angular 2 carries the advantages of web components and shadow DOM and is also free from the performance degradation caused due to two-way data binding of Angular 1.

Bonus

Here is this pomodoro app done in React

See the Pen Pomodoro Timer : React by Raj Gupta (@rajdgreat007) on CodePen.

Here is this pomodoro app done in Vue

See the Pen Pomodoro Timer : : Vue by Raj Gupta (@rajdgreat007) on CodePen.

Explore Angular Courses

, , , , ,

Comparing Javascript & jQuery Through Building a Pomodoro Timer

Modern web development offers an incredible variety of tools, libraries, and frameworks to build web sites/applications. As of 2016, jQuery, React, Angular, and Vue are the most popular front-end libraries/frameworks in use. They can all be used to build and accomplish similar things, but in different ways. What are the advantages/disadvantages of each? How does each approach vary? What do the new tools of React, Vue, and Angular 2 offer that Angular 1, JavaScript, and vanilla JS didn’t?

In this 3 part tutorial series, we’re going to build a simple pomodoro timer as a means to compare vanilla JavaScript, jQuery, React, Angular 1, Angular 2 and Vue.

What is a pomodoro timer?

The pomodoro timer is an easy-to-use productivity method. Using this method, you work in 25 minute spurts with 5 minute breaks in between. Many people find it helpful for helping them focus and work on tasks during the day.

screen-shot-2016-10-11-at-9-31-11-am

Project Overview

In this tutorial, first we will create a pomodoro timer using vanilla javascript. Then, we will re-create the same pomodoro timer using jQuery.

Here is how the final version of pomodoro timer built using vanilla javascript looks like :

See the Pen Pomodoro Timer : : Javascript by Raj Gupta (@rajdgreat007) on CodePen.


Here is how the final version of pomodoro timer built using jQuery looks like :

See the Pen Pomodoro Timer : : jQuery by Raj Gupta (@rajdgreat007) on CodePen.


Our pomodoro timer shows minutes, seconds, and gives simple control buttons. It’s a simple timer but can give enormous productivity gains if used right.

Building the Pomodoro Timer : Javascript

Let’s first write the html code to create various elements of the pomodoro timer.

<div id="pomodoro-app">

 <div id="container">

        <div id="timer">

        <div id="time">

    <span id="minutes">25</span>

    <span id="colon">:</span>

    <span id="seconds">00</span>

        </div>

        <div id="filler"></div>

        </div>

        <div id="buttons">

        <button id="work">Work</button>

        <button id="shortBreak">Short Break</button>

        <button id="longBreak">Long Break</button>

        <button id="stop">Stop</button>

</div>

 </div>

</div>

As you can see, nothing fancy here. Just a container with the timer and control buttons. We will be using a background filler that will keep increasing as time progresses.

Let’s apply some css to the above markup to make it look nice.

#container{

 border:1px solid #333;

 border-radius :20px;

 width:400px;

 margin:20px auto;

 padding:20px;

 text-align:center;

 background : #333;

}

#timer{

 color:#f00;

 font-size:50px;

 margin:10px auto;

 border : 5px solid red;

 border-radius:50%;

 width:200px;

 height:200px;

 overflow:hidden;

 position:relative;

 -webkit-user-select: none;

 -moz-user-select: none;

 -ms-user-select: none;

 user-select: none;

 cursor:default;

#time{

 margin-top:70px;

 z-index : 1;

 position:relative;

}

/*

filler width is set to 200px (i.e. equal to width of the timer) so that it completely covers the timer in background. The height is initially set to 0px and it increases as timer                   progresses to give background fill effect.

*/

#filler{

 background : #ddffcc;

 height: 0px;

 width: 200px;

 position:absolute;

 bottom:0;

}

#buttons button {

 background:#4da6ff;

 border:none;

 color:#fff;

 cursor:pointer;

 padding:5px;

 width:90px;

 margin:10px auto;

 font-size:14px;

 height : 50px;

 border-radius : 50px;

}

#buttons button#shortBreak{

 background : #0c0;

}

#buttons button#longBreak{

 background : #080;

}

#buttons button#stop{

 background : #f00;

}

Now the timer looks nice, but there is no functionality associated with it yet. Let’s add javascript to make it functional.

We will be using object oriented javascript in which all of the variables and functions of the pomodoro timer will be encapsulated inside an object. Below is the basic structure of the code :

var pomodoro = {

           ...………….

           …………….

           init: function() {

               }

           ……………

      …………….

};

//The pomodoro object consists of variables and methods in key value pairs.

window.onload = function() {

     
    pomodoro.init();

};

/* window.onload method is used to make sure that page and DOM are loaded before we call init method as it queries and manipulates DOM. */

Let’ s add variables and other methods which are needed to make the pomodoro timer work.

var pomodoro = {

           
    started: false,

    /*       
started variable stores the state of the timer. If it is true, it means that some task (work, short break, long break) is going on with pomodoro timer. If it is false, it means that the pomodoro is not yet started or it is stopped (by clicking stop button)
     
     */

           minutes: 0,

    /*

            minutes variable stores current minute which is displayed in the pomodoro.       

    */

           seconds: 0,

    /*

            seconds variable stores current second which is displayed in the pomodoro.

    */

           fillerHeight: 0,

    /*

            fillerHeight variable stores the height of the background filler. Initially it is set to 0. As soon as a pomodoro task starts, its height starts increasing (by a value which is stored in fillerIncrement variable) and it keeps increasing till that particular task ends. On click of stop button, it is again set to 0.

    */

           fillerIncrement: 0,

    /*

            fillerIncrement variable stores the value by which fillerHeight should increase.

    */

           interval: null,

    /*

            interval variable stores the reference id of the currently running interval. If we need to clear the interval, we will need this variable. Although in the demo, we are not clearing the interval, it’s always a good idea to clear the interval at some point.

    */

           minutesDom: null,

    /*

            minutesDom : It stores the reference of the minutes element of pomodoro. It’s good to store the reference so that it can be reused instead of querying the DOM again for the same element.

    */

           secondsDom: null,

    /*

            secondsDom variable stores the reference of the seconds element of pomodoro.

    */

           fillerDom: null,

    /*

            fillerDom variable stores the reference of the filler element of pomodoro.

    */

           init: function() {

        /*

                Init method initializes the variables and set event listeners for all buttons. It also starts the interval due to which a callback function (intervalCallback) is called after every 1 second and updates the DOM depending on the task which is in execution.

        */

               
        var self = this;

               
        this.minutesDom = document.querySelector('#minutes'); /* caching the reference to seconds dom object */

               
        this.secondsDom = document.querySelector('#seconds'); /* caching the reference to seconds dom object */

               
        this.fillerDom = document.queryS elector('#filler '); /* caching the reference to background filler dom object */

               
        this.interval = setInterval(function() {

                   
            self.intervalCallback.apply(self);

                   
        }, 1000);



                /* adding the listener to be called when user clicks 'Work’ button */

               
        document.querySelector('#work').onclick = function() {

               
            self.startWork.apply(self);

                   
        };

                /* adding the listener to be called when user clicks 'Short Break’ button */

         
        document.querySelector('#shortBreak').onclick = function() {

                   
            self.startShortBreak.apply(self);

                   
        };

                /* adding the listener to be called when user clicks 'Long Break’ button */

             
        document.querySelector('#longBreak').onclick = function() {

               
            self.startLongBreak.apply(self);

                   
        };

        /* adding the listener to be called when user clicks 'Stop’ button */

             
        document.querySelector('#stop').onclick = function() {

                   
            self.stopTimer.apply(self);

                   
        };

               
    },

    /* resetVariables will be called for each of the actions (work, Short Break, Long Break, Stop) to set the value of variables to the corresponding action values */

           resetVariables: function(mins, secs, started) {

               
        this.minutes = mins;

               
        this.seconds = secs;

               
        this.started = started;

             
        this.fillerIncrement = 200 / (this.minutes * 60);

             
        this.fillerHeight = 0;

               
    },

           startWork: function() {

         
        this.resetVariables(25, 0, true);

               
    },

           startShortBreak: function() {

               
        this.resetVariables(5, 0, true);

               
    },

           startLongBreak: function() {

             
        this.resetVariables(15, 0, true);

               
    },

           stopTimer: function() {

             
        this.resetVariables(25, 0, false);

             
        this.updateDom();

               
    },

           toDoubleDigit: function(num) {

        /*

        If num is single digit (0-9), it is prepended with a '0’ and resulting string is returned. If num is double digit, it is returned as such. This function is needed as we want to display ’05’ instead of '5’ in timer

        */

               
        if (num & lt; 10) {

               
            return "0" + parseInt(num, 10);

                   
        }

               
        return num;

               
    },



    /*

    updateDom function updates the values of minutes, seconds and filler height every second, so that user can see the remaining time and background fill height changing continuously

    */

           updateDom: function() {

             
        this.minutesDom.innerHTML = this.toDoubleDigit(this.minutes);

             
        this.secondsDom.innerHTML = this.toDoubleDigit(this.seconds);

             
        this.fillerHeight = this.fillerHeight + this.fillerIncrement;

             
        this.fillerDom.style.height = this.fillerHeight + 'px';

               
    },



    /*

    intervalCallback function is called each second, updates the value of minutes and seconds variables and calls updateDom function to reflect the updates in timer

    */

           intervalCallback: function() {

             
        if (!this.started) return false;

               
        if (this.seconds == 0) {

               
            if (this.minutes == 0) {

                         
                this.timerComplete();  /* As soon as both minutes and seconds variables become zero, it means that the timer is complete and it can be stopped now*/

                  
                return;

                   
            }

               
            this.seconds = 59;

                   
            this.minutes--;

                   
        } else {

                   
            this.seconds--;

                   
        }

             
        this.updateDom();

               
    },

           timerComplete: function() {

               
        this.started = false;

         
        this.fillerHeight = 0;

               
    }

};

window.onload = function() {

     
    pomodoro.init();

};

Building the  Pomodoro Timer : jQuery

Now we’re going to build this exact same app in jQuery. The HTML and CSS are exactly same as that of above.

var pomodoro = {

/*
All the variables and functions below have same meanings as described in javascript pomodoro code. The difference is only in how we will achieve the same functionality using jQuery code
*/

           
    started: false,

           minutes: 0,

           seconds: 0,

           fillerHeight: 0,

           fillerIncrement: 0,

           interval: null,

           minutesDom: null,

           secondsDom: null,

           fillerDom: null,

           init: function() {

               
        var self = this;

               
        this.minutesDom = $('#minutes');  /*  slower as compared to document.querySelector('#minutes’) */

               
        this.secondsDom = $('#seconds');

               
        this.fillerDom = $('#filler');

               
        this.interval = setInterval(function() {

                      
            self.intervalCallback.apply(self);

                   
        }, 1000);



        /*  adding the click handlers for work, short break, long break and stop buttons */

        $('#work').click(function() {

                   
            self.startWork.apply(self);

                   
        });

             
        $('#shortBreak').click(function() {

                   
            self.startShortBreak.apply(self);

                   
        });

               
        $('#longBreak').click(function() {

               
            self.startLongBreak.apply(self);

                   
        });

         
        $('#stop').click(function() {

               
            self.stopTimer.apply(self);

                   
        });

               
    },

           resetVariables: function(mins, secs, started) {

               
        this.minutes = mins;

               
        this.seconds = secs;

               
        this.started = started;

         
        this.fillerIncrement = 200 / (this.minutes * 60);

         
        this.fillerHeight = 0;

               
    },

           startWork: function() {

         
        this.resetVariables(25, 0, true);

               
    },

           startShortBreak: function() {

               
        this.resetVariables(5, 0, true);

               
    },

           startLongBreak: function() {

         
        this.resetVariables(15, 0, true);

               
    },

           stopTimer: function() {

         
        this.resetVariables(25, 0, false);

         
        this.updateDom();

               
    },

           toDoubleDigit: function(num) {

               
        if (num & lt; 10) {

               
            return "0" + parseInt(num, 10);

                   
        }

               
        return num;

               
    },

           updateDom: function() {

             
        this.minutesDom.text(this.toDoubleDigit(this.minutes));

             
        this.secondsDom.text(this.toDoubleDigit(this.seconds));

               
        this.fillerHeight = this.fillerHeight + this.fillerIncrement;

         
        this.fillerDom.css('height', this.fillerHeight + 'px');

               
    },

           intervalCallback: function() {

         
        if (!this.started) return false;

               
        if (this.seconds == 0) {

               
            if (this.minutes == 0) {

                    
                this.timerComplete();

                  
                return;

                   
            }

               
            this.seconds = 59;

               
            this.minutes--;

                   
        } else {

               
            this.seconds--;

                   
        }

         
        this.updateDom();

               
    },

           timerComplete: function() {

               
        this.started = false;

         
        this.fillerHeight = 0;

               
    }

};

$(document).ready(function() {

     
    pomodoro.init();

});

First of all, I would like to mention that jQuery is a huge library. In our pomodoro app, we have used a very small subset of the features that it offers. This is the biggest disadvantage of using jQuery for our case because we will be loading entire library and because of that, the page load time will be much higher as compared to javascript’s pomodoro app. In huge pages, using jQuery makes a lot of sense.

In the above code we are using $(‘#minutes’) for caching the minutes DOM element.  As a matter of fact, javascript’s document.querySelector(‘#minutes’) is way faster than jQuery’s $(‘#minutes’). This speed difference could not be realised in a small app (such as a pomodoro timer) but it is relevant for large pages where there is intensive DOM query. Javascript’s document.getElementById(‘minutes’) is even faster than document.querySelector(‘#minutes’). So, the speed of executions has the following order :

document.getElementById(‘minutes’)  > document.querySelector(‘#minutes’) > $(‘#minutes’)

The reason for the above speed difference being, under the hood $(‘#minutes’) boils down to document.getElementById(‘minutes’) wrapped by jQuery wrapper. But when we say $(‘#minutes’), jQuery has to a lot of work in identifying if the argument is a string, does it contain spaces, it starts with a ‘.’ or a ‘#’ or is it a tagname and so on. This extra work takes time and hence reduces the speed.

Although, jQuery is at disadvantage because its DOM query speed is less as compared to javascript but when it comes to code convenience, jQuery is far ahead of javascript.

In the pomodoro app created using javascript, we can easily spot long lines of code whereas in the app created using jquery, the code seems relatively short. That means, if we are using jQuery, we have to type less as compared to javascript to achieve the same functionality. Whereas in javascript there are different methods to query DOM (by id, class and tagname), in jQuery, one single selector takes care of all of them.

Moreover,  javascript’s document.querySelector(‘#work’) will not work in all the browsers. It may break in IE8. On the other hand, jQuery’s $(‘#work’) is guaranteed to work in all the browsers. The reason is, all jQuery’s methods are standardised to work across all browsers.

Additionally, jQuery provides support for chaining which means that we can chain a method call at the end of another method call and save few bytes by saving the amount of code required to be written if chaining was not supported. For example, we can do the following in jQuery :

$('#work’).css('background’,’#999’).show()

Here we have chained show() method at the end of css() method. On the other hand, javascript doesn’t support method chaining.

In jQuery, we are using $(document).ready(), to make sure that DOM is ready before we query it. In javascript, we used window.onload event to achieve the same. jQuery’s $(document).ready() event occurs earlier as compared to window.onload of javascript because the latter occurs after the DOM is loaded and all the resources (scripts, images etc) are also loaded.

Last but not the least, while writing javascript code, there is big scope for writing inefficient code. jQuery library on the other hand, is tested over time and highly optimised. Thus, if used carefully, the scope for writing inefficient code using jQery is very less as compared to javascript.

Conclusion

We created two pomodoro apps, one using vanilla javascript and other using jQuery. The two approaches are fairly similar, but jQuery offers an easier syntax in querying for elements and offers shorter (albeit slower) ways of doing things compared to JavaScript.

The differences between libraries/frameworks will get much more interesting in future posts, where we use Angular, React, and Vue to build this same app.