Angular is an MVVM-like framework comprised of several major conceptual components that work together to separate concerns.
Some of these major components include:
Routers: Use pattern matching to map urls to templates/controllers.
Services: Handle application business logic and make calls to web API’s. They’re used to pass data among controllers because only a single instance of each service exists for the lifetime of the application. These are lazily instantiated when you try to first access them.
Controllers: Glue services to html templates. Controllers are mostly used to mould data into a format that the UI can work with. They’re also used to handle user actions. These are often instantiated when our routes change.
Directives: Used to create reusable html components that interact with the DOM. You should never change the DOM from a controller or service. If you’re looking to change a DOM attribute, you’re likely looking for a directive.
Data Binding: Angular provides one-way and two-way data binding to bind controller variables to html templates. In your controllers, the
$scope variable may be injected and used to bind to the view. Any property attached to
$scope will be available in the view via interpolation. If your controller contains
$scope.name = ‘Rick’;, you may access this in your view via double curly brace syntax,
Dependency Injection: Angular uses a pattern known as dependency injection to loosely couple its conceptual components.
Before starting the code, we’ll need a way to run the app. I recommend installing http-server using npm.
You can install npm here.
Once npm is installed you can install http-server from the command line with:
npm install http-server -g
Okay let’s look at some code!
Though I think you should work through the code incrementally according to the tutorial, you may clone this repo if you wish.
Since the scope of this tutorial does not include css styling, I recommend you simply copy the following styles.css into your working directory.
Because we’re creating a relatively simple app, all subsequent files will be placed directly in this working directory as well.
Our index.html file contains hardly anything. On the body tag we’ve included an angular app called DemoApp, which will exist shortly.
Our content has been deferred to a ui-view which will be our root state. This state will have an associated template and controller. When the state is entered, the html template will be injected as contents of the div.
We will use an angular library called ui-router, which approaches routing with a state-based model. One major flaw of Angular’s default router is that it’s not capable of nested views. The ui-router library is capable of nested views and is generally considered superior.
Here, we’ve initialized our angular app and included the ui-router module. We’ve also set up two states. The root state will always be active because ‘root’ is made the parent of the note-detail state. This state has an associated template and controller. I always like to include a root state for any functionality that exists across the entire website. For example toolbars and sidebars as well as log-in and log-out functionality. Our other state is the note-detail state, which shows the full title and body of a specific note.
We want the note list always to be visible no matter where we navigate to in our application, so we will include the note list’s html in the html template for the root state.
In our root-partial.html template you can see the note list and a nested state (view) for the note detail.
ng-repeat (line 10) will often come in handy. It lets us iterate over collections stored on the controller’s
ui-sref tag provides us an on-click state transition. When we click a note with id 1, we will enter the note-detail state and the url suffix will become
For now we‘ve hardcoded the data in our RootController, but soon we’ll hook it up to the web API endpoints.
At this point we’re ready to spin up the server and give our app a test run. From the terminal, in the directory with the index.html file, run:
Our app is only partly functional at the moment, but we can see how the controller’s
$scope properties are rendered in the view via interpolation.
This is cool I guess, but the whole point of this is to consume an API, so let’s get on that. We’re going to create an angular service that knows how to interact with the placeholder API and returns note(AKA post) objects.
As you can see, there’s a lot going on here. We use Angular’s $http service to perform a GET request on the note-list endpoint and note-detail endpoint.
The ‘get’ method returns a promise, which is a placeholder that will eventually be replaced with the result of the async operation. Making a call to a web service takes time and it would be bad if the whole application blocked for a long amount of time while waiting for the response. So instead we make the method async and use a promise to handle the eventual result.
The ‘then’ function allows us to handle the success and error cases of the eventual response with two callbacks. The return values of these callbacks is itself wrapped in a promise and returned by the ‘then’ function allowing for promise chaining.
Let’s modify root.controller.js to populate the notes dynamically.
Notice the dependency injection happening in line 1. We’ve already registered our NoteService with our app, so Angular knows it exists and knows how to inject it into our controller.
We can call the getNotes function which returns a promise. And then if the operation was a success we’ll set the notes on the
$scope, but otherwise we’ll just log the error to the console.
If we now try spinning up the server again, we see a list of many notes! However, if we try clicking any of the notes, nothing happens. All that’s left to do is create a template and controller to handle the note-detail state.
Let’s create a note-detail template.
Also go ahead and save this as preloader.gif in your working directory.
As you can see, our note-detail template is pretty straightforward. We have interpolation happening in lines 1 & 2 and we’ve included a preloader gif which we’ll conditionally show using the ng-show directive. We’ll show the preloader for the duration it takes to receive a response from the note-detail endpoint of the placeholder API.
Lastly, we’ll need a controller to handle the note-detail view.
As for our controller, this all looks pretty familiar with the exception of $stateParams, which allows us to grab the noteId from the url so we can pass it to the service. And, as mentioned, the
$scope.resolved.preloader is set to false just before we call
getNote. This allows us to show our preloader temporarily in the UI, and once we get a response containing the note, we set
$scope.resolved.preloader = true;.
If you spin up the server one last time, you should see that our app is fully functional!
AngularJS is pretty nifty, though some would say it has a steep learning curve. I personally have enjoyed using it over the years and I hope this has been a good, not-that-confusing introduction for you!