Last Saturday, I gave yet another talk on getting started with AngularJS and with good success. I found myself wondering though, along the way, why is it that we keep needing these “getting started” talks with Angular? What makes it so complicated? Why do we need endless “basic” tutorials?

I think the answer lies in the fact that AngularJS docs do not prepare you for Angular and good getting started tutorials don’t exist in the top 10 of google’s results. On top of that, finding one of your developer friends being an expert in Angular is impossible. In the grand scheme of things, it’s a small framework. Especially compared to the behemoth that jQuery is.

On top of that, we’re in the age of Udemy and similar services where you pay for a class as a way to thank an expert for sharing their knowledge. All of this makes Angular on-boarding difficult.

So I would like to rewrite my talk for you as a tutorial. You can view the presentation itself here and the code examples for the presentation on my github.

So before we get to “how to use Angular”, let’s discuss “why” and “what” Angular is.

About AngularJS

AngularJS is an MV*-style javascript framework. You may already be familiar with MVC architecture: model/view/controller. In Angular’s case (and many other frameworks’), the “controller” part is a little muddy. Unlike traditional back-end frameworks, the controller isn’t the middle man between the request and response but rather, it’s a scoped object that may contain functions, additional logic, and helps every part of the application interact together.

Now, despite AngularJS coming into the mainstream just about two years ago, its initial release was actually back in 2009. Its development really took off when one of the original creators started working at Google and over time, Google put its weight behind it, making it enterprise-ready over time.

What do I mean by that? Well, if you’ve ever spent any amount of time in the development world, you’ll know that long-term enterprise-y projects are 10% solution, 10% optimization, and 80% legibility under which I also classify architecture, maintenance and similar concepts. AngularJS does a good job separating different portions of an application into various files where a view, for instance, does not conflict with a controller or other libraries. Nothing is necessarily tied together except via dependency injection.

And since it’s backed by Google, we can bet that it will be around for a few years and won’t disappear into the nether (similar to what happened to KnockoutJS, unfortunately).

During my talk, I wanted to emphasize just how greatly AngularJS is enterprise-ready. It’s like Zend or Symfony for PHP or (the default) Java. Due to its architecture, new developers can jump in after learning the basics of Angular since most applications follow the semi-rigid pattern that Angular sets up.

Lastly, keep in mind that Angular is a FRONT-END framework that runs single-page apps. That means that what makes it special is that it can load and interact with data without reloading the page or having to rely on the server to figure out how to display data.

“Single Page Apps” the Old Way.

Or, “via jQuery”. Single Page Apps didn’t really exist until recently but before that happened, we TRIED and (somewhat) failed to build SAPs via jQuery. Our “apps” were more of “let me use jQuery to fetch a page and copy/paste that DOM into the current page”.

So let’s see how this was done and what problems arise along the way.

App 1

$(document).ready(function(){
    $('#some-element').click(function(e){
        //some interaction
        e.preventDefault();
    });

});

Easy, right? I think we’re all used to the typical jQuery syntax of “dom ready” and binding our listeners. That’s pretty much jQuery: an easy syntax for adding listeners and have those perform some kind of functionality. When jQuery first came out, it became the sugar on top of HTML. Meaning that you could submit a form without refreshing a page, add some neat animations, etc. But, you couldn’t do any super fancy stuff.

Everything is all fine and dandy in the world if you stick to this pattern.

App 2

Let’s look at another example that will illustrate the shortcomings of this approach.

$(document).ready(function() {
    $('#some-element').click(function(e){
        $.get('/api/list-comments', function(data) {
            var $comments = $('<div></div>');
            $comments.addClass('comment-list');

            for(comment in data.comments) {
                var $comment = $('<div></div>');
                $comment.addClass('comment');

                var $link = $('<a></a>');
                $link.attr('href', comment.userUrl);
                $link.addClass('user');
                $comment.append($link);

                var $content = $('<div></div>');
                $content.addClass('comment-content');
                $content.html(comment.content);
            }

            $('.comment-list').html('');
            $('.comment-list').append($comments);
        });
        e.preventDefault();
    });

});

