Getting Started with Angular: Part 2 — Routing
Missed Part 1 of this series? You can find it here.
Looking for Part 3? Go here.
Read this article on my blog for better viewing.
Angular UI-Router
AngularJS is a front end framework for making Single Page Applications. There are a couple reasons to develop Single Page Applications. They are faster than server-rendered websites because all of the views live on the browser and are loaded up when the page first loads, rather than having to call back to the server each time the user redirects to a new page. There is no actual page redirection because everything is loaded via templates into a single html page, therefore the user gets a more seamless experience. Thanks to Angular’s two-way data binding the user should never have to refresh the page either.
In order to make all this happen Angular needs a way to route between views on the front end. Angular’s original router is called ngRoute but it isn’t very popular because there is a better router called the AngularUI Router, which we will use. Specifically the UI Router is better because it allows multiple views and controllers to be loaded into a single state. The UI Router uses the concept of states to define URL routes and their associated views and controllers.
I will also introduce you to the $http Angular service by using a GET request to pull in data from GitHub and display it on the page.
Project Setup
Let’s set up the directory and files for our project. Make a new directory in your terminal, let’s call it Router-Tutorial. Inside your directory make two files: index.html and routes.js. Make three folders, call them home, github, and gallery. Each of those folders will hold an HTML file and a JavaScript file that represent the view and controller for each of the three routes we will be making. The final project structure should look like this:
Router-Tutorial/
…index.html
…routes.js
…home/
……home.html
……homeController.js
…github/
……github.html
……githubController.js
…gallery/
……gallery.html
……galleryController.js
Angular Setup
In the first part of this series of articles we went over how to setup Angular. Our index.html will look like this once set up:
Here we are pulling in the AngularJS CDN and at the bottom of the body we are including the scripts for the Angular UI Router and the four JavaScript files in our project. You can find the UI Router CDN online by searching for it, or just go grab it from here. The UI Router script must come before routes.js because routes.js relies on it. The routes.js file must come next because we will create our Angular module in that file, the other three files will be using the module we create in the routes file.
Time to create our three controllers for home, github, and gallery. I won’t go through explaining this since we covered Angular controllers in Part 1 of this series.
We didn’t pass the dependency array to the module in any of these files because in these controllers we are using a module that we will create in routes.js. You only pass the dependency array when you actually create the module.
Setting Up Our Views
Notice that we didn’t use an ng-controller directive in our html. That’s because the router is going to handle the linking of controllers to views for us. However, we do need to give our router a place to load up the HTML templates it routes to inside of index.html. We do this using the UI Router’s ui-view directive. To do this we put ui-view as an attribute on a div. Any template (view) that is loaded by the router will be inserted into index.html as the content for that div. This means all our content will be loaded into index.html, thus making this website a Single Page Application. In index.html, below the h1 tag, let’s add:
Let’s fill up our home.html and gallery.html files and get started on github.html. The home view will display ‘Home Page’ and then two buttons which will route to the gallery state and the github state. We don’t need to include any of the standard HTML boilerplate code because home.html is just a template being loaded into index.html, and we already put all the HTML boilerplate code in index.html. Our home.html will look like this:
As you can see when the first button is clicked it will call the changeState() function. This function takes a string which is the name of the state that it will route to. But what does the second button do? The ui-sref (ui state reference) attribute is similar to the href (hypertext reference) that you would normally use in an anchor tag, except the ui-sref is something that the UI Router gives us and it routes to the given state by state name instead of routing by URL. So we are using two different ways to route to the desired state. The ui-sref requires no more code to work, so it takes less code than using ng-click because we still have to set up the changeState() function in our controller. In this case using ui-sref makes more sense because clicking the button will always route us to the same state. Routing from the controller would make more sense if you want to only load up a new template from the routes based on some condition, so you would need to check the condition in the controller’s logic in order to decide whether or not to route to the new state. In this tutorial we use both for learning purposes. Lets do the same thing in gallery.html but switch which state the first button routes to and add in an image (I chose an adorable alpaca from the internet).
We’ll also get the github view started. The github.html file should look like this for now:
Using The UI Router
Inside routes.js we will set up our routes to seamlessly swap out templates from index.html in order to display different views in the browser. To do this we call the config() method on our angular module in routes.js, and we have to pass ‘ui.router’ as a dependency to the module:
In routes.js above we are creating the Angular module called ‘routesApp’, which means we have to include its dependencies list. Our module requires another module called ‘ui.router’ so we include it here. The method used in Angular to handle routing is config(). Unlike controllers config doesn’t get a name, but it does take the same kind of array of Angular services that the controllers have for injecting the services it will use.
The UI Router uses two services that we have to inject into the config() function here. The UI Router uses the concept of states in which a URL path, views, and controllers are all parts of that state. It routes by directly by state instead of by URL path. The the URL path, the HTML view being displayed, and the controller being used are tied to which state the UI Router is currently at. The $stateProvider service is what we use to define these states.
The $urlRouterProvider allows us to define what happens when the user tries to route to a specific URL path manually. We will only be using the $urlRouterProvider on one line of code in here, and that is to define what happens when the browser tries to route to any URL that isn’t specified in one of our states. To do this we use the otherwise() method on the $urlRouterProvider, which takes as an argument a string representating a URL path. With this line of code we can tell the UI Router to send the browser to a specific URL path whenever the URL doesn’t match any of the URLs defined in our states. Here we make it route to the root URL, ‘/’, which is the URL for our home state so Angular will route there when given an undefined URL. Notice that Angular will put ‘#/’ in the URL path immediately preceding the Angular paths. This can be removed, but that is a lesson for another time.
Inside the config() function of routes.js add this line of code.
Now we need to define our three routes. Inside the config function add this code.
As shown above, setting up routes with the UI Router involves making states using the state() method of the $stateProvider service. As you can see, we chain multiple state() methods onto the $stateProvider service. The state() method takes two arguments: the name of the state and an object that holds all the information about the state. Inside the object we define properties of the state, including the URL that will display in the browser, the HTML template that will be loaded into the ui-view div, and the controller that is used for that template (which is why we don’t need to use ng-controller). That’s it for understanding the basics of the UI Router!
Making Our Controllers Handle The Routing
Now we need to set up our changeState() function in the controllers so that our buttons that use ng-click will work. First we will have to inject the $state service into each of our controllers. $state gives us the ability to route by state in our code. Notice where we inject $state into our controllers, it is just the same as injecting $scope or any other Angular service. We will be using $state’s go() method to route to the state that we passed in as an argument to the changeState() function. Our three controllers should now look like this:
Great, now reload the browser and click on each button, you’ll see the browser seemlessly routes to each of our three views.
Using $http
In the final section of this article I’ll introduce you to Angular’s $http service. This is how we do AJAX calls in Angular. Here we will make a GET request to GitHub’s API to get my GitHub user data and display some of it in our GitHub view. To make a GET request with $http we use $http.get(). It takes one argument which is the URL we hit with the GET request. We then chain a success and error function onto the end of $http.get(), each of which takes a callback function. If the request succeeds the success function will be executed where we can get access to the data we pulled down from that URL and do something with it. If the GET request fails the error() function will be run instead. The callback in both the success and error functions can be passed up to four arguments: data, status, headers, and config. You should console.log() each of them to see what you get on both success and error (make the error function run by deleting something from the correct URL we are using below). In our code, however, I will only use the data argument to get the actual data. Here is the syntax for using an Angular GET request:
Now for our actual code. The API endpoint to get a user’s profile data from GitHub is ‘https://api.github.com/users/USERNAME' where USERNAME is that user’s username of course. My GitHub name is theCodeBear, so our GET request will go to ‘https://api.github.com/users/theCodeBear'. We will save the data into a new property of $scope that we will call ‘user’ so that we can display the data in the github.html view. Don’t forget we have to inject the $http service into the controller as well. The githubController.js file should now look like:
On success I am also putting the data into console.log() so I can see it in the browser’s dev tools console. By looking at the object displayed in the console we can see that, among a bunch of other data, my username is under the ‘login’ key, my name is under the ‘name’ key, my photo is under the ‘avatar_url’ key, and my location is under the ‘location’ key. We will display these four items from my GitHub profile in our github.html using Angular’s {{ }} syntax. For example, we saved the data to $scope.user, so we can access my GitHub username with {{ user.login }}. Underneath our two buttons in github.html add the following code to display my GitHub profile.
This Angular routing tutorial is now done! Make sure your app works, if it doesn’t look back at the code to see if you made any typos.
Summary
You now know how to create Single Page Applications using AngularJS. You also got introduced to two new Angular services: $state and $http. And you’ve seen how ui-sref can easily route your Single Page Application to different states.
View the full code for this tutorial on Github.
In the final part of this series we will create a to-do list in Angular using some of what you have learned in these first two parts. You’ll also learn how to make your own custom Angular service to store data across your entire Angular application and access it from any controller.