Book Review: Learning AngularJS by Ken Williamson

One of my plans for 2015 is to read a lot more development-related books, so you’ll see book reviews of JavaScript, CSS (a skill I need to improve), responsive design, and various other front-end topics. I recently bought a Surface Pro 3 (awesome so far), I thought I would use it to read & review something prior to the 2015 kicking off. Some of the reviews will be long(ish) and some will be more brief, depending on how much I learned from the book.

My first review is for Learning AngularJS by Ken Williamson. Before I jump into it, I should mention this book is an “Early Release”, which means it is not the final edition. I assume the content is mostly there, but some editing and polish remains. With that out of the way, let me pass on my thoughts…

I’ve been working with AngularJS for quite a while now, maybe 18 months (my Github repo). That means I am not the target audience for this book. But having read several AngularJS books (and having read tons of tech books during my career), I would like to think I know what makes a good beginning book. I’ve also done some recent pre-publication technical reviewing for Packt and Manning (and O’Reilly several years ago). And I’m afraid to say that I don’t think this would qualify as a good beginning book on AngularJS. In fact, I’m a bit confused about the target audience for this book. If you are a developer, this book won’t help you learn enough AngularJS for it to be useful. If you are a designer, it might help you understand enough to add some html to a page that contains Angular. If you are a manager, it might give you a high level overview of the different pieces of Angular (animation, routing, directives, services, etc).

The biggest problem is that the book is SO shallow, I don’t see how it offers any benefits over other introductory Angular books or even many of the free online tutorials and blog posts. For example, the chapter on directives explains how to define a directive, how to restrict them to elements, attributes, classes in the html, and how to pass an html  attribute into the directive. That’s it. Nothing else.  The chapter on services shows you how to define a service module, and make some basic calls with $resource. Pretty much all of the chapters are this way. The book gives you just enough info to READ some Angular code, but nowhere near enough to actually do coding in Angular. If you view the Table of Contents, you’ll see that almost half of each chapter is devoted to testing. Great! No…the testing is so basic that it isn’t useful, other than as a skeleton for how to write your first, basic test.

To say something positive, the author does point out useful tips occasionally throughout the book. But without major changes to the content, I wouldn’t recommend this to a developer who needs to learn AngularJS. If you are interested in a super high-level view of Angular, just to get an idea what its about, you might get something from this book. But you could also find this info for free on a ton of blogs (see my Angular Learning repo on the Github account).

I’ll keep an eye out for the final book to be published (the current pub date is March 2015) and update this review if the book’s content changes significantly.

Some Angular 1.3 Links

I decided to take some time earlier this week to find some blog posts around the new features in Angular 1.3 so that I could add them to my github repository. I thought I would also list the links here, in case some of you wanted to do some Angular 1.3 reading over the holidays (for those of you in the US who celebrate Thanksgiving).

If you know of other Angular 1.3 links that I am missing, please let me know. I’m mostly looking for articles that focus on the NEW features in Angular 1.3…

Taming Forms in AngularJS 1.3
Asynchronous form errors and messages in AngularJS
$touched is the new $dirty – AngularJS Migration Guide 1.2 to 1.3
Exploring Angular 1.3 – One-Time Bindings
-Exploring Angular 1.3 – ng-model-options
Working with Validators and Messages in AngularJS
Exploring Angular 1.3 – Angular-Hint
Exploring Angular 1.3 – Stateful Filters
ngEurope: what’s new in Angular 1.3?

The Never Ending Parade of Verizon System Errors (iPhone 6 Plus)

This post is basically a vent session about my attempts to buy a new iPhone 6 Plus, and constantly being foiled due to Verizon (?) systems errors. I know this is a big list of first world problems, and I know how lucky I am to have a job, a family, a house, etc. But the thoughts below are those a frustrated gadget geek 🙂

Sept 12