If your first thought after looking at this code is “ew”, then you’re correct. It’s terrible code. It’s terrible jQuery, but unfortunately, it illustrates the reality of using a javascript library without templates to, well, do a workaround and try to template data nevertheless.

Now, given, jQuery is not meant to be used this way, there are plenty of people who have and continue to do so.

There is no way to template with jQuery, that means that we either have to use strings to concatenate strings of HTML and then have jQuery interpret it or do as I did above. While factories may help (passing information to a dedicated function that will build all this stuff for us), they end up doing the same stuff as before, just nicer.

Let’s get into the bigger problems.

As you can already tell, that code above is not only unmaintainable, it’s difficult to follow and understand. This creates a big problem. You know how I said most projects are 80% legibility? We’ve just failed that.

Here are the under-lying issues:

  • listeners no longer work on new elements, the listeners have to attach on the parent-most element and wait for bubbling like so: $('body').on('click', '.comment-like', function() {});. This means, we’ll end up with a slew of listeners waiting at the top element where jQuery tries to figure out if the initial event dispatcher element matches what we need.
  • any state changes and updates have to be manually tracked. Since there is no two-way binding, we’ll need to implement our own listener/dispatcher system for data. To put this in perspective, if we have a counter for “comment likes”, we’ll have to manually fire off a “counting function” whenever a comment is liked, make sure that the comment is not double-counted, etc.
  • There is no way to build a multi-page app. Separate pages would have to be either stashed somewhere or “display:none”d similar to how tabs work.
  • Speed. Since we have to create work-arounds and extra code, we’ll most likely experience speed issues, this is something to consider. There are benchmarks you can check out on this matter, just make sure you dig deep enough to find fair and sensible comparisons.
  • jQuery isn’t difficult to maintain by itself or for the purposes it was created. There are even certain design patterns for using jQuery; however, if you’re trying to build a single-page-app with jQuery, you’re better off hammering a nail with a t-shirt.
  • Again, templating. Templating, templating, templating is the biggest issue here and AngularJS is pretty much the best framework out there for dealing with that.

Enter AngularJS

So what does AngularJS bring to the table? Lots:

Routing – server-side-like routing that allows us for the application to change the URL. Historyjs-like functionality included. This means that loading up a deep-linked page won’t cause any issues and wherever you go in the site, the URL will update.

Templating – a biggie. Not only does Angular have templating but it also supports handlebars-like templating for displaying data. This is contrary to, let’s say, KnockoutJS that used data-bind as an attribute to show data.

Variable tracking / data-binding – this is the crux of MV* frameworks and AngularJS does a great job with it. It’s also automatic where you can simply add a variable to the $scope and have it tracked unlike KOjs where you have to manually declare each variable as “observable” or “computed”.

No listeners – the event listener paradigm doesn’t really exist in AngularJS. You can declare functions and then bind them to an event via ng-click for instance, but the experience is completely different from jQuery where your listener is removed from your template and declared independent of your view. At first, this seems counterintuitive but it works really well.

Separation of concerns – this is the “enterprise-y” part of AngularJS. There are services, factories, encapsulation, and dependency injection all of which allow many different developers to work on a project together, reuse code, and keep it DRY.

All of that makes a full front-end framework that requires no additional libraries on the side.

side note: Angular router was taken out of core a year ago or so, and is not available separately. This opened an avenue for libraries like ui router which serve as more featureful alternatives.

Let us App

I’d like to go over the concepts above more in-depth while I go over how to use them. It makes more sense in practice than on paper and you’ll quickly see that. I strongly believe in teaching what you’ll use and show the academic side of things on the go rather than give you a ton of boilerplate that won’t make sense.

I think of learning Angular like peeling an onion backward. You keep adding more layers to create something bigger and better but you don’t need to have all the layers ready to start!

