Documenting my attempts to learn AngularJS. I know almost no javascript. I’ve focused on C/embedded programming mostly, with some python and Java, but no Javascript. When I was in high school, I used to mess around with static HTML/CSS web pages with niblets of javascript thrown in for spice. In college, messed around a little more with manipulating the DOM using javascript, but never did anything meaningful, and I have since forgotten. So I’m effectively starting from scratch here.

Using egghead.io.

Note: JQuery Lite is also included with AngularJS.

Step One: “installing” AngularJS

  • Add Angular script
    • Instead of downloading angular and including it on the web server, recommended to source it directly from google’s CDN: angularjs.org has a link to it under Download.
    • I will be using 1.3.x (latest version)1.2.x since it is what the tutorials use
  • Initialize the app with ng-app
    1. Add ng-app to the html tag
    2. Bind h1 tag to a “property” called hello: <h1>{{hello}}</h1>
    3. Add input field with ng-model="hello". This way, whatever is entered in the input field will update the h1 tag.
  • Simple two-way binding with ng-model
<!DOCTYPE html>
<html ng-app>
  <head lang="en">
    <meta charset="UTF-8">
    <title></title>
  </head>
  <body>
    <h1>{{hello}}</h1>
    <input type="text" ng-model="hello" />
  </body>
  <script type="text/javascript" 
          src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.3/angular.min.js">
  </script>
</html>

Step Two: Two-way Binding

Binding is a mechanism for tying your HTML to your data, via {{expressions}}. Many expressions can be evaulated within the curly braces, but should be kept to a minumum. Very useful for creating input and giving users a way to interact with the site. Lets you manipulate a LARGE part of the DOM… not just text, but element classes, for example.

Step 3: Controllers

Controllers connect the markup with the data. <div ng-controller="FirstCtrl"> Provides the data that the data bindings will use. Everything inside that div will have the “$scope” of that controller. The controller can modify the scope. e.g. $scope.data = {message: "Hello"}; Global controller functions are apparently no longer enabled by default in 1.3. So I’m reverting back to 1.2 to learn.

Step 4: Sharing Data Between Controllers

First, the example shows how if there’s a parent scope, both children can inherit from it. But there’s a better way… creating a service. This is done with a factory. After you have a service which in this case the service is called Data and it returns an object with the string), you can share it with the controllers.

// myApp should be the name of ng-app in the html
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
  return {message: "I'm data from a service"}
})

function FirstCtrl($scope, Data) {
  $scope.data = Data;
}
function SecondCtrl($scope, Data) {
  $scope.data = Data;
}

Step 5: Defining a Method on the Scope

Defining a methon on the scope of the controller is pretty easy. Just define a function inside the controller, like thus:

function FirstCtrl($scope, Data) {
  $scope.data = Data;
  $scope.reversedMessage = function() {
    return $scope.data.message.split("").reverse().join();
  }
  $scope.reversedMessageBetter = function(message) {
    return message.split("").reverse().join();
  }
}

If any of the scope models change, this method will be invoked automatically on the new scope.

Step 6: Filters

Apparently the method from step 5 is the perfect use case for a filter. Filters let you create reusable text-manipulating functionality in an easy syntax. So let’s turn it into one.

You can add a filter to the App, for example the reverse filter would be:

myApp.filter('reverse', function() {
  return function(text) {
    return text.split("").reverse().join("");
  }
})

…and then in the html, you would use it like this:

<div ng-app="myApp">
  <div ng-controller="FirstCtrl">
    <input type="text" ng-model="data.message" />
    <h1>&#123;&#123;data.message|reverse&#125;&#125;</h1>
  </div>
</div>

Step 7: ng-repeat

The ng-repeat directive lets you repeat the same UI element over and over with each value from objects in a set. For example, generate a table from a list of actors and their roles:

<div ng-controller="AvengersCtrl">
  <input type="text" ng-model="search.$">
  <table>
    <tr ng-repeat="actor in avengers.cast|filter:search">
      <td>{{actor.name}}</td>
      <td>{{actor.character}}</td>
    </tr>
  </table>
</div>

Other built-in filters:

  • filter:search
  • orderBy:’name’
  • orderBy:-‘name’ – order in reverse
  • limitTo:-5 – show last 5 results
  • orderBy:’name’ limitTo:5 filter:search – show first 5 results alphabetically
  • lowercase, uppercase

Step 8: Directives

According to egghead.io, “The killer feature. That said, they are aguably the steepest cliff…”. Directives let you create HTML elements, attributes, and classes. e.g.:

var app = angular.module("superhero", [])
app.directive("superman", function() {
  return {
    restrict: "E",
    template: "<div>Here I am to save the day</div>"
  }
})
<div ng-app="superhero">
  <superman></superman>
</div>

What does this render? Here I am to save the day Cool.

You can also access the scope, element, and attributes from the directive. For example if you want to print “Hello world” using a line like this: <div my-first-directive="" message="world"></div>:

egghead.controller("AppCtrl", function() {
  var app = this;
  app.message = "Hello";
}
egghead.directive("myFirstDirective", function() {
  return function(scope, element, attrs) {
    element.text(scope.app.message + " " + attrs.message);
  }
})

Caveat: can do this more easily with a template in the directive, and typically want to avoid scope inheritance like this.

Step 9: Directives and Custom Behaviors

You can also use directives to set up some behaviors. This is the recommended way of interacting with the DOM. Shortcut: if all you’re going to do is use the link function in the directive object, you can just have the directive return a function(scope, element).

app.directive("enter", function() {
  return function(scope, element) {
    element.bind("mouseenter", function() {
      console.log("I'm inside of you!");
    )}
  }
})

Step 10:

Using directives to add/remove a class:

app.directive("enter", function() {
  return function(scope, element, attrs) {
    element.bind("mouseenter", function() {
      element.addClass(attrs.enter);
    })
  }
})
app.directive("leave", function() {
  return function(scope, element, attrs) {
    element.bind("mouseleave", function() {
      element.removeClass(attrs.enter);
    })
  }
})

…and the HTML: <div enter="panel" leave>I'm content!</div>

Step 11: Isolated Scope

Directives need isolated scope for many meaningful behavior. The syntax is confusing me at the moment. I think I’ll resume this at a later date.