Like many, many others, I decided to wake up in the middle of the night to pre-order the new iPhone 6+. I knew there was going to be a big demand for these new, larger iPhones. So I expected there to be issues trying to pre-order online. Since the pre-order started at 2a CST, I set my alarm for 1:55a. I woke up, logged in to the Verizon Wireless website, and right at 2:00a I started my order. Everything was going well, and by 2:03a I had my iPhone in my cart and was nearing the end of the order process. Things were going way better than I expected. Then everything came to a suddent halt. I saw an ECPD (I think that is the right code) on my screen. I kept refreshing the page, kept getting the same error. I started my order over a couple of times, same error. Did some searching on MacRumors and Reddit and saw many others complaining about the same issue. As the error repeats, I watch the order delivery date for the iP6+ start to slip into October. By 3a, an hour into the process, I’m tired and frustrated. But I keep thinking, “its been an hour, certainly it will be fixed soon”. I keep trying to order, and see that others are beginning to have success. 3:30a now, still no luck. On reddit, I see someone mention having success ordering on their iPad. Naturally, this makes no sense to me, since the backend system should be the same whether I order from my PC or my iPad. But, its now 3:45a, so I try my iPad since my PC still reports the same error on the Verizon site. From my iPad, I visit the same url, login to My Verizon, and am finally able to complete my preorder at 3:56a. Ship date is now 10/7. Good times. (Apparently this error affected customers who receive employee discounts)

Sept 16

Other than receiving my confirmation email, I’ve gotten no other feedback about my order. And when I check My Orders in my Verizon account, I get an error message. Yeah, for 6 days, instead of my order, I get a “technical difficulties” message in My Orders. I finally chatted with a Verizon rep online, who confirmed that my order was in the system and there were no issues.

Sept 18

I still can’t view my order, but I see movement on the preorder status checking website. My order has moved up to 10/3. Yippee!

Sept 21

Despite all the talk of shortages on the iP6+, I head to one of the local Apple stores at noon, hoping to get lucky. There are only 10 people in line, and I found out that, yes, they do have an iPhone 6+ 64GB Space Gray for Verizon! I reserve my spot in line, thinking my phone luck is about to change. After 45 minutes, I’m in the store with the iP6+. Near the end of the purchase (I am a Verzion Edge customer, and am “Edging Up”), the Apple order system reports an STL or ST1 error. The Apple employee says this happens sometimes, and it usually resolves itself. He tries a few more times, but the error keeps occuring..during the step where he is trying to print my new Edge agreement. The ordering system finally tells him to call a number to resolve the issue. He calls, and the first operator he speaks to says that the issue is because Verizon no longer offers Edge. I manage not to laugh, somehow, and tell the Apple guy there is no way that is true. So he restarts the order, same issue. We are now 90 minutes into the purchase process, with no phone. OH! And to get this far into the order, I had to cancel my existing preorder. I figure that is ok, since I’ve got the phone IN MY HANDS now, right? Anyway, the order is restarted, and the error occurs again, while trying to print the Edge agreement. After refreshing and getting the same error for 10 more minutes, he calls the support number again (not sure if this is Apple internal systems support, or Verizon support). After a 15 minute wait on hold, he gets a rep. The call disconnects. He calls back, and is on hold 20 minutes this time. Finally speaks to someone, and they check my account and everything is good on their end. The order should be working. The apple guy tries the order one more time, but no luck. At this point, I am holding the last Verzion iP6+ 64GB Space Gray for sale in Middle Tennessee. And due to sysem errors, I can’t buy it. And they won’t hold it for me, even though the issue is with their system, and not me. At 4p, 4 hours later, I leave the Apple store without my new phone, and without my pre-order. Pre-ordering now is a November ship date. Good times.

And, to make things even better, 20 minutes after walking out of the Apple store, Verizon deactivates my current phone. I guess we got far enough in the process at the Apple store for Verizon to think I’m buying a new phone. So now, I have lost the new phone purchase, my pre-order, and my current phone no longer works. Awesome!

We have dinner and I try to get control of my frustration of the previous 4 hours. On the way home, we drive by a Verizon store. They close in 15 minutes, but I decide to run in anyway. They have iPhone 6’s, but no pluses (as expected). Since I no longer have a working phone, I decide to buy the normal 6 and see if its big enough (my previous phones were a Note 3 and an LG G3, so I am prefer bigger screens). I’m also curious to see if Verizon can complete a purchase for me, since the Apple store could not. 15 minutes later, I am walking out with the iPhone 6. No issues during the purchase, finally.

Sept 23

While I like the iPhone 6, I decide I really want a 5.5 inch screen. So I return the 6 to the store, and reactivate my LG G3. I decide I’ll call stores each day until I track down a 6+

Sept 24