I created a list of various “steps” to teach. You can check out the code in its github repo, and live preview online on my dokku server. Note, you’ll have to manually change the URL (

Data binding and affecting data output

Before we get into the nitty gritty of setting up a controller (which is not a true controller in my opinion), we should explore the beauty of angular from the beginning.

One of the most fantastic things about Angular is that when you create a “model”, whatever changes you make will be updated immediately. Let’s look at Step 1

Link

Go ahead and enter whatever you want in that input field. See that? Instance response. Here’s what the code looks like:

<html>
    <head>
        <title>Step 1</title>
    <link href="tseczka.css" rel="stylesheet" type="text/css">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    </head>
    <body ng-app>
        <div class="row">
            <div class="col-6">
                <input type="text" ng-model="myText">
            </div>
            <div class="col-6 last">
                {{ myText }}
            </div>
        </div>
    </body>
</html>

Right away, you should notice two things:

  1. there’s no javascript written (only Angular imported)
  2. ng-*

Angular’s templating is two-fold. On the one hand, you can display data using the handlebars notation like so: {{ myText }}. On the other hand, you can bind all kinds of information via the ng-* syntax. For instance, ng-model="myText" creates a model called “myText” bound to the $scope. The $scope is like a global variable, except scoped, depending on where you’re at. In our example, the $scope is part of ng-app, so anywhere within our file, we can call up the model and show it, or manipulate it.

Ng-app is a way to tell angular “this is where our application starts” and it’s usually on the body tag or html tag.

Let’s move on, let’s do something with our data. There’s no sense in having an input box and having that information show on the other side of the page. Perhaps…perhaps, we can build a markdown editor!

Let’s look at Step 2

Link

What we’re doing here is creating a simple markdown editor. Enter text on the left, and output on the right in markdown. To do this, we’re going to change the data output to match our expectations, meaning that somewhere along the way, before the model gets shown on the page via {{ }}.

There are several ways to do it, so let’s checkout the code:

<html ng-app="myapp">
    <head>
        <title>Step 2</title>
    <link href="tseczka.css" rel="stylesheet" type="text/css">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
    <script>
        //what if we want to convert this interaction into a markdown previewer?
        var app = angular.module("myapp", ['customFilters.markdown']);

        angular.module('customFilters.markdown', [])
            .filter('markdown', function($sce) {
                var converter = new Showdown.converter();
                return function(input) {
                    var html = $sce.trustAsHtml(converter.makeHtml(input || ''));
                    return html;
                }
            });

    </script>
    </head>
    <body>
        <section>
            <div class="row">
                <div class="col-6">
                    <textarea ng-model="myText"></textarea>
                </div>
                <div class="col-6 last" ng-bind-html="myText|markdown">
                </div>
            </div>
        </section>
    </body>
</html>

A few changes I made from the last example. First of all, I included showdown which is a markdown converter library. Second, I added some angular-specific code and lastly, I did away with {{ }}. Here’s what all of them mean.

The first line:

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

We’re creating our application here. Angular no longer owns the entire page. We’re “scoping” things out a bit here. This allows us to run several separate angular applications on the same page. We won’t be doing that, but just like in casual sex, it’s good to wrap things up. You’ll notice that I moved the ng-app tag to the top and referenced our new application as ng-app="myapp", this tells angular that this particular page will be run by “myapp”.

Angular does dependency injection, like I said earlier, the way it works here is why including it in that array up there. It’s customary, for large applications, to have a declaration list with all of the controllers, filters, and other parts of the application declared here. This makes those code segments (called “modules”) available to the application itself.

We passed in customFilters.markdown which is a custom module I made. I named it so to create a makeshift namespace pattern. I’d like to store all of our custom filters under the customFilters name.

       angular.module('customFilters.markdown', [])
            .filter('markdown', function($sce) {
                var converter = new Showdown.converter();
                return function(input) {
                    var html = $sce.trustAsHtml(converter.makeHtml(input || ''));
                    return html;
                }
            });

First, there are different ways of declaring a “module” (a code segment that we can namespace and create dependencies list for). The way above is the best way in that it makes that module available for any Angular application that wants to inject it. The other way is to ignore namespacing (and thus make it un-injectable) and just append it to the app itself like so app.filter('markdown'). This is a bad idea and I ended up doing this for most of the steps.

Anyways, so we created a new “filter”. A filter is a function that takes an input, modifies it, and returns it as output. This is what we want: take in markdown, convert it to HTML, and output. I’ll show you how to use those next. But before we get there, notice something in the filter. The filter itself returns a function that does all the work. Why? Because the filter actually CREATES the function that takes the input and does the work. In this case, we take advantage of that by creating only a single instance of the Showdown converter, and use it for all of our filter use.

The one thing you’ll see here is that we’re passing in a variable called “$sce”. This is a security feature of angular. Angular does not allow you to show straight HTML on a page from a variable. This neat variable lets you mark HTML as “safe” for angular to use and show on a page. Otherwise, angular would just show the HTML as plain text.

<div class="col-6 last" ng-bind-html="myText|markdown"> <- lastly, we’re putting all this together and instead of using {{ }}, we’re using “ng-bind-html” which allows us to show html! 🙂

In Step-3, we’re breaking things out a bit. Remember our filters? Well, we can “chain” them together. Meaning that we can do this:

myText | markdown | pretty which would (in theory if we had a “pretty” filter) do this: pretty(markdown(myText)). The input of myText run through markdown and then its output would go through pretty. Here’s what we used that for:

Link

Here’s the relevant code:

       var app = angular.module("myapp", ['customFilters.markdown', 'customFilters.trust']);

        angular.module('customFilters.markdown', [])
            .filter('markdown', function() {
                var converter = new Showdown.converter();
                return function(input) {
                    var html = converter.makeHtml(input || '');
                    return html;
                }
            });

        angular.module('customFilters.trust', [])
            .filter('trust', function($sce) {
                return function(input) {
                    return $sce.trustAsHtml(input || '');
                }
            });

Quickly, we created two filters. One that converts markdown into html, and the second filter that “trusts” that html. Which allows us to use markdown separately from trust like so:

<div class="col-6">
   <textarea ng-model="myText"></textarea>
 </div>
 <div class="col-6 last" ng-bind-html="myText|markdown|trust">
  </div>
  <div class="col-6">
  <h2>Downloadable HTML</h2>
   <textarea>{{myText|markdown}}</textarea>
  </div>

The myText|markdown|trust will show our output and look all nice while myText|markdown below will populate our <textarea> with copy/pastable HTML.

Data aggregation and angular templates

Already, you can create some neat stuff with the knowledge above, especially if you have javascript background. And that’s wonderful, but we’re just getting started going down this oddly shaped rabbit hole.

First, let me just say that one of the things that got me excited about Angular when I worked with KnockoutJS was the fact that an api feed could be consumed immediately without any post-processing. Any missing data would just yield an empty string. So for example, if we had a feed like this:

{ name: 'Antonin', userid: 3, comment: 'hello', meta: 'super-comment' }

consume it and return it like this in a template:

{{ name }}, {{ userid }}, {{ comment }}, {{ meta }}

If meta didn’t exist, it’d just end up empty. And notice, we didn’t have to do any pre-processing or create observables. In our controller (yep, we’re there already), we’ll just attach our feed to $scope and our application will monitor for value changes.

Let’s look at Step 4

Link

<html ng-app="myapp">
    <head>
        <title>Step 4</title>
    <link href="tseczka.css" rel="stylesheet" type="text/css">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
    <script>
        var app = angular.module("myapp", []);

        app.controller('CommentsController', function($scope) {
            $scope.comments = ['comment', 'comment2'];
        });

    </script>
    </head>
    <body>
        <section ng-view class="row">
            <div class="col-6">
                <div ng-controller="CommentsController">
                    <div class="feed-item">
                        <p>Omfg! I can't believe this one thing just happened, right?</p>
                        <ul class="list-meta">
                            <li><a href="#">comment</a></li>
                            <li><a href="#">like</a></li>
                    </div>
                    <div class="feed-comments">
                        <ul class="block-list comment-block">
                            <li ng-repeat="comment in comments">
                                {{ comment }}
                            </li>
                    </div>
                </div>
            </div>
        </section>
    <script src="js/filters.js"></script>
    </body>
</html>

What happened here? I moved the filters out to a separate file (which is a good practice) and changed a few things out. First, let’s go over the bit above that says “controller”.

        app.controller('CommentsController', function($scope) {
            $scope.comments = ['comment', 'comment2'];
        });

As I’ve said, Angular’s controllers aren’t true controllers. They’re more akin to mini-applications. In this case, our controller holds our comments. It uses $scope to make sure that this data is available in the view.

When we bind this controller to our application, we use ng-controller. The semantics here should be self-explanatory.

Further down, we get to see the scope information being used in the view like so:

<li ng-repeat="comment in comments">
    {{ comment }}
</li>

ng-repeat allows us to iterate through our comments just like a for loop. Yay! Templating! One of Angular’s little templating helpers. There are tons of others like ng-class.

Let’s move onto step 5 where we get to use REAL data.

Link

<html ng-app="myapp">
    <head>
        <title>Step 5</title>
    <link href="tseczka.css" rel="stylesheet" type="text/css">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
    <script>
        var app = angular.module("myapp", []);
    </script>
    </head>
    <body>
        <section ng-view class="row">
            <div class="col-3"> &nbsp;</div>
            <div class="col-6">
                <div ng-controller="FeedController">
                    <ul class="block-list feed-list">
                        <li ng-repeat="item in feed">
                            <div class="feed-item">
                                <div ng-bind-html="item.content|markdown|trust"></div>
                                {{ item.user }}
                                <ul class="list-meta">
                                    <li><a href="#">comment</a></li>
                                    <li><a href="#">like</a></li>
                            </div>
                            <div class="feed-comments">
                                <ul class="block-list comment-block">
                                    <li ng-repeat="comment in item.comments">
                                        <div ng-bind-html="comment|markdown|trust"></div>
                                    </li>
                                </ul>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </section>
    <script src="js/filters.js"></script>
    <script src="js/factories.js"></script>
    <script src="js/controllers.js"></script>
    </body>
</html>

A little emptier than the previous files, we moved over most of our logic to other files. Big applications would probably require further separation into folders called controllers, factories, and such, with each subsequent module being in its own file.

Before we get to the view, let’s check out our new FeedController.

app.controller('FeedController', function($scope, feedFactory) {
    $scope.feed = [];

    var init = function() {
        feedFactory.getFeed.success(function(data) {
            $scope.feed = data;
         });

    };

    init();
});

Sweet, so we declared our FeedController, and passed in a feedFactory along with the scope? Yep, that’s right, we’ll look at that right after the controller. The feedFactory is a piece of code that allows us to run a function that retrieves an API feed. As far as the sections of the code:

$scope.feed initializes an array that we can use in the view. Because of data-binding, whenever we update this variable, our view will update, just what we need.

Next, we created an “init” function. This function is not available to the view but within the controller, we can use it as a constructor. We could also name it update() and create an interval function that will update the feed periodically.

Within our init() function, we’re using our factory to retrieve a “promise”. You’re welcome to read about them or just take my word for it that when you call success(function() { callback stuff goes here }) on it, you’ll get the results.

Let’s look at the factory to get a better understanding of what’s going on:

app.factory('feedFactory', function($http) {
    return {
        getFeed: $http.get('/api/feed')
    };
});

A factory is a way to create a singleton in Angular. Here, we can specify a factory to return various functionality. In our case getFeed is simply a function that uses Angular’s built in $http to “get” /api/feed. The /api/feed links to a custom feed served by my server (that I created for these purposes). You can check out the raw feed if you wish.

Back up the rabbit hole. Our factory gets the data, our controller assigns it to a feed variable. Now onto the view:

    <div ng-controller="FeedController">
        <ul class="block-list feed-list">
            <li ng-repeat="item in feed">
                <div class="feed-item">
                    <div ng-bind-html="item.content|markdown|trust"></div>
                    {{ item.user }}
                    <ul class="list-meta">
                        <li><a href="#">comment</a></li>
                        <li><a href="#">like</a></li>
                    </ul>
                    </div>
                    <div class="feed-comments">
                        <ul class="block-list comment-block">
                            <li ng-repeat="comment in item.comments">
                                <div ng-bind-html="comment|markdown|trust"></div>
                            </li>
                        </ul>
                    </div>
                </div>
             </li>
        </ul>
    </div>

Same-old, same-old. We’re using our filters. Note the nested ng-repeat (yes, you CAN do that). Cool, let’s move on!

Large-scale application

We’ve covered just about everything in basic Angular usage. From filters to controllers, from templates, to factories. You’re pretty much ready to create an app. But not a very large one. You’re still lacking multiple pages, templates, and routing!

Time to check that out. Let’s move onto step 6

Link

<html ng-app="myapp">
    <head>
        <title>Step 6</title>
    <link href="tseczka.css" rel="stylesheet" type="text/css">
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular-route.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
    <script>
        var app = angular.module("myapp", ['ngRoute']).config(function($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'templates/feed.html',
            controller:'FeedController'
        }).when('/users', {
            templateUrl: 'templates/users.html',
            controller: 'UsersController'
        });
    });
    </script>
    </head>
    <body>
        <div class="nav-container nav-main nav-right">
            <div class="nav">
                <a href="#" class="nav-title emboss">My Angular App</a>
                <ul>
                        <li>
                            <a href="#">Feed</a>
                        </li>
                        <li>
                            <a href="#users">Users</a>
                        </li>
                </ul>
            </div>
        </div>
        <section ng-view class="row">
        </section>
    <script src="js/filters.js"></script>
    <script src="js/factories.js"></script>
    <script src="js/controllers.js"></script>
    </body>
