Book Review: AngularJS Web Application Development Cookbook

So this is the third book review in this blog series, and I’m happy to say I’ve finally found a book I can recommend. I just finished reading AngularJS Web Application Development Cookbook by Matt Frisbie. The e-book version happens to be on sale for $5 before January 6, 2015, and I highly recommend it for that price.

As the title says, this one is a cookbook. Its not a tutorial, and I wouldn’t recommend it if you are new to Angular. The book has 10 chapters, and each chapter has multiple recipes (I believe the book description claims 90+ recipes). Each recipe is comprised of 3 sections: How To Do It, How It Works, and There’s More. The How To Do It section explains the purpose of the recipe, and contains the code sample. How It Works explains the code sample in more detail, and There’s More gives additional information about the recipe.

Even though I’ve worked with Angular for 18 months, I still learned a few things in the first 5 chapters. The chapter on testing (#6), was a bit of a disappointment, but that is really the only weakness in the book. I thought chapters 7-9 were excellent, even for more advanced Angular developers. In fact, I plan to go back and re-read those chapters as I didn’t fully understand the details of some of the recipes in my first read-through. Those 3 chapters explained how to speed up your Angular apps, using promises, and covered some of the new stuff in Angular 1.3. The last chapter contained recipes on Angular hacks, and I felt these were a bit mixed. I did not like the DRY Your Controllers recipe (I can’t imagine ever implementing that recipe in real life. I would solve the problem by using Controller As), and the recipe on using $parse to reference deep objects felt a bit too hackish. But those are minor complaints. Most of the book is well-written, interesting, and full of good stuff.

Overall, this is one of the better Angular books I’ve read in the last year. If you already know some Angular, and are looking to take your skills to the next level, you should add this book to your reading list. And do it fast so you can take advantage of the $5 sale.

Book Review: Responsive Web Design with AngularJS

This is the 2nd in my series of book reviews (my previous post was the 1st book review, also an AngularJS book). This time I am reviewing another newly released book: Responsive Web Design with AngularJS by Sandeep Kumar Patel. And like the first review, this isn’t a book I can make myself recommend (sorry!).

I was looking forward to seeing what this book had to offer. Since moving from being a java developer to a front-end developer 2 years ago, I’ve spent most of my time programming JavaScript, and not enough learning css & responsive design (which is one reason I’ve started this review series, as I plan to include design books in my reviews). I also wondered, having used AngularJS a lot, what I could have missed in regards to it supporting responsive design. So when I saw a book called Responsive Web Design with AngularJS, I had to check it out.

The book is short, just 5 chapters, and only 3 of them really focus on the topic of responsive design. Below are some thoughts about each chapter.

-Chapter 1: Introduction to Responsive Single Page Application and AngularJS

First, notice the small grammatical error in the chapter title. Those grammatical errors are littered throughout the book. Not a huge deal, but I do expect better editing from a professionally published book. And I thought some of the editing issues had an affect on the material. Moving on…there isn’t much to say about this chapter. The author describes the meaning of SPA, and gives a quick overview of the features of AngularJS. While obviously not a tutorial, the overview isn’t bad.

-Chapter 2: The AngularJS Dynamic Routing-Based Approach

I’m not sure about you, but my first thought was “what the heck does the Angular router have to do with responsive design”? Turns out (at least in my opinion) the answer is nothing. The author builds a service using $provider (why?) to determine the device type (tablet, mobile, desktop) based on width, then within the router, serves 1 of 3 templates. Thus there is a completely different template (and css file) for each of the 3 device types. While I’m fairly new to responsive design, this doesn’t sound like RD to me. Does it? My opinion on the book takes a hit…let’s see what happens in the next chapter.

-Chapter 3: The AngularJS Directive-Based Approach

This chapter begins by talking about the shortcomings of the approach from the previous chapter. Good. Though it makes we wonder why a chapter was devoted to the previous topic if it wasn’t a good approach. Just to have something to talk about maybe? Anyway, in this chapter, 3 custom directives are made: one for responsive images, responsive text, and responsive item lists. I’m honestly not sure the ideas in this chapter are any better. Each of the 3 directives has some duplicate code that is used to determine the device type. The directives attach a $watcher to the $window, listening for windowResize events. The code is listening for changes to the window’s width, so that it can change the layout of the page if needed. Seems a bit messy to me, and I don’t like having this device type logic in 3 separate places. Maybe this is a good idea, and those of you with more RD experience can correct me. But I don’t see my adopting ideas from this chapter, either.

-Chapter 4: The AngularJS-Based Breakpoints for Layout Manipulation

Again, maybe it’s my lack of RD knowledge, but the design in this chapter feels downright dirty (wrong) to me. Basically, the author sets up an event-based approach to setting breakpoints for changing the page’s layout. I won’t give away all the author’s tips, but basically a couple of watchers are set up this time, and when the width changes and drops below (or goes above) one of the pre-defined breakpoints, an event is broadcast. Then listeners for this event will catch it and modify the layout accordingly. Again, not something that feel’s right to me. This feels like an abuse of the pub/sub system.

-Chapter 5: Debugging and Testing Responsive Applications

This chapter had a promising title, but it was really just a collection of debugging tools and plugins you can use. There were some I had not heard of, which is good. But there isn’t really enough explanation into how to use any of them (though that info could easily be found on the website for most of the tools mentioned)

After reading this book, I don’t feel like I know any more about proper RD with Angular than I did before I read it. I guess I did learn a few ideas that I would NOT want to repeat in my applications, though. I believe my preference is to choose a CSS framework that will take care of most of the RD logic for me, so that I’m not littering my code with hard coded device widths and conditional logic. For those of you more experienced in RD than I am…what are you thoughts?

Also, I plan to read a proper Responsive Design book soon. Anyone have any recommendations? I would prefer something published in the last 12 months. My first thought is to read this one.

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.

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.

Yet Another Opinionated AngularJS Best Practices Guide

A couple of months ago, I created an Angular Best Practices guide for the team I was on at the time. The ideas for those Best Practices came from several places: blog posts, Github repos, personal experience, ideas from others on the team, etc (in other words, I’m not claiming credit for the ideas below. They’ve come from various places, people/coworkers I respect, with some personal opinions added). Now that I’ve started a new role, I wanted to update my Best Practices guide. The original version was just a Google doc, which I then imported into a Word doc. But, I had thoughts of adding it to my Github account in case others were interested. Then, a few weeks ago, Todd Motto posted his Angular Styleguide. While it contained some of the same ideas from my original document, Todd also had many more that I hadn’t thought of, but really liked. My document was also very light on code samples/examples, which was something I wanted to fix. When I saw that Todd moved his Styleguide to a Github repo, I thought I would just fork it instead of starting my over. I liked the organization and formatting of his doc, so it made sense to start from there.

I spent a few hours working on my tweaks to his Guide, and finished it up over the weekend. So my fork of his guide is missing a few things from Todd’s, and contains many more that I’ve added. I know some of my additions are personal preferences, but I added them because I think they can provide consistency in how projects are structured (especially the stuff in the Files category).

I haven’t decided yet whether to commit any of my changes back to his repo. I thought I would post them first in my fork and get some community feedback.

You can view my fork of the styleguide (which I am calling Best Practices) at my Github repo: AngularJS Best Practices Guide. I also hope to create another repo containing an Angular starter project (another Github repo) that follow these guidelines. That way you can see what these guidelines look like when applied to a simple project.

I’ll list some of the additions I made below, but you’ll need to visit the repo to see further explanations and code samples:

General

  • When possible, use angular.element(), etc. instead of jQuery lookups and DOM manipulation.
  • Don’t wrap element inside of $(). All AngularJS elements are already jqobjects.
  • Do not pollute your $scope. Only add functions and variables that are being used in the templates.
  • Do not use $ prefix for the names of variables, properties and methods. This prefix is reserved for AngularJS usage.
  • Use ng-bind or ng-cloak instead of simple {{ }} to prevent a FOUC (Flash of Unrendered Content).
  • When you need to set the src of an image dynamically use ng-src instead of src with {{}}.
  • When you need to set the href of an anchor tag dynamically use ng-href instead of href with {{}}

Files

  • One module per file
  • Each file should get its own namespace
  • Each filename should match the controller/service/etc name
  • Function name and file name should match
  • Each file should be CommonJS compatible
  • A specific directory structure

Controllers

  • controllerAs ‘self’

Directives

  • Templating (avoid inline templates)
  • Each directive should live in its own directory
  • Use isolate scope in directives whenever possible

Routing Resolves

  • Promises (modified Todd’s entry to recommend ui-router, $stateProvider, etc)

AngularJS: Using $setViewValue and $render() to Update Models & Forms

Earlier this week, I ran into a situation in Angular that I hadn’t run across before. I had a form that had several fields: address, city, state, zip, latitude and longitude. The page also had a Google Map, that would allow the user to click on the map, and update the form fields with the newly selected address on the map. To give the user a visual clue that the form had updated with the new values from the map, I was using $dirty to change the styling of the form fields. To change the form fields, I was updating the model directly. However, it turns out that directly changing the model in a Controller, wasn NOT triggering the $dirty flag in my Angular form. It took me awhile to figure out what was going wrong, and how to solve it. I thought I would post my solution here, in case it might help someone else (or in case one of you might have an even better solution to the problem).

I don’t want to include my work code, so I created a plnkr to simulate the issue. You can view the plnkr here. Basically, I have 3 form fields. A snippet of one of them is below:

<div ng-class=”{‘has-warning’: myCtrl.simpleForm.city.$dirty}”>
<label for=”city” class=”col-lg-2 control-label”>
    City <span ng-show=”myCtrl.simpleForm.city.$dirty”>*</span>
</label>

<div class=”col-lg-2″>
    <input type=”text” class=”form-control” id=”city” name=”city”
        ng-model=”myCtrl.location.city”>
</div>

And in the controller, I am updating the model like so (in my real app, I would get the data from a service, but am keeping the code here simple):

self.updateModel = function updateModel() {
self.location = {
    city: ‘Atlanta’,
    state: ‘Georgia’,
    zip: ‘30339’
};

Notice that when you click the Update Model button, the model is updated, but the form fields are not marked $dirty, so the extra styling is not added to let the user know the form values have changed.

Doing some reseach on StackOverflow, I found a few references to the same problem, with the solution being to call $setViewValue() and $render(). Problem was, I didn’t know how to call $render. Thanks to the console.debug() statement, I dug into the object graph of one of the input fields and found a way to get the controller for each input. Once i have the ngModel controller for each input, I can call the $render() method on it.

So the answer turned out to be a 2 step solution. First, you update the view value in the input by calling $setViewValue. Updating the view value also triggers the $dirty flag for the view/input.

self.simpleForm.city.$setViewValue(‘Atlanta’);
self.simpleForm.state.$setViewValue(‘Georgia’);
self.simpleForm.zip.$setViewValue(‘37013’);

While this updates the view value, the mode value does not seem to get updated. (i.e if you just execute the 3 lines above, without $render(), the form fields will be marked $dirty, but the values in the form will not change). This is where $render() comes in. You need to tell the view (input) that just changed, to render itself so the model value is changed (so the new value displays in the form field). To call render, you need to get the ngModelController for the 3 elements we changed above. For example, the input for the city field has an id of city. We can get the controller for that input and call $render() on it like this:

angular.element(‘city’).controller(‘ngModel’).$render();

In the plnkr, you will notice that I made a utility method to call $render(), so that I could pass in an array of id’s to $render(). You can view the working plnkr here

So that is one way to update both the view and the model inside a controller, while also triggering $dirty on the form fields. I’m not thrilled with having to access the DOM in my controller, or having to reference element id’s in my controller. If someone knows of a better way to solve this issue, feel free to let me know in the comments.