I run to the other Apple store at lunch, but they are already out of the 6+’s they had received early that morning. I decide to stop by Best Buy, not expecting anything. However, it turns out they had just gotten a new shipment in within the last hour, and they had a rare 6+ 64GB Space Gray. Hooray! Before we can even start the order, the computer the BB guy is using freezes. He switches to a different computer. Its running slow, but seems to work. He is working through the order process, and BAM!, a “Manual Review Needed” screen pops up. Naturally, I can’t believe this is happening again. He calls Verizon, and once again they say everything is fine on their end. This time, another customer is also trying to Edge Up, and is getting the same error. Makes me feel a little better, knowing its not just me. After sitting there for an hour with no resolution, the BB guy tells me I can leave, and he will hold the phone while the system issue is being resolved. So, AGAIN, I have a 6+ in my hands, but walk out without it due to another system error (and to keep this clean, I won’t mention the other things running through my head).

I call back around 4:00p, but they are still trying to resolve the issue. At 5p, the BB guy calls me back, saying the issue still hasn’t been resolved, and probably won’t get resolved today. However, he spoke to his manager, and they will continue to hold the 6+ for me while the error is fixed. He does tell me that the issue was resolved for the other person. But no one knows why my purchase won’t complete. Verizon shows everything is fine in their system. Apparently my issue has been raised a couple of levels and is being worked on.

Now

So that is my story so far, about trying to buy a new iPhone 6+. I’ve been thwarted 3 (!) separate times due to some sort of system error. The first error affected  thousands, or tens of thousands of people during the pre-order phase. I’ve got no idea why I am “lucky” enough to have 2 other errors prevent me from buying the phone. I know there is nothing wrong with my account, as multiple Verizon reps have checked and it looks fine (and I have no late payments, excellent credit, so none of that could be causing the problems, either). Not to mention I was able to Edge Up at a Verizon reseller (i.e. not a Verizon corporate store). It seems like I am experience a strange bug that is preventing me from Edging Up at a 3rd party store (Apple & Best Buy).

Hopefully the issue is resolved tomorrow (Sept 25) and I can report that I’ve finally purchased a 6+. But even if BB calls tomorrow to say the issue is fixed, I won’t believe it until I actually walk out of the store with the phone. Being a gadget geek, I’ve always enjoyed the excitement of buying a new phone on release day. But after this parade of frustration, I’m just exhausted from the whole process.

So that is my story.I know there are a lot of bad things going on in the world at the moment, and complaining about a failed phone purchase(s) is silly..but I needed to vent..and I thought this blog was the perfect place to do that 🙂

AngularJS: Use constant service Instead of Magic Strings

Depending on your programming background, this tip might look a little strange. As I’ve mentioned before, I spent the first 15 years of my career as a java developer. One of the first things I was taught was to avoid “magic strings”. The term “magic string’ is really just another term for a string literal. To relate this to Angular, below is an couple of example of a magic string/string literal:

// UI Router config in app.js
$stateProvider.state('locationDetails', {..rest of config obj...};

And navigating to the state above in another file…

// in locationsListingCtrl.js
$state.go('locationDetails');

Both of the examples above feature a hard-coded string literal. In the first case, we are defining a state called ‘locationDetails’. Any piece of code that needs to navigate to this state will also use a magic string:

$state.go('locationDetails');

The problem is that ‘locationDetails’ is now scattered across multiple files. A simple misspelling can cause your code to be incorrect. Or if you decide ‘locationDetails’ is too long and you want to rename it ‘locDetails’..now you have to search the project for all instances of ‘locationDetails’ and replace them with ‘locDetails’. Sure, your text editor can help you with this, but it doesn’t change the fact that your code is more fragile than it needs to be.

So how can you fix this? Angular’s constant service to the rescue. I’ve updated the angularBPSeed project to add the following module:

.constant( 'STATE', {
    'MAIN': 'main',
    'LOCATION_DETAILS': 'locationDetails'
})

I’ve defined a constant service called STATE. As the name indicates, I will use the STATE service to define constants needed by UI Router. A nice thing about the constant service is that it is available in the config service. That will allow us to use constants when configuring out UI router navigation. For example:

.config(['$stateProvider', '$urlRouterProvider', 'cfpLoadingBarProvider', 'STATE',
    function ($stateProvider, $urlRouterProvider, cfpLoadingBarProvider, STATE) {
        ...omitting some code.....
        $stateProvider.state(STATE.LOCATION_DETAILS, {...rest of config...});
        ...rest of the config module below...

Two things were changed from the previous version of the config module. First, you can see that STATE is now passed in as a dependency. Second, instead of

$stateProvider.state('locationDetails', {...rest of config...});

We now have

$stateProvider.state(STATE.LOCATION_DETAILS, {...rest of config...});

The “magic string’ has now been replaced by an object. At runtime STATE.LOCATION_DETAILS becomes ‘locationDetails’, because ‘locationDetails’ is the value we defined for the LOCATION_DETAILS key in the STATE constant service.

This also means when we need to manually navigate to the location details state, instead of

$state.go('locationDetails');

we do this

$state.go(STATE.LOCATION_DETAILS);

(note that you will need to add STATE as a dependency to any angular module that accesses the STATE constant service we defined above)

So how does this help us in the real world? First, you are no longer using “magic strings”. Second, if you later decide that the location details state should be “locDetails” instead of “locationDetails”, you only need to make ONE change to your code:

.constant( 'STATE', {
    'MAIN': 'main',
    'LOCATION_DETAILS': 'locDetails'
})

You just change the value for the LOCATION_DETAILS key in the constant service. Throughout the rest of your app, any references to STATE.LOCATION_DETAILS will now resolve to “locDetails” instead of “locationDetails”.

This change makes your code less brittle, while removing the bad practice of “magic strings”.

As I mentioned, I’ve updated the angularBPSeed project to use remove magic string usage from the UI Router code. Check out the following files for more details: /src/app/app.js, /src/app/components/locationDetails/locationDetailsCtrl.js, /src/app/components/locationsListing/locationsListingCtrl.js

I also updated the Angular Best Practices Styleguide to add the following:

When possible, avoid using “magic strings” by using Angular’s constant service.

 

AngularJS Tip: Adding App-Wide Messaging

Yesterday, someone left a comment in my Angular Best Practices post, asking the following question (paraphrasing):

If a promise is rejected during the UI Router resolve, how do you let the user know?

I thought about it a bit, and decided to answer this question instead:

What is a quick and easy way to enable app-wide messaging?

By “app-wide messaging” I mean the ability for any module in the app to display a message to the user. So if an error happens in a service, or an error happens in a directive, there should be a consistent way to tell the app to display a message to the user. I’m not a fan of using dialogs or modals for this, so my solution was to use an Alert to display messages. I came up with a solution that feels pretty simple (note the solution below has been cleaned up, thanks to commenters on this post and on reddit/angularjs). Basically, there will be a new directive (called app-messages) and a new service (appMessagesService). When a message needs to be shown, a module will call appMessageService.addMessage(). The app-messages directive has a reference to the list of messages maintained by the service. So when a message is added to the service, the app-messages directive will display an alert to the user. If you want to see this code in the angularBPSeed project, check out the app.js file, services/locationLookupService.js, and all the files in components/appMessages. I’m also going to explain the solution in more detail below.

The first thing we’ll do is create the directive, called appMessages (app-messages in the html file). I’m not going to show the full contents of all of the directive files (you can see the full files in the seed project), but I’ll include the main logic from the appMessagesCtrl below:

    
var self = this;

self.alerts = appMessagesService.getMessages();

/**
 * closes the alert and removes it from the list of alerts.
 * @param alertIndex
 */
self.closeAlert = function (alertIndex) {
    appMessagesService.removeMessage(alertIndex);
};

The alerts array is used to store the messages to display. This array is actually a reference to the array stored within the appMessagesService. The service will be explained below, but it contains logic for adding and removing messages, as well as getting a reference to the list of messages. When the service modifies its internal array, the directive’s array will also change (since JavaScript objects are ‘pass by reference’). And since Angular is ‘watching’ our self.alerts array, when it is changed, our view will be updated to reflect those changes.

The html for the directive looks like this:

    
    
    <alert ng-repeat="alert in appMessagesCtrl.alerts" type="alert.type"
        close="appMessagesCtrl.closeAlert($index)">{{alert.msg}}
    </alert>

We are using the alert directive from the Angular UI Bootstrap project. The type attribute specifies the type of alert to display (warning, success, etc), the close attribute is the method to call when the ‘x’ is clicked, and alert.msg is the message text to display.

Next, lets look at appMessagesService:

var self,
    messages = [];

self.addMessage = function (message) {
    messages.push({
        type: message.type,
        text: message.text
    });
};

self.getMessages = function() {
    return messages;
};

self.removeMessage = function(messageIndex) {
    messages.splice(messageIndex, 1);
};
 

You’ll notice that the service has a private reference to a messages array. It also exposes methods to add a message, remove a message, and get the list of message. Unlike previous version of this code, the $rootScope and events are no longer necessary. Everything is encapsulated within the service.

An example of using the service to send a message (from locationLookupService.js):

    
    appMessagesService.addMessage({
        type: 'warning',
        text: "Error looking up location with locId: " + locId
    });

As you can see, the code is fairly simple. We use the appMessagesService to add our message. That’s it..nothing to it!

Finally, a snippet from the index.html, to show where the directive is added to the html:

    <div app-messages></div>
<div class="container" ui-view="page"></div>

You’ll notice that I added the appMessages directive to the div ABOVE the ui-view. If you are unfamiliar with Angular UI Router, the ui-view is similar to ng-view. In other words, the ui-view div is where the views for our SPA live. So, by adding the app-messages directive above the ui-view, it means the app-messages directive can be shown at the top of every view within our app. Sorta like a global message center. Obviously, if you only need to display messages within certain views, you can add the appMessages directive to those views instead of making it a global directive like I did in the seed project.

Before my next post, I think I need to find a plugin to make code snippets look nice 🙂

 

Edit: Changed the $emit to a $broadcast.

Edit 2: Per a comment here on the blog, and on reddit, I added a appMessagesService, which is used to send the messages. Post has been updated to reflect this change.

Edit 3: Per further comments and discussion, I’ve removed the dependency on rootScope and event broadcasting.

Angular Best Practices Seed/Template

Last week I posted about my Angular Best Practices Guide (as noted, it was heavily inspired by Todd Motto’s guide). As useful as a guide can be, nothing beats looking at real code. So I decided to create a simple seed project to show many of the best practices in action. The result of that work can be found here: angularBPSeed.

More details, including instructions on how to run and build the seed project, can be found on the project’s Github page above. I will also list some of the features of this seed below:

Features

  • An example app following many of the best practices from my Angular Best Practices Guide
  • Built-in Express server for serving the app during development.
  • An optional proxy server for CORS functionality. This allows you to serve the app from your local machine, and also make requests to a 3rd party server if needed.
  • Includes 2 services, 2 directives, 2 top-level views, an Angular UI Bootstrap modal, “fake” server call using promises, a loading bar displays during calls to the server.
  • Uses AngularJS, Angular UI Router, Angular UI Bootstrap, Angular Loading Bar, Bootstrap, Grunt, Browserify, ngAnnotate, html2js (for compiling templates and adding them to the template cache
  • 2 builds: grunt build is used during development, and grunt (the default task) will run the build and prod tasks to build a production-ready version of the app.

In addition to highlighting the Best Practices, I wanted to show how you can integrate Browserify (and thus CommonJS) into your project. Browserify is really easy to use, and using CommonJS adds minimal overhead to your project. I’m far from an expert on Browserify, but I can’t imagine not using it on a project.

To use this project as a template for your own project, just clone it remove (or rename and customize) the existing services, directives, etc. It should be fairly easy to use this seed as a skeleton to start your own project.

If you would like further clarification on the ideas behind the code in the seed, or further explanation of how something works, feel free to ask me in the comments of this post.

Quick Review: Days of Rage by Brad Taylor

While book reviews won’t be a focus of this blog (tech related stuff will be), I will still mention books I’ve read and liked. I recently finished the latest book in the Pike Logan series by Brad Taylor: Days of Rage.

Brief Thoughts:

The Pike books continue to get better and better. I’m not sure how how the author can continue to release 2 high quality books each yet, but he is doing it. This series is the biggest reason I’m reading spy/thriller novels again. As for this book, it continues to take Pike and his team into new territory. What I really like about this series is that you can see how events in previous books are affecting events in this book. In many series, it seems like each book is a standalone episode, with each book having minimal impact on the next. But in the Pike Logan books, the characters continue to grow (and unfortunately, die). These books and characters feel real…unlike many in this genre (in which the characters feel like they are just filling roles in the story).

I’m already looking forward to the next book (which I thought was due in Jan 2015, but now I can’t find a reference to it on Amazon).