</html>

Not too different, let’s tackle the differences first.

We included a new library called angular-route which is the router for Angular’s applications. It used to be included in the core but was taken out in favor of more modularity. We’re using Angular’s default choice for this tutorial.

        var app = angular.module("myapp", ['ngRoute']).config(function($routeProvider) {
        $routeProvider.when('/', {
            templateUrl: 'templates/feed.html',
            controller:'FeedController'
        }).when('/users', {
            templateUrl: 'templates/users.html',
            controller: 'UsersController'
        });
    });

As you can see we included ngRoute as the dependency and pass in the $routeProvider for the config, there the router works similarly to a back-end router except you’ll specify the controller and view here, not in the controller itself.

Out of the box, angular route supports URL mapping that allows bookmarkable URLs. Meaning that when you visit various sections of the site, the URL will update, without a refresh. This is accomplished in one of two ways:

  • a hashbang legacy routing which looks like index.html/#/page-name and works on all browsers (pretty much).
  • an HTML5 history/state api routing which looks like /page-name and resembles a regular website.

You can easily declare the latter via the config just like anything else.

Next, you’ll notice I added a menu that works off our hashbang routing schema and I can refer to those URLs directly.

After that, our entire application view got condensed into

<section ng-view class="row">
</section>

Because of the way the router works, we can offload all of our templates into a separate folder and angular will include it when necessary which is pretty awesome! So our main “bootstrapping” file is pretty simple: include all files you need, setup the basics, and let the rest of the application handle the behavior and view.

