Basics of Angular: Start Here

By Dave Ceddia

A lot of people are (rightfully) overwhelmed and confused when they start using AngularJS. There are a ton of new concepts to grasp - $scope, controllers, services, and the often-confusing directives. And then what’s the difference between a service and a factory? And how do you use promises?

This post aims to clear up some of the confusion. And don’t worry – it’s normal, even expected, to be confused when you start working with Angular. But you’ll get over it quickly as you start to build apps, and hopefully this overview will help you along the way.

A story, for starters

Code can do more harm than good in the beginning, so let’s start off with a story.

Our tale takes place on a cold, blustery night when Lucy, collapsing down on her couch after a long day at work, realizes an urgent problem: she’s hungry. “It’s 8pm! I forgot about dinner again,” Lucy scoffs to herself.

Lucy works as a developer at Food Delivery Corp. It’s a very hectic startup where she’s the sole developer, and she’s responsible for writing the web app that lets customers get food delivered from nearby restaurants. So it’s especially ironic that she would forget about dinner, like ever.

In any case, she decides to order some food online (using the app she wrote, obv).

She brings up the Place Order page, and even though it’s just a simple list of restaurants, her mind is running through the code as she clicks around.

“List the restaurants using ng-repeat. Click ‘Order Here’, triggers an ng-click handler on the controller. Not on $scope, that’s for newbs. I’m using controllerAs.”

“Off goes a call to the data service, and a request to the server using $http. Request comes back, promise resolves, calls my then() handler, which shows the order form.”

“Here we go. Small hawaiian, bacon instead of ham. Throw in a Coke, too. Should be here in about 15 minutes.”

[ed] They must have magic elves or something. 15 minutes for delivery?! I’ve never gotten anything faster than 45.

Lots of pieces

Let’s walk through what Lucy was muttering to herself during that pizza order. There are a bunch of components interacting there. Did you catch all of them?

  • 1 View: some HTML that shows a list of a restaurants, and displays an order form
  • 1 Controller: to hold on to the list of resturants, and handle the user’s interaction
  • 2 Directives: ng-repeat and ng-click, both built-in to Angular
  • 2 Services: $http, which comes built-in with Angular, and also a custom “data” service
  • 1 Promise: returned by $http, and handled by a function that updates the restaurant data
  • 1 Delicious Pizza: Pineapple and bacon, amirite?

Down to business

We’ll dive into each component and see if we can reverse-engineer something that looks like the app Lucy wrote. Her boss probably won’t be happy but we’ll learn a lot about Angular this way.

Views

Let’s start with the easy one: the view. It’s what renders on the web page. It’s what the user sees. It’s mostly plain old HTML, but there can be some Angular magic sprinkled in there too (in the form of directives, which we’ll get to later).

The Place Order page that Lucy was using is a view. For the sake of argument, let’s say it looks something like this:

<h1>Food Delivery Corp</h1>

<h2>Place Order</h2>

<ul>
  <li ng-repeat="restaurant in vm.restaurants">
     <a ng-click="vm.showRestaurant(restaurant)">Order Here</a>
  </li>
</ul>

Aside: The h1 tag should be used for the most important thing on the page, and describe what the page is for. “Food Delivery Corp” is not that. Lucy argued with her boss for hours over that one.

Controllers

It’s the controller’s job to give data to the view, and to handle user interaction. In the case of Lucy’s ordering page, the controller needs to provide the list of restaurants and also a way to order from one.

function RestaurantListCtrl(RestaurantData) {
    var ctrl = this;

    ctrl.restaurants = [{
        name: "Primo Pizza",
        id: 1,
        rating: 4.5
    },
    {
        name: "Fajitas",
        id: 2,
        rating: 3
    },
    {
        name: "Taste of China",
        id: 3,
        rating: 4
    }];

    ctrl.showRestaurant = function(restaurant) {
        RestaurantData.getOrderingInfo(restaurant).then(function(data) {
            restaurant.expanded = true;
            restaurant.extraData = data;
        });
    };
}
  

