Some AngularJS notes
I wanted to brush up on my AngularJS over the last few days and I found some of my old notes - thought someone else may find them useful.
AngularJS introduction / notes
Key
Facts / description
“Angular way” / Advice
My judgement calls
Angular concepts
Scope
- Scope is the data model.
- Nested (like the DOM).
- Updates to scope are immediate.
- Forget Rails/ Django etc scope, its not like that.
- Scope just links things together (like UI and Data).
Controllers
- Typically represent a page in an application.
- Destroyed when navigating away
- Controller should prepare the scope.
- May be nested.
- Whenever possible delegate all the logic out of the controler - thin controler = better.
- Avoid DOM manipulation inside of them (use directives instead)
- May have a template(s) associated.
- e.g.
- Set Info controller (describe page)
- Set Media controller (upload/reorder/dragdrop)
- Set Caption controller (caption page)
Templates
- Can be partials (can include other templates)
- Can have some logic bits in them like if, foreach (but don’t go nuts)
- Can be inline or loaded via AJAX
- e.g.
- header + nav region
- set info page
- partial media item display
Directives
- Self contained “packages” that act on the DOM.
- Think of them either as widgets or widget enhancer.
- May be nested.
- Can include other bits of code (e.g. jQuery lib).
- Advanced crap (could be we don’t get this yet) :
- Can have an associated controller inside of it (for complex stuff)
- Can also have a controller along side it too (directive-controller)
- **Can communicate with parent scopes **
- They are instantiated in the template by using tags
- e.g.
- Drag and drop enhancer
- Char limit enhancer
Directive and Scope binding
- Demo code to help with understanding : http://plnkr.co/edit/nRnAhMMb5Kjr1ZwpIr7W
- You have 3 options @, & and =
- = (Two way binding)
- Magic and powerful
- This means, the
my-directive-var
is actually a pointer to the ngModel called name. That ngModel is then passed by reference into the directive. - So,
$scope.myDirectiveVar => ng-model="name" = OliverOriginal
and so changes to$scope.myDirectiveVar are actually changes to ng-model=name. - Go ahead and test the demo : http://plnkr.co/edit/nRnAhMMb5Kjr1ZwpIr7W
- You can edit ether input box and the other will update - cool eh?
- & (One way binding)
- This means, the
my-directive-var
is actually a pointer to the ngModel called name. That ngModel is then passed by value into the directive. - So,
$scope.myDirectiveVar => ng-model="name" = OliverOriginal
(just like in the “=” two way binding), but, changes to each are not reflected in the other. - If you set
$scope.myDirectiveVar = 'DaveDirective'
in the link function (see comment in the demo), it will get set only inside the directive, parent unchanged. - Any changes will also be local only.
- This means, the
- @ (Text binding)
- This means, the
my-directive-var
value name will have been “passed by value” into the directive. - So
{myDirectiveVar} = name
. - But.
$scope.myDirectiveVar == undefined
(* except if you use watch, see bellow). - Any changes made, as its by value, are local only.
- Always a string.
- Parsed (so
{{}}
stuff will work). - Expected only to be used with templates
- Not simply accessed/edited inside the directives link function, as its not yet interpolated (happens later in the loop)
- You CAN get access to the result, but requires use of the
$watch
function e.g. $scope.$watch(‘myDirectiveVar’, function() {
console.log($scope.myDirectiveVar); $scope.myDirectiveVar = 'WilliamWatcher’; });
- This means, the
Modules
- Modules in Angular are different ways of encapsulating data and logic
- Services, Factories and Providers
- There are two phases in the run cycle:
- Configuration: when the application boots
- Injection: when the module is created inside a controller that requests it
Services (object)
- Act as singletons (not destroyed between pages)
- Used to hold active data or provide functionality across the app
- No constructor arguments, injecting a service returns an object
- Useful for static data, like
{a:1, b:2}
- e.g.
- In current uploader: Set Service = Stores (and transmits) set information (title etc)
- In current uploader: Util Service = IPTC extraction, Thumbnail generation, etc
- Forward: General purpose code
- UUID - to generate uuids
- Util - for thumb generation etc
- When possible we should attempt to use Providers
Factory (a function that returns objects)
- Like services but provide a “constructor” with arguments
- Injecting it returns a function that creates services
- They are not shared between controllers
- Useful when you need to do ‘new Object()’
- e.g.
- While this can be used for modules that require some sort of parameters (like Piwik which requires username and site-id) we should attempt to only use Providers
Provider (an abstract factory with config)
- The only major (and very important) difference is that they can be configured before they are injected. This is really useful for testing.
- This allows to have every provider configured (api url, test url, api keys, permissions etc) before it is being used in a controller
- Allows the separation of config and code
- e.g.
- We should use providers instead of factories in almost all cases.
- We can use build Domain specific services as well as for stubbing/testing
- Set service with domain based validation and required field settings
- Any module that requires any type of configuration
Filters
- Transform data in templates
- Used for formatting data on screen
- e.g.
- epoch converter
- length trimmer + …
- File size converter
More reading and notes
- A good book = https://www.ng-book.com/
- Code structure/style guide = https://github.com/mgechev/angularjs-style-guide
- Groking Services, Factories and Providers
- *Simple demo to show all 3 working : http://plnkr.co/edit/SJCgOjcFj5pu5rjt8XUw
- Controllers in directives : http://jasonmore.net/angular-js-directives-difference-controller-link/
- When to use
$
$
’s prefix is for internal Angular methods and APIs - don’t use it in your own.- Nested vars with
$
won’t be rendered when interpolated e.g.<div ng-init="n = {noDollar: 'foo', $hasDollar: 'bar'};">{{n}}</div>
would show foo, not bar.
- USE BOWER!
- How i think about naming
- Folders :
/{package}-{name-hyphened}
- Module :
{package}.{nameCarmeleCase}
- Code :
{package}{NameCapitilized}{Type}
- e.g.
- Folders :
/acme-widget-maker
- Module :
acme.widgetMaker
- Code (directive) :
acmeWidgetMakerDirective
- Code (service) :
acmeWidgetMakerService
- Folders :
- Folders :
- Building more advanced directives - http://www.ng-newsletter.com/posts/directives.html
- From beginner to expert - http://www.ng-newsletter.com/posts/beginner2expert-how_to_start.html
Personal preferances
Skinny controllers
- Try to keep them small and simple
- Controllers are likely to be more domain specific than any other part of the app (so less code here the better)
- Most of the application logic should be encapsulated into directives and modules