DJ Quilter

Front-End Developer

The Anatomy of My First Angular App

I should start by saying I’ve already lied to you; this isn’t my first Angular app. A few months ago, I went through a couple of tutorials to get to grips with Angular. But this is the first one that I’ve written for myself though. It’s probably worth saying that this is just one way of writing an Angular app too. There seem to be plenty of different ways to write the same functionality, but this one worked for me.

A Little Overview

The app that I’m building had a few goals. I wanted:

  • To have multiple routes which the user could choose.
  • A model, or set of data, which they would populate at the start.
  • And for the model to be updated the user progressed through the app.

Because of these goals, I knew that I would need:

  • Controllers to take the user’s decisions and transform the model appropriately.
  • An Angular Service which had access to or stored the Model (which shouldn’t much more than a Javascript or JSON Object).
  • A Routing system that presents the user with the correct Views.

The above are all provided by Angular, so all that’s left is to start coding!

Let’s Bootstrap This Mother-Flipper

First off, here’s the folder structure that I created:

  • index.html
  • css
    • main.css
  • js
    • vendor
      • angular-route.js
      • angular.min.js
      • jquery.js
    • app.js
  • views
    • intro.html

Everything here should look pretty straightforward, so I’m not going to waste too much time explaining, but briefly:

  • App.js is where the Angular code that we’ve written lives.
  • The js/vendor folder is where all of the code for our frameworks live.
  • Index.html is basically the template which our views are dropped into.
  • And the views folder contains the HTML for each individual route.

The Template

The index HTML file is where everything starts off:

<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
    <title>Choose Your Path</title>
    <link rel="stylesheet" href="css/main.css">
    <script src="js/vendor/jquery-1.11.3.min.js"></script>
    <script src="js/vendor/angular.min.js"></script>
    <script src="js/vendor/angular-route.js"></script>
    <script src="js/app.js"></script>
</head>
<body ng-view>
</body>
</html>

This is massively simplified, but there are a few things to note. Such as the ng-app attribute on the HTML element. This tells the Angular framework that this is the root element of the application and that anything inside it is part of the application.

Then there’s the Javascript files. I’ve included jQuery just for ease of development, but it is not required for using Angular. The Angular framework is obviously needed, and the Angular route module if you’re planning on using it (which we are). And finally the app.js file which will contain all of our code.

The last point of interest is the ng-view attribute on the body. This is telling Angular that all views should be rendered within this element. More on this later.

Next stop is app.js.

Let’s Write Some Code!

First thing to do is to instantiate our Angular app and declare the dependencies:

angular.module('app', ['ngRoute'])

Notice the ‘app’ is the same at the value on the ng-app attribute in our HTML template. This is not a coincidence. We’re tying our application code to our markup. The array which following it contains of the dependencies, which in this case is just Angular’s routing module.

Usually, I think you’d start writing your controllers next, but before we get into that you need to look at a service.

Services differ from controllers in that they are shared across an application. Whereas a controller is tied to a view, a service can be called upon by many controllers to do something. In this case we’re using a service to create and store our model.

.factory('userData', function() {
    var userData = {
        type: 'user’
    };
    return userData;
})

Angular’s factory method creates the service (named ‘userData’) within which we have a very simple Object that gets return to whatever calls on the service. Easy, right?

Controllers

So let’s have a look at a controller:

.controller('intro' function($scope, userData) {
    $scope.updateUser = function(data) {
        userData[data] = $scope[data];
    }
})

We have another method, with a name, ‘intro’, and after that, a function. For parameters, we have something called a $scope and the userData service.

The use of the userData should be fairly obvious; we’ve included it so that we can get or set data within the basic model that lives in our service. The $scope is something a bit more difficult to explain. The Angular docs say:

Scope is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.

I don’t know about you, but that means very little to me. I tend to think of the scope as an Object which ties a view to a controller. In essence you can think of it as a small model that is only in use with a specific view-controller combination.

So what about the code used in our controller above? We have a function that, when run, will copy data from the scope into the userData model. But when is it run? And where does the data come from? If we look to our view, we’ll find out!

The View

In the views folder, we have intro.html, which looks like this:

<section class="intro">
	<p>What's your name?</p>
	<input type="text" ng-model="name" ng-change="updateUser('name')">
</section>

The interesting element here is the input. We have two attributes, ng-model and ng-change. The first of these defines a name for input data in the scope. So if I entered ‘David’ in the input, $scope[‘name’] would return ‘David’. This is via some black magic which is much too complicated to explain here. All we need to know is that it works beautifully.

The second attribute on the input (ng-change) tells Angular to do someone every time the input value changes; which in this case to to run the function which we created in the controller.

This (I hope) is the final step in showing how the controller ties in with the view and the model, but there is one more thing to look at.

Routing

The final part of the app.js file is this ‘config’ block, which makes reference to $routeProvider. This is something which we get from the ngRoute dependency which we mentioned earlier. It allows you to define pseudo-pages (pseudo in the sense that they don’t actually exist as complete files), and then navigate to those pages in an application by updating the URL.

.config(function($routeProvider) {
    $routeProvider
        .when('/', {
            controller: 'intro',
            templateUrl: 'views/intro.html'
    });
});

For each route, you define a ‘.when’ which is looking for a specific path the in the URL. In this case, it’s looking for the root URL, as you can see by the first string after the when ‘/’. If you wanted look for the URL www.myapp.com/page/, that string would be ‘/page’.

The Object that follows is straightforward. There are a number of options you could set, but the basic ones set the controller (by reference to the controller’s name), and the HTML view (by reference to the path from the root of the application).

The content in the HTML view is output into the HTML template, and specifically the element with the ng-view attribute. In this example, as we mentioned earlier, we put it on the body element.

A quick aside: Angular actually makes use of hashbangs for its routing (mainly to support older browsers), so the URL for the root of our application would be www.myapp.com/#/ and any further pages www.myapp.com/#/page/. I think it’s enough to know that for the moment; going into detail on this is a whole other blog post.

Conclusion

So that’s the first page of the app and a structure which can be built upon for future pages. To summarize, we have a template which views can be injected into, depending on the user’s URL. Data can be entered and stored in a model which persists whilst the user is in the application.

I’ve actually simplified a lot of the code here from the application that I originally build, but if you want to see the whole thing, you can take a look here.