Sweet. We can look into the rest of the files, but not much has changed. We created a new UsersController:

app.controller('UsersController', function($scope, feedFactory) {
    $scope.users = [];

    var init = function() {
        feedFactory.getUsers.success(function(data) {
            $scope.users = data;
         });
    };

    init();
});

which looks almost identical to our FeedController except that it references a new method from that feedFactory. The updated feedFactory is pretty straightforward as well:

app.factory('feedFactory', function($http) {
    return {
        getFeed: $http.get('/api/feed'),
        getUsers: $http.get('/api/users')
    };
});

And finally, we create all of our separate templates. Templates are kind of like small portions of an html file that are put directly into where our ng-view starts. This is great because there’s no need to write out separate head and body tags, only what’s necessary.

The feed template has been updated in this step as well:

<div class="col-3"> &nbsp;</div>
<div class="col-6">
    <h1>Feed</h1>
    <div ng-controller="FeedController">
        <div class="form-horizontal">
            <div class="form-group row">
                <label>Search: </label>
                <input type="text" ng-model="filterField">
            </div>
        </div>
        <hr />
        <ul class="block-list feed-list">
            <li ng-repeat="item in feed | filter: filterField">
                <div class="feed-item">
                    <div ng-bind-html="item.content|markdown|trust"></div>
                    <ul class="list-meta">
                        <li><a href="#">comment</a></li>
                        <li><a href="#">like</a></li>
                </div>
                <div class="feed-comments">
                    <ul class="block-list comment-block">
                        <li ng-repeat="comment in item.comments">
                            <div ng-bind-html="comment|markdown|trust"></div>
                        </li>
                        <li ng-include=" 'templates/commentForm.html' ">
                        </li>
                    </ul>
                </div>
            </li>
        </ul>
    </div>
