Part of the Bloc course involves setting up a portfolio site, which includes a blog.
I’ve now finally made it live, and my new blog – along with examples of my work – can be found at balzafire.com.
Come and say hello! 🙂
Part of the Bloc course involves setting up a portfolio site, which includes a blog.
I’ve now finally made it live, and my new blog – along with examples of my work – can be found at balzafire.com.
Come and say hello! 🙂
The past two weeks have been absolutely mental at the job that pays me, but Mentor Ben sent me this a while ago and I had to share. I think it sums it up pretty well!
As both the next steps in my Bloctime project involve taking breaks, I’m going to write about both user story 3 (Take a break) and 4 (Take a 30-minute break) together.
The goal of user story 3 is to allow the user to take a five-minute break after a 25-minute work session. Users shouldn’t be able to begin their break unless they have finished a work session, but once on the break should be able to pause if necessary. Users should also only ever see a single timer and button, regardless of whether they’re on break or working.
The goal of user story 4 is to allow the user to take a longer 30-minute break after they have completed four completed work sessions.
I originally wanted to use the same button to control all timer activity, but this proved to be slightly too difficult – especially taking into consideration some of the requirements that would eventually need to tie into my app.
So I created a second button that controls the break timer. Both buttons use ngHide
to determine which should be shown based on whether my onBreak
variable is set to its default of false, when the task button appears, or true, when the break button is shown:
<div class="button-container"> <div class="button-styling"> <p ng-class="setButtonClass()" ng-click="toggleTimer()" ng-hide="onBreak">{{ buttonText }}</p> <p ng-class="setBreakButtonClass()" ng-click="toggleBreak()" ng-hide="!onBreak">{{ breakButtonText }}</p> </div> </div>
The break button controls both the five- and 30-minute breaks, and uses almost exactly the same function under a different name than that controlling the work session – the only difference is that instead of resetting the timer, the user is able to pause their break.
In user story 3, the idea of constants was introduced. Constants are used whenever variables are known and set, and won’t be changing. I’ve assigned three constants for this project: TIME_TASK
, which is the 25 minutes for a task; TIME_BREAK
, the five minutes for a normal break; and TIME_LONG_BREAK
, which is 30 minutes.
I’ve now got to keep track of quite a lot in the app:
In order to make the logic of my app easier to understand – and because endless nested if statements hurt my eyes – I’ve broken it down into two functions and made use of Angular’s $watch method.
My first function, checkRunning()
, makes sure that a work session is followed by a short break, counts how many work sessions have occurred and stops the timer:
scope.checkRunning = function() { if (scope.isTimerRunning === true) { $interval.cancel(scope.timerInterval); scope.isTimerRunning = false; scope.onBreak = true; scope.tasktime = TIME_BREAK; scope.sessionTracker += 1; scope.breakButtonText = "Start break"; scope.buttonText = "Start"; } if (scope.isBreakRunning === true) { $interval.cancel(scope.timerInterval); scope.onBreak = false; scope.isBreakRunning = false; scope.tasktime = TIME_TASK; scope.buttonText = "Start"; } };
expireTimer()
stops all timer countdowns at 0. If the user has completed three or fewer work sessions, it does this by calling checkRunning()
. If the user has completed four work sessions, it prompts the user to take a longer break:
scope.expireTimer = function(){ if (scope.tasktime === 0){ if (scope.sessionTracker <= 3) { scope.checkRunning(); } if (scope.sessionTracker === 4) { $interval.cancel(scope.timerInterval); scope.onBreak = true; scope.tasktime = TIME_LONG_BREAK; scope.sessionTracker = 0; scope.breakButtonText = "Start break"; scope.buttonText = "Start"; } } };
And this is all controlled using Angular’s $watch
method, which, well, watches the value that you give it – in this case, tasktime
, which is what I’ve called my timer – and does something when the value is equal to 0:
scope.$watch('tasktime', function(newVal, oldVal) { if (newVal === 0) { scope.expireTimer(); } });
My next task will be to allow a user to input tasks into my app, and then check off when they have completed them.
The first user story assigned in the Bloctime project is to allow the user to start and reset a 25-minute work session. Bloc breaks this into two sections: creating a button and tracking time.
Following a suggestion from Mentor Ben, I created a directive that handles the countdown clock and its button. The HTML linked to the functionality I’m going to talk about looks like this:
<div class="timer-content"> {{ tasktime | timeconvert }} </div> <div class="button-container"> <div class="button-styling"> {{ buttonText }} </div> </div>
I’m going to look at how I’m tracking time first, as some of my logic in doing this changed how I implemented my button.
One of the parts of learning to program I find particularly difficult is how abstract most of it is. For the past decade, I’ve been working in print design – an obviously visual medium that doesn’t require a great deal of abstract thought. So attempting to figure out how to translate seconds or milliseconds into a display of minutes and seconds was a challenge.
The solution I eventually landed on was to use a filter to convert my tasktime
‘s seconds – 25 minutes equates to 1,500 seconds – into a minutes:seconds display.
In what I am learning is fine tradition, I ‘borrowed’ the code from someone else to accomplish this – although I did rename the filter, as calling it timeconvert
made more sense to me than timecode
because I’m ‘converting’ the time to display how I’d like it to:
bloctime.filter('timeconvert', function() { return function(seconds){ seconds = Number.parseFloat(seconds); if (Number.isNaN(seconds)){ return '--:--'; } var wholeSeconds = Math.floor(seconds); var minutes = Math.floor(wholeSeconds / 60); var remainingSeconds = wholeSeconds % 60; var output = minutes + ':'; if (remainingSeconds < 10) { output += '0'; } output += remainingSeconds; return output; } });
Let’s break down CJMatson’s filter.
return function(seconds){
The first thing that we’re doing is telling the filter to return its result when we run it. This may seem obvious, but I’m often banging my head against my desk in frustration only to realise that while I’ve asked my function to do something, I haven’t asked it to give me back what the outcome is. We’re also telling the filter that it should expect a variable called seconds
.
seconds = Number.parseFloat(seconds); if (Number.isNaN(seconds)){ return '--:--'; }
The above two lines set the seconds
variable and provide a default if, for some reason, seconds
does not contain a number. The first line makes sure that if tasktime
contains a string, it is converted to an integer. The if statement dictates the view should the seconds not return an integer.
var wholeSeconds = Math.floor(seconds); var minutes = Math.floor(wholeSeconds / 60); var remainingSeconds = wholeSeconds % 60;
The next three lines make sure things are going to convert and display properly. Using Math.floor(seconds) converts any partial seconds to wholeSeconds, allowing us to then convert those seconds into minutes for the minute variable. remainingSeconds needs to be set because…
var output = minutes + ':'; if (remainingSeconds < 10) { output += '0'; } output += remainingSeconds;
…when we create our outputs, as in the above, if remainingSeconds is less than 10, we still want it to look like a clock, and therefore a ‘0’ needs to be added before the number.
return output;
Finally, we ask it to return the final output.
This was, by far, the easiest part.
I started off with a simple <button> that allowed me to start or stop incrementing an integer down using AngularJS’s $interval service. This was fine when I was simply trying to get the functionality working, but is also ugly and horrible and did not provide the look I wanted for this project.
Luckily, as any element can contain an ngClick, simply changing it to a <p> tag has allowed me to not only create more of the look that I’m aiming for, but also to add in a perfect animation (thanks to Animate.css) when the buttonText reads ‘Start’ to draw attention to the fact that you can click it.
The button needed to start the countdown, and when the countdown was running allow the user to reset the countdown process. Here’s how I did it:
scope.toggleTimer = function() { if (scope.isTimerRunning === false) { scope.timerInterval = $interval(function(){ scope.tasktime--; }, 1000); scope.isTimerRunning = true; scope.buttonText = "Reset"; } else { scope.isTimerRunning = false; scope.tasktime = 1500; $interval.cancel(scope.timerInterval); scope.buttonText = "Start"; } };
If the timer is not running (isTimerRunning = false
), clicking the button starts the countdown using $interval
, changes isTimerRunning
to true and modifies the buttonText
to ‘Reset’.
If the timer is running (isTimerRunning = true
), clicking the button changes isTimerRunning
back to false, cancels the $interval
, resets tasktime
to 1500 seconds and changes the buttonText
back to ‘Start’.
My commit for this step on GitHub
My next task is to let a user begin a five-minute break after their work session.
As I’m now 100% of my way through Bloc’s apprenticeship programme (according to their tracker) but I’ve got until early February before my term is finished, I’m planning to do as many of the remaining projects as possible.
With that in mind, and as I’d just finished up my first project using Firebase, I decided to do the Bloctime project next. Bloctime is a time-management application based on the Pomodoro technique, which means you have timed work sessions of 25 minutes followed by a five-minute break. After four sessions, you’re prompted to take a 30-minute break instead of a five-minute one. I’ll eventually be using Firebase to track the names of the work sessions.
The following are the user stories I’ll be working through on this project:
Because I used Bootstrap on my previous project, I’m not going to be using it on this one – I’d really like to make sure that my knowledge of CSS continues to evolve, and because it’s such a great library Bootstrap does half the hard work for me.
I finished my self-destructing task list project some time ago, but as I’ve been generally crap at updating this blog it shouldn’t come as a surprise that I completely forgot to write about it. I like to think this is not me being slightly useless, and prefer to pretend that I’m just so very busy creating more code that I just don’t have time to record the thought process. ^^
One of the most difficult things about this project for me was figuring out how to conditionally apply one of three CSS classes.
In story 6, Create new tasks, I’m asked to allow priority selection when a user is adding a task to the list. This in itself was easy enough, using one of Bootstrap’s dropdown buttons and populating the dropdown options with an array defined in my .js file, which also sets an ID for each selection that is stored as todo.priority
.
I wanted to communicate the urgency of each task in a simple to understand, visual way that didn’t involve adding any further text – such as ‘Urgent’, ‘High’ or ‘Low’ – to each task. But how could I create an element that would change class, and therefore how it looks, based on the priority selected for each task?
At first, all I could find were Stack Overflow were ways to apply a class based on a true/false value; in other words, I could apply one of two classes as long as something evaluated to true or false. This wasn’t what I wanted at all – I needed to apply one of three classes to the same element.
After going round in circles for a while, I finally figured it out. Using ngClass
, I then asked my element to check what it should look like using my setIndicator()
function:
$scope.setIndicator = function(todo) { if (todo.priority == 0) { return 'priority-urgent'; } if (todo.priority == 1) { return 'priority-high'; } if (todo.priority == 2) { return 'priority-low'; } };
This seems straightforward and simple, but – as always – the most obvious part of the above was the part that took me the longest. The key bit that I’d been missing from many of my previous attempts was that I needed to have my code return what the conditional class should be.
Once that was done, I had a great looking list, helpfully colour-coded by priority; red for urgent, yellow for high and green for low.
There are a few more things that I’d like to do with the above – including adding some touchscreen functionality, organising multiple lists and asking users to authenticate to use the app – but what I’ve done so far is the core of the project. I’ll be moving on to the next project and plan to save the extra functionality for when I’ve finished the course and am looking for a developer role.
My next Bloc project is to build a single-page, self-destructing task list using Firebase.
Bloc divides each project into separate user stories that each build on the previous. This project has six – not counting the ‘extra credit’ stories that add mobile-friendly features and complexity:
One area where I find the Bloc curriculum completely frustrating is in the expectation that someone doing what is essentially an entry-level, learning to code course is going to be able to diagnose and fix errors within the development environment.
Getting going on this project took me about two weeks (hence the lack of updates) because, for reasons that are beyond my current ability to understand fully, the virtual machine set-up that Bloc takes you through during the foundation section refused to install Grunt. Which meant that I couldn’t start doing anything, really.
Mentor Ben spent nearly an hour attempting to figure out why it wasn’t working, without any kind of solution. Luckily, as my husband is a .NET dev, he did eventually get it sorted out… after two days of working on it most of the evening.
At one point Mentor Ben suggested that it might be worth me investing in a Mac, which I think is a bit of a ridiculous ask. I can’t be the only student who has had this kind of issue, and I simply don’t believe it’s because I’m using a PC instead of a Mac.
As it’s not a course about setting up a development environment, I do think that Bloc needs to have better support for this kind of instance – perhaps a dedicated person that can help without using precious mentor time.
Although Bloc divides setting up the backend for this project with displaying a list of current tasks into two separate user stories, this didn’t make that much sense to me – after all, if I’m generating tasks and they’re appearing in my Firebase dashboard, it’s easy enough to also get them to display in my UI with basic styling.
However, I yet again had a stumbling block to connecting up the backend, helpfully provided by Bloc itself: the wrong version of Firebase and AngularFire.
After going through several tutorials and entering the pulling-out-of-hair stage after about four hours of nothing that I did working, Mentor Ben looked at my code and asked: “Why are you linking to an old version of Firebase?”
::headdesk::
So that’s working now.
And just for fun, here’s a screenshot of what my task list currently looks like, now that it’s correctly wired up to Firebase and displaying tasks:
There were two more things that I needed to do to finish this project. The first was to add some basic animations to the text of the Bloc Jams landing page, as well as creating a more complex flip animation on the album covers to make things more interesting. The second was to make sure the Bootstrap grid holding the images was responsive and that it sat in the centre of the page regardless of size.
I started with adding simple animations to the landing page’s introduction text using Dan Eden’s wonderful Animate.css. This was a very simple addition to my CSS and required the addition of a few classes to my HTML tags. While I’ve written my own basic animations previously it’s fantastic to simply be able to plug in a few lines of code and just have things work.
The flip animations needed to function as in the GIF below (created by Bloc):
This was actually super simple, thanks to David Walsh’s post on creating a CSS flip animation. It required a tiny bit of messing around with the CSS in order to position the ‘back’ of the album in the correct place for my project, but otherwise this was straightforward and easy.
My commit for this step on GitHub
The next step was considerably harder and took me a solid day to figure out. Part of the problem is that when creating the page in the foundation section you start with the following:
<div class="landing-album-list container"> <div class="row"> <div class="col-md-4" ng-repeat="albumURL in albumURLs"> <img ng-src="{{albumURL}}"> </div> </div> </div>
And after adding the flip animations, this is what I was working with:
<div class="landing-album-list container "> <div class="row"> <div class="col-md-4 flip-container" ng-repeat="albumURL in albumURLs"> <div class="flipper"> <div class="front"> <img ng-src="{{albumURL}}"> </div> <div class="back"> <h3>The Colours</h3> <h4>Pablo Picasso</h4> </div> </div> </div> </div> </div>
While both the above are using the correct Bootstrap classes container
and
row
, along with col-md-4
to dictate the width of the items within the row, unbeknownst to me – at this point in the process – was that the default grid isn’t responsive. The grid also automatically aligns left, which, in my opinion, is pretty idiotic – in most cases, while you might want to change the alignment of content within the grid I think that you’d generally want it to remain centred on the page.
In addition, there are some further classes that the img
tag requires in order to scale the images as the grid changes in size and that hold the contents of each cell in a row to the centre of that cell.
Finally getting the grid to act responsively had the unfortunate effect of totally ruining the flipping animation, which meant that I had to revisit the CSS for this section. In the end, however, I (mostly) got things appearing as I wanted them. I’m not posting my CSS as it would be easier to see what’s changed through the link to my GitHub repo for this commit below. Here’s what my final HTML looked like:
<div class="landing-album-list"> <div class="landing-album-grid-padding"> <div class="container-fluid"> <div class="row-fluid"> <div class="col-xs-12 col-md-4 flip-container" ng-repeat="albumURL in albumURLs"> <div class="flipper"> <div class="front"> <img class="img-responsive center-block" ng-src="{{albumURL}}"> </div> <div class="back"> <div class="back-background center-block"> <h3 class="text-center">The Colours</h3> <h4 class="text-center">Pablo Picasso</h4> </div> </div> </div> </div> </div> </div> </div> </div>
My commit for this step on GitHub
As I’ve now essentially finished this project, I’ll be moving on to my next one: Bloc’s self-destructing task list with Firebase.
One of the suggestions that Bloc makes at the end of the foundation section is that ‘done is better than perfect‘.
I’m mentioning this because while I absolutely got my problem menu chevron to rotate when it’s clicked, I didn’t do it using solely CSS3 transitions/animations as my mentor suggested.
As you can see, I’ve used the ngClick event to trigger the transition. This may be what my mentor had in mind, but as he’d linked me to a post he wrote on CSS Tricks about animations, I somehow doubt it.
However. It works. Correctly. Every time. And I think right now, that’s something to celebrate. (Even if I’m not entirely sure how and why, or if I’ve now got a load of superfluous code that does nothing except for looking pretty.)
In attempting this, I also learned something that is likely obvious to anyone who has been working with Angular for any length of time – in other words, not me.
You can only have one ngApp definition per page/site. As my index page’s html tag includes ng-app="BlocJams"
, which is how I’ve embedded the rest of the Angular functionality in the page, using the example from Ben’s article on CSS3 animation with Angular didn’t work for me because I was trying to establish a second Angular app within the page.
Figuring this out took a frustratingly long time.
Well, that goal of posting once a week went out the window, didn’t it?
In the middle of July, just before going on holiday for around three weeks, I finished the Bloc foundation course. Anyone familiar with the Bloc front-end developer curriculum will know that the foundation level involves building a single-page app for a site called Bloc Jams (my repo on GitHub) using AngularJS.
The goal of the foundation level is to introduce you to the concepts you’ll be working with for the rest of the course and mainly involves copying, pasting and walking through why you’re being asked to do what you’re doing.
One of the next projects is to take Bloc Jams and make it more mobile friendly, as well as adding in some CSS animations. The first part is to make the app look like the below (created by Bloc):
Thus far I’ve managed everything bar the dropdown menu – or, at least, getting the chevron in the dropdown menu to animate on click.
I think this is going to involve either the ngClick or ngAnimate functions within Bootstrap, but currently I feel at a bit of a loss. I’ve asked my Bloc mentor, the wonderful Ben Simmons, for help in terms of pointing me in direction of some helpful information, as I’m not sure whether I’m going the correct direction.