I just watched Alicia Liu's HTML5 Developer Conference talk Levelling Up in AngularJs which had a lot of great information on common design patterns in Angular. I wrote some notes to make sure I really absorb the information, hopefully others will find them useful.
Views can be separated into modules
I've never seen anyone do this but I really like the idea, especially the concept of keeping your routes inside a dedicated module. This also would allow you to just remove a dependency from the main app to remove a view, which would immediately remove the route as well. She suggests the following:
- Separate your application components into individual modules to keep the code organized and allow for lazy loading of modules in the future.
- Define routes for each of those modules inside the module to avoid a huge route file.
Services vs Factory
I've been waiting for someone to tell me this is more than just a very subtle pattern, this is not really true. Services and Factories are both just convenience functions which help you register a provider.
- Services should be used with pre-defined object models, which are then exposed via the service.
- Factories should be used in all other cases.
Directives: Scope properties
I've always found the angular docs to be a little unclear in this area, I feel like Alicia helped clear it up for me. First the code:
@ prefix provides one-way string binding. In the example,
@enemyType is passed in to the directive scope as a string, and as you can see in the html it can still be based on a parent scope variable.
& prefix also provides one-way binding through a getter function. In the example,
onDestroy it looks like it is passing the result of
destroy(); I found this pretty confusing. What you're actually defining is an expression which will be called on the parent scope.
destroy() will be executed on the parent scope, and therefore when you define the template for the directive you still need to add the parenthesis to call the method:
ng-click="onDestroy()". On top of all that there is a special syntax for passing data into these methods, watch this, or play with this to learn more.
= prefix provides two-way data binding. In the example,
=lives is automagically available as a reference from the parent object. Additionally any changes made to the currentLives property on the child scope will also change on the parent scope.
This was also incredibly helpful in understanding the scope binding prefixes.
Communication between directives
How do you write directives in a way that they can be applied to the same element and then talk to each other easily? This is a pretty common problem that I've tried to avoid in several different ways. In her example Alicia uses
$watch to track the attributes on the primary
mario directive. This allows the
fireMode directive to act like a decorator and add additional functionality to
mario in a manner that can be reused with other directives using the same interface.
$observe vs $watch
Up till now I've only used
$watch to track
$scope values, this works pretty well but now that we've clarified all the easy ways to use attributes above, we need a way to listen to those changes directly.
$observe is a method on the attributes object which is passed in to a directives link function. In the example below
$observe is being put to use for this purpose. You can also use
$observe to avoid creating a scope altogether, and just observe changes that a parent makes to the attributes.
I didn't take notes on everything
I tried to focus on some of my favorite information from this talk but you might find some of the below valuable.