</div>

You’ll notice two things right away, a new input field, and an ng-include on the bottom. The input field is bound to a model just like in step 1 and that information is passed onto Angular’s built in “filter” function. The “filter” function is a simple search function. If you check out the example running live, you’ll be able to type in any word in any of the posts and filter them out this way. This is very apparent in the users page (just type in a user name!).

ng-include is what I call a “lazy directive”. I’ll go over directives as last but basically, ng-include includes the html referenced. In our case, we include a form that allows us to add comments!

I’m excited about this part because here, finally, the user is able to affect the data directly, not just the presentation. So let’s check that out.

Our FeedController has a new function called addComment:

    $scope.addComment = function(comment, i) {
      $scope.feed[i].comments.push(comment);
      $scope.newComment = '';
    };

Notice that addComment is bound to the $scope unlike our init function. Why is that? It’s so that we can fire it off on a user event. Here’s our commentForm.html:

<form class="form-vertical" ng-submit="addComment(newComment, $index)">
     <div class="form-group">
        <textarea class="fill" ng-model="newComment"></textarea>
     </div>
    <div class="form-group">
        <input type="submit" class="button main block">
    </div>
</form>

The ng-submit fires off the function inside it (the same addComment as in our controller), uses the ng-model from the textarea below for the comment, and a special $index variable gives us the counter of which feed item we’re in currently in the ng-repeat. If you look at the addComment function, you’ll see how we’re just appending the new comment. Angular updates the view once we click “submit”! 🙂

