befriending AngularJS

Over the past few weeks, I've explored Angular's architecture while building a Twitter replica, a tool for non-profit dashboards, and a to-do application. While it's relatively easy to get an app up and running, it's far more difficult to understand just how the MVVM architecture works - and how to optimize it for more complex apps. To that end, I've developed a workflow for beginning a basic Angular app.

My Workflow for Architecting Angular.js Applications

  1. I always start with the view (likely a .html file), and define the DOM elements that I want to be in scope for my Angular application. Angular is flexible in defining its own scope -- unlike Backbone, you can utilize Angular for only pieces of your application. Defining Angular's scope is as easy as inserting an ng-app directive into the relevant html tag. In the view, I also define a ng-controller, as well as any user inputs that I wish to translate into action.
  2. I then build controllers in .js files. In the controllers, I define the functions that will update the $scope object by calling services and factories. Note that controllers should not handle the model updating or logic themselves; this should be outsourced to the services and factories.
  3. Finally, I write the services and factories that return an object with defined properties and methods. The $scope object can then be updated by setting a $scope property to a property of the returned object.
Factories:

Services and factories are extremely important in Angular. They should always be utilized (in lieu of the controller) for updating models. Models in Angular are essentially properties on the $scope object.

Factories in Angular return singletons, which are objects that are instantiated once at an application's runtime.

A basic implementation of a factory looks like this:

var app = angular.module('myapp', [ ]);

app.factory('myFactory', function ( ) {

     var factoryInstance = { };

     var factoryInstance.message = "";
     // some code that adds properties or methods to the factoryInstance
     factoryInstance.sayHello = function ( ) {
         factoryInstance.message = "Hello!";
     };
     return factoryInstance;
  };

Creating a factory returns an anonymous function that returns the 'factoryInstance' variable. One thing to remember here is that by default, using a factory to instantiate an object makes use of the functional instantiation pattern. You must create a new object and return it explicitly within the body of the factory.

A factory's methods are called in the controller:

app.controller('myController', function($scope) {  
    $scope.message = "";
     $scope.sayHello = function ( ) {
          factoryInstance.sayHello( );
          $scope.message = factoryInstance.message;     
     };
};

The controller accesses the factoryInstance properties to update the $scope object, which acts as the model and passes along its information to the view.

<div ng-app= "myapp">  
    <div ng-controller= "myController">
         <h1> {{ message }} </h1>
    </div>
</div>