angular.module('fdcApp')
    .controller('RestaurantListCtrl', RestaurantListCtrl);

In a real app, you probably wouldn’t hard code a list of 3 restaurants like this, but bear with me.

I want to talk about the line var ctrl = this for a minute.

There are 2 ways controllers can pass data to views:

  1. Using $scope, and setting variables on it like $scope.restaurants = [...]
  2. Using controllerAs, and putting data on the controller’s this object

You can see here that Lucy used option #2.

But wouldn’t it be possible to just use this directly without assigning it to ctrl? Why take that extra step? Well, because variable scope in JavaScript is a little unusual, and if you were to use this inside a nested function, like inside showRestaurant, it’d refer to something totally different, and cause weird bugs.

So be safe, save yourself some hair pulling, and assign this to a variable at the top of your controller.

It’s common to name it something like ctrl or vm (for ViewModel). I didn’t name it vm lest you think that the name vm in the view must match the one in the controller. But we’ll get to that later.

Interlude: controllerAs

The controllerAs construct is relatively new in Angular (introduced in 1.2). Todd Motto has a great writeup about it, but the 30-second version is that it reduces your dependency on $scope, treats the controller more like a proper class, and helps to disambiguate variable names when working with nested scopes.

It’s the current “best practice” to use controllerAs instead of injecting $scope into your controllers. So instead of:

<div ng-controller="MainCtrl">
  Hello {{ location }}!
</div>

You’ll do something like this (note the as main, and main.location):

<div ng-controller="MainCtrl as main">
  Hello {{ main.location }}!
</div>

Directives

Angular would not be much of anything special if it weren’t for directives. They make it possible to extend HTML with custom elements and attributes that bring their own behavior.

In the story above, Lucy used two directives that are built in to Angular: ng-repeat and ng-click. These are pretty easy. Let’s go over how they work.

ng-repeat

It works like a for loop in your HTML, iterating over an array of elements and rendering each one.

<ul>
  <li ng-repeat="restaurant in vm.restaurants">
     <a ng-click="vm.showRestaurant(restaurant)">Order Here</a>
  </li>
</ul>

Every restaurant will get its own <li> tag showing its name and the “Order Here” link.

ng-click

If you’ve ever used onclick, or jQuery’s .click(function() {...}), well, ng-click is very similar to those.

If you’ve never used those things, what you need to know is this: ng-click will call the given function when the user clicks on the element. In this case, it’s vm.showRestaurant(restaurant). Super simple.

What about custom directives?

Writing your own directives are a big enough topic that talking about them here will take this post off into the weeds. I’ll cover how to create your own directives in another post! (If you want to be sure you don’t miss it, sign up for email updates at the end!)

Services

It’s widely regarded as a good idea to keep logic (and especially HTTP requests) out of your controllers. The best place for that kind of stuff is in a service.

Angular comes with bunch of services built-in, and they all start with a $. $http is a prime example, and one that Lucy used in her app. Keeping up with best practices, she didn’t call $http directly from the controller; rather, she created a service to take care of that. It probably looks something like this:

    function RestaurantData($http) {
        return {
            getOrderingInfo: getOrderingInfo
        };

        function getOrderingInfo(restaurant) {
            return $http.get('/restaurants/' + restaurant.id + '/orderinfo').then(function(res) {
                return res.data;
            });
        }
    }

    angular.module('fdcApp')
        .factory('RestaurantData', RestaurantData)

You can see that the $http service is a parameter to the RestaurantData function. It’s not just any old parameter though, it’s being injected by Angular’s dependency injection system.

In getOrderingInfo, we’re making a call to $http.get which returns a promise. The promise will be resolved when the HTTP request comes back successfully (or rejected if the request fails).

Dependency injection

DI is at the core of how Angular works. It’s a fancy term, but the concept is simple: rather than having each object know about how to create the things it needs, those things are automatically created and handed to the object.

Angular will look at the argument list to your controller/service/factory/directive, go and find objects that match those names, create them, and pass them in to your thing.