I’d like to go over what the users.html looks like but it’s pretty much the same as feed.html.

And that’s it. We’ve just tackled:

  • how to organize your app (controllers, filters, templates, etc.)
  • routing!
  • built-in filtering
  • and templates.

You’re ready to make your first app and start using the angular docs and have them make at least some sense to you. From here, it’s much easier to just keep going. You’ll learn more ways to manipulate the view/template via ng- attributes and more interesting ways of using the controllers. As you keep going, you’ll find problems and highlights, unexpected treasures, and hopefully, you’ll enjoy the journey.

I’m not done yet – Directives

Now, some critics may look through my presentation and say, “Well, the guy didn’t even mention directives! How can I take him seriously?”. Directives are considered the best part of Angular. Not to me. I think they’re great sugar but nothing necessary. But no talk would be complete without at least mentioning them.

I’ll do one step better and show you how we can improve our “final” piece. I won’t bother iframing it because the final product will look the same but the code won’t.

So what’s a directive? Simple said it’s a module, almost an app that has it’s own:

  • mini controller
  • mini template

and is completely modular, able to be used in any view, even if it has a controller. The power here is immense in that you can have small reusable pieces of logic and templating that can be referenced anywhere and made to work with any controller.

In our case, we’ll modularize and directivize (my own word) our form submission.

A directive, by the way, can be referenced in all kinds of ways and works similarly to “ng-include”. You can either have a custom directive element like so:

<my-element></my-element>

Or follow angularjs convention by referencing it as an attribute:

<div my-element></div>

Or use it as a class:

<div class="my-element"></div>

Cool thing is, you can specify which way it has to be referenced to prevent various conflicts. Let’s check out the directive code:

