(This post is part of my “from scratch” AngularJS project. If you are feeling lost, the first post is here.)
Foreward
The coding portion of this post was BY FAR the most amount of time and effort I’ve put into any of them so far. My CSS skills were very rusty, so I had to do a lot of research and back and forth to get things right. More advanced front-end people may find some issues with my code, but it is, as always, a work in progress.
Experience
While our blackjack game is technically correct, it has all the glimmer of a game written for the TI-82. Don’t get me wrong, I love bootstrap, but for a game, it just isn’t enough.
New Visual Style
Here is what our game currently looks like:
If you walked into a casino and had to play blackjack this way, you’d definitely find another casino quickly. Luckily for us, we’ve already setup most of our game objects as directives (game, hand, card) so we can go through and layout each item. Since most of this visual styling doesn’t have much to do with angular, I’ll just share some helpful links:
- http://www.google.com/fonts
- http://www.transparenttextures.com
- http://selfthinker.github.io/CSS-Playing-Cards/
Putting all those together, we get a much nicer looking game area:
Animations
The bad thing about angular is how fast it is. Well, let me clarify. It is tough to generate any suspense when the cards are dealt immediately to all players. The solution for suspense comes in the form of $timeout
. Let’s use our ‘card back’ state in the card directive to hide the card’s value:
<div class="card back" ng-class="vm.cardIndexClass" ng-if="vm.card.hideValue"></div>
Now, when we deal the card to the player, we’ll pause for a second before revealing the card:
game.dealCardToPlayer = function(card, animate, callback){ if(animate) { card.hideValue = true; game.playerCards.push(card); $timeout(function () { card.hideValue = false; callback(); }, 250); } else{ game.playerCards.push(card); callback(); } };
We also want to give the same suspense after we finish our hand and have the dealer complete, but since we are looping our commands through, it is a bit more complicated:
dealer.finish = function (callback) { var loop = { next: function(){ dealer.getHandValue(); if(dealer.handValue < dealer.minValue) { //Animate Card In dealer.hit(false, true, function () { loop.next(); }); } else{ loop.done(); } }, done: function(){ if(dealer.handValue > dealer.maxValue){ dealer.busted = true; } dealer.isDone = true; callback(); } }; //Reveal first card, then play: $timeout(function(){ dealer.cards.forEach(function(card){ card.hideValue = false; }); loop.next(); },500); };
Now we’ve built in some timeouts to generate some player anxiety!

Testing $timeout
Now that we are using the $timeout
service, when we run our tests, we don’t really want to have to wait like a regular user would. With the help of the angular team, we don’t have to! angular-mocks
comes with a custom $timeout
with a function called .flush()
. This will clear anything in the $timeout queue and immediately kick it off. Here is how I’m testing our dealer function:
it('should set isDone value after finishing', inject(function ($timeout) { dealer.deal(); expect(dealer.isDone).toBe(false); spyOn(dealer,'getHandValue').andCallFake(function(){ dealer.handValue = 23; }); dealer.finish(function(){ }); $timeout.flush(); expect(dealer.isDone).toBe(true); }));
By injecting $timeout, it makes it available to the test spec. You can see we’re doing dealer.finish()
then immediately calling $timeout.flush()
to not have to wait for the timeout to finish before checking our expectations.
Finally
Now we’ve got it looking pretty, the next step is to actually deploy!