In the example above, $http is a built-in Angular service, but you can just as easily define and later inject your own custom objects. This is what the line .factory('RestaurantData', RestaurantData) is doing: it says to create an object named “RestaurantData”, implemented by the function RestaurantData, so that when some other object calls for a RestaurantData argument, it will get this function.

It’s nice that the names match, but they don’t have to – just make sure when you go to inject an object, that you use the string name.

Now that the name “RestaurantData” is registered with Angular, it can be used in other objects you create. If you look back to the Controllers section, above, you’ll notice that RestaurantListCtrl calls for RestaurantData as an injected argument.

Why factory and not service? What’s the difference?

  • A factory returns an object that contains a set of behavior, variables, etc. RestaurantData, above, is done as a factory.

  • A service is different in that Angular will call new on it before injecting it. So rather than returning an object from a service, the behavior should all go on the this object. Here’s RestaurantData rewritten as a service:

    function RestaurantData($http) {

        // 1. Don't need to return anything
        // 2. The functions/variables/etc go on 'this'
        this.getOrderingInfo = getOrderingInfo;

        function getOrderingInfo(restaurant) {
            return $http.get('/restaurants/' + restaurant.id + '/orderinfo').then(function(res) {
                return res.data;
            });
        }
    }

    // 3. Use '.service' instead of '.factory'
    angular.module('fdcApp')
        .service('RestaurantData', RestaurantData)

Factory and service are similar, but they are not interchangable without some modifications.

As John Papa recommends in his Angluar style guide:

Since [services] are so similar to factories, use a factory instead for consistency.

Read more about factory vs service here.

Promises

The last common stumbling point we’ll talk about is promsies.

It’s ok, and very normal, if you’re confused by how they work. They confused the heck out of me when I started with Angular. Even now, when more advanced uses come up, it might take me a few tries to get it right. So don’t worry.

Promises are a way to deal with calling functions that take a while to return. The reason you don’t want to call a function and just wait (even if that might be easier to think about) is because the browser is only running one thread for JavaScript. If you make it sit there and wait, it can’t do anything else, like respond to the user furiously clicking buttons because the damn thing isn’t responding.

So, when you make a call to something that returns a promise, the actual result of that call is deferred until later, even though the function returns immediately. Here’s an example:

    console.log('about to send the request!');
    $http.get('http://purple.com').then(function(res) {
        console.log('request completed!');
    });
    console.log('request has been sent!');

When this runs, it will print about to send the request! followed by request has been sent!. When $http.get() is called, it returns right away, with a promise. But the request isn’t finished yet.

Only once the request completes successfully will it call the function passed to then(), which will print out request completed!. Got that?

Another nice thing that promises let you do is chain them together, like so:

    $http.get('http://purple.com')
        .then(function(res) {
            console.log('request completed!');
            return res.data;
        })
        .then(function(data) {
            console.log('the page is ' + data.length + ' bytes long');
        })
        .then(function(this_will_be_undefiend) {
            console.log('the last function returned nothing, so this one receives nothing');
        });

Maybe this is self-explanatory, but I’ll explain it anyway:

  1. $http.get is called, and the request goes off to the server. The function returns a promise immediately.
  2. That returned promise has a method called then, which accepts a function, so, we call it and pass a function that prints request completed! some time in the near future. It also returns something. When a then function returns something, that gets passed along to the next function in the chain.
  3. The next function in the chain prints how long the reply was. But it doesn’t return anything, so the next function won’t receive anything as an argument.
  4. The last function is called with no argument (so this_will_be_undefined is, well, undefined).

Wrap Up

Ok! That’s the high level overview of all the big pieces of Angular. The best thing you can do now is to go out and practice. Make a number of different apps, little simple things, in order to solidify your knowledge. The best way to get better at anything is to do it, not read about it. So get to work!

Oh, one last thing! I’d be remiss not to mention that I’ll be posting more articles like this one, with more helpful Angular tips and solutions. If you want more like this, sign up below. Thanks for reading.