Let's manage time!
At this point of time, I already know that you are so, so, so enthusiastic with this book that you want to read it to the end without stopping. But this is not right. We should manage our time and give us some time to work and some time to rest. Let's create a small application that implements a Pomodoro technique timer so that it can help us in our working time management.
Note
The Pomodoro technique is a time management technique named after the kitchen tomato timer (in fact, Pomodoro means tomato in Italian). This technique consists of breaking down the working time into small intervals separated by short breaks. Read more about the Pomodoro technique on the official site: http://pomodorotechnique.com/ .
Thus, our goal is very simple. We just have to create a very simple time counter that will decrement untill the end of the working interval and then restart and decrement till the end of the resting time and so on.
Let's do that!
We will introduce two Vue data variables, minute and second, which will be displayed on our page. The main method on each second will decrement second; it will decrement minute when second becomes 0; and when both minute and second variables come to 0, the application should toggle between working and resting interval:
Our JavaScript code will look like the following:
const POMODORO_STATES = {
WORK: 'work',
REST: 'rest'
};
const WORKING_TIME_LENGTH_IN_MINUTES = 25;
const RESTING_TIME_LENGTH_IN_MINUTES = 5;
new Vue({
el: '#app',
data: {
minute: WORKING_TIME_LENGTH_IN_MINUTES,
second: 0,
pomodoroState: POMODORO_STATES.WORK,
timestamp: 0
},
methods: {
start: function () {
this._tick();
this.interval = setInterval(this._tick, 1000);
},
_tick: function () {
//if second is not 0, just decrement second
if (this.second !== 0) {
this.second--;
return;
}
//if second is 0 and minute is not 0,
//decrement minute and set second to 59
if (this.minute !== 0) {
this.minute--;
this.second = 59;
return;
}
//if second is 0 and minute is 0,
//toggle working/resting intervals
this.pomodoroState = this.pomodoroState ===
POMODORO_STATES.WORK ? POMODORO_STATES.REST :
POMODORO_STATES.WORK;
if (this.pomodoroState === POMODORO_STATES.WORK) {
this.minute = WORKING_TIME_LENGTH_IN_MINUTES;
} else {
this.minute = RESTING_TIME_LENGTH_IN_MINUTES;
}
}
}
});
In our HTML code, let's create two placeholders for minute and second, and a start button for our Pomodoro timer:
<div id="app" class="container">
<h2>
<span>Pomodoro</span>
<button @click="start()">
<i class="glyphicon glyphicon-play"></i>
</button>
</h2>
<div class="well">
<div class="pomodoro-timer">
<span>{{ minute }}</span>:<span>{{ second }}</span>
</div>
</div>
</div>
Again, we are using Bootstrap for the styling, so our Pomodoro timer looks like the following:

Countdown timer built with Vue.js
Our Pomodoro is nice, but it has some problems:
- First of all, we don't know which state is being toggled. We don't know if we should work or rest. Let's introduce a title that will change each time the Pomodoro state is changed.
- Another problem is inconsistent display of minutes and seconds numbers. For example, for 24 minutes and 5 seconds, we would like to see 24:05 and not 24:5. Let's fix it introducing computed values in our application data and displaying them instead of normal values.
- Yet another problem is that our start button can be clicked over and over again, which creates a timer each time it's clicked. Try to click it several times and see how crazy your timer goes. Let's fix it by introducing start, pause, and stop buttons, apply application states to them, and disable buttons to the state accordingly.
Toggle the title by using computed properties
Let's start by fixing the first problem by creating computed property title and using it in our markup.
Note
Computed properties are the properties inside the data object that allow us to avoid blowing up the template with some extra logic. You can find more information about computed properties on the official documentation site:
http://vuejs.org/guide/computed.html
.
Add the computed section in the Vue options object and add the property title there:
data: {
//...
},
computed: {
title: function () {
return this.pomodoroState === POMODORO_STATES.WORK ? 'Work!' :
'Rest!'
}
},
methods: {
//...
And now just use the following property as it was a normal Vue data property in your markup:
<h2>
<span>Pomodoro</span>
<!--!>
</h2>
<h3>{{ title }}</h3>
<div class="well">
And voilà ! Now we have a title that changes each time the Pomodoro state is being toggled:

Automatic change of the title based on the state of the timer
Nice, isn't it?
Left-pad time values using computed properties
Now let's apply the same logic for left padding our minute and second numbers. Let's add two computed properties, min and sec, in our computed section in the data options and apply the simple algorithm to pad the numbers with 0 on the left. Of course, we could use a famous left-pad project (
https://github.com/stevemao/left-pad
), but to keep things simple and not to break the whole Internet (
http://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/
), let's apply a simple logic of our own:
computed: {
title: function () {
return this.pomodoroState === POMODORO_STATES.WORK ? 'Work!' :
'Rest!'
},
min: function () {
if (this.minute < 10) {
return '0' + this.minute;
}
return this.minute;
},
sec: function () {
if (this.second < 10) {
return '0' + this.second;
}
return this.second;
}
}
And let's use these properties instead of minute and second in our HTML code:
<div class="pomodoro-timer">
<span>{{ min }}</span>:<span>{{ sec }}</span>
</div>
Refresh a page and check how beautiful our numbers are now:

Left padding using computed properties in Vue.js
Keep state with start, pause, and stop buttons
So, to fix the third problem, let's introduce three application states, started, paused, and stopped, and let's have three methods that would allow us to permute over these states. We already have the method that starts the application, so we just add the logic there to change the state to started. We also add two additional methods, pause and stop, which would pause the timer and change to the corresponding application state:
const POMODORO_STATES = { WORK: 'work', REST: 'rest' }; const STATES = { STARTED: 'started', STOPPED: 'stopped', PAUSED: 'paused' }; //<...> new Vue({ el: '#app', data: { state: STATES.STOPPED, //<...> }, //<...> methods: { start: function () { this.state = STATES.STARTED; this._tick(); this.interval = setInterval(this._tick, 1000); }, pause: function () { this.state = STATES.PAUSED; clearInterval(this.interval); }, stop: function () { this.state = STATES.STOPPED; clearInterval(this.interval); this.pomodoroState = POMODORO_STATES.WORK; this.minute = WORKING_TIME_LENGTH_IN_MINUTES; this.second = 0; }, //<...> } });
And, let's add two buttons to our HTML code and add the click listeners that call the corresponding methods:
<button :disabled="state==='started'" @click="start()"> <i class="glyphicon glyphicon-play"></i> </button> <button :disabled="state!=='started'" @click="pause()"> <i class="glyphicon glyphicon-pause"></i> </button> <button :disabled="state!=='started' && state !== 'paused'" @click="stop()"> <i class="glyphicon glyphicon-stop"></i> </button>
Now our application looks nice and allows us to start, pause, and stop the timer:

Toggling start, stop, and pause buttons according to the application state
Check what the whole code looks like in JSFiddle at https://jsfiddle.net/chudaol/b6vmtzq1/1/.
After so much work and so many of new terms and knowledge, you certainly deserve a kitten! I also love kittens, so here you have a random kitten from the awesome site http://thecatapi.com/ :