app.directive('commentForm', function() {
  return {
        restrict: 'A',
        template: '<form class="form-vertical" ng-submit="addComment()">' +
                   '<div class="form-group">' +
                      '<textarea class="fill" ng-model="comment"></textarea>' +
                   '</div>' +
                  '<div class="form-group">' +
                      '<input type="submit" class="button main block">' +
                  '</div>' +
                '</form>',
        scope: {
          onAddComment: '&',
          comment: '='
        },
        replace: true,
        link: function (scope, elem, attrs) {
          scope.comment = '';

          scope.addComment = function(){
            scope.onAddComment(scope.comment);
            scope.comment = '';
          }

        }
      }

});

Phew, this looks really messy, I know. But once you get the hang of it, it’ll get easier. Let’s go through this piece by piece. I’ll skip the usual initialization app.directive because that makes sense.

First, we have restrict: 'A',, this line allows us to restrict how our directive works. Here, we specified that it has be declared as an Attribute. You can also do E for Element, or a mix of AE where either element or attribute can be specified.

Then we have our template

template: '<form class="form-vertical" ng-submit="addComment()">' +
                   '<div class="form-group">' +
                      '<textarea class="fill" ng-model="comment"></textarea>' +
                   '</div>' +
                  '<div class="form-group">' +
                      '<input type="submit" class="button main block">' +
                  '</div>' +
                '</form>',

Note that whatever functions and model we specify in THIS template won’t affect our outside template even if naming conflicts. This is what whole “scope” thing I talked about through the article. There’s nothing new in here except that we had to specify our template as a long string. You can also use templateUrl and specify the url of the template instead.

       scope: {
          onAddComment: '&',
          comment: '='
        },

This part was a little difficult for me to understand but once you get it, it’ll make sense. This is a way to allow our directive to get data from the outer scope. In our case, from our controller. We want to be able to send information from our directive (such as comment body) to the controller so that the controller can save that data (add comment). We also want to be able to broadcast the “save” command. This is what this allows.

The = sign means that the data is two-way-bound to each other. If you checkout the Feed template:

<div comment-form on-add-comment="addComment(newComment, $index)" comment="newComment"></div>

Another way to bind parts of the application is with the & symbol which basically means that we’re passing a function and allows us to call an outside function inside a directive. In this case, we’re referencing our addComment function in the controller and we’re calling it inside the directive as onAddComment. Lastly, the @ symbol passes the information through as a string.

This may sound a bit confusing and that’s because directives are their own rabbit hole with various settings and possibilities of use. I recommend reading further into it once you grasp the basics of everything else.

So let me explain what else we’re doing:

replace: true,

This means that the original element we used (<div comment-form></div>) will disappear and be replaced by the template inside the directive. If you leave out the replace part, the template will be wrapped with the <div></div> we declared.

Last but not least, our link function:

link: function (scope, elem, attrs) {
          scope.comment = '';

          scope.addComment = function(){
            scope.onAddComment(scope.comment);
            scope.comment = '';
          }

        }

Things should start looking familiar. We’re passing in a scope. There are some other dependencies that made their way here but let’s not concern ourselves with those at this moment.

Since you’ve already seen the template (above), this function should look self-explanatory. We have a comment on the scope which is bound to the textarea for that new comment. And we have a function that fires off when our form is submitted. The function, you’ll notice, is named exactly the same as in our scope declaration earlier. In the directive declaration in our template (the <div></div>), we had an attribute called on-add-comment. This is the same thing.

We passed in scope.comment which is then passed to our controller’s own function addComment. Since we already prefilled the $index part there, we don’t have to pass it in again. We also don’t have a way to pass it in unless we augmented our scope declaration and made a new variable.

Where to now?

Now that we’re done with the beginner’s guide, it’s time to move on, move forward. I’d say that your best shot learning AngularJS is to start making apps. Make a twitter feed with twitter’s API, or a simple tool for yourself, whether it’s a to-do list, or a simple tool for finding movies by actors.

Or, build a blog. It’s all up to you 🙂

Additional Resources

Want to take the next step? Here are some good resources on getting there:

Free:

Paid: