Tutorial

Single Page Apps with AngularJS Routing and Templating

Draft updated on Invalid Date
Default avatar

By Chris on Code

Single Page Apps with AngularJS Routing and Templating

This tutorial is out of date and no longer maintained.

Introduction

Single-page apps are becoming increasingly popular. Sites that mimic the single-page app behavior are able to provide the feel of a phone/tablet application. Angular helps to create applications like this easily.

Our Simple App

We’re just going to make a simple site with a home, about, and contact page. Angular is built for much more advanced applications than this, but this tutorial will show many of the concepts needed for those larger projects.

Goals

  • Single page application
  • No page refresh on page change
  • Different data on each page

While this can be done with just Javascript and AJAX calls, Angular will make this process easier as our app starts growing.

File Structure

        - script.js             <!-- stores all our angular code -->
        - index.html            <!-- main layout -->
        - pages                 <!-- the pages that will be injected into the main layout -->
        ----- home.html
        ----- about.html
        ----- contact.html

HTML

This is the simple part. We’re using Bootstrap and Font Awesome. Open up your index.html file and we’ll add a simple layout with a navigation bar.

index.html
        <!DOCTYPE html>
        <html>
        <head>
          <!-- load bootstrap and fontawesome via CDN -->
          <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
          <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />

          <!-- load angular and angular route via CDN -->
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
          <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.js"></script>
          <script src="script.js"></script>
        </head>
        <body>

            <!-- HEADER AND NAVBAR -->
            <header>
                <nav class="navbar navbar-default">
                <div class="container">
                    <div class="navbar-header">
                        <a class="navbar-brand" href="/">Angular Routing Example</a>
                    </div>

                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="#"><i class="fa fa-home"></i> Home</a></li>
                        <li><a href="#about"><i class="fa fa-shield"></i> About</a></li>
                        <li><a href="#contact"><i class="fa fa-comment"></i> Contact</a></li>
                    </ul>
                </div>
                </nav>
            </header>

            <!-- MAIN CONTENT AND INJECTED VIEWS -->
            <div id="main">

                <!-- angular templating -->
                <!-- this is where content will be injected -->

            </div>

        </body>
        </html>

For linking to pages, we’ll use the #. We don’t want the browser to think we are actually traveling to about.html or contact.html.

Angular Application

Module and Controller

We’re going to set up our application. Let’s create the angular module and controller. Check out the docs for more information on each.

First, we have to create our module and controller in javascript. We will do that now in script.js.

script.js
        // create the module and name it scotchApp
        var scotchApp = angular.module('scotchApp', []);

        // create the controller and inject Angular's $scope
        scotchApp.controller('mainController', function($scope) {

            // create a message to display in our view
            $scope.message = 'Main Controller message';
        });

Let’s add the module and controller to our HTML so that Angular knows how to bootstrap our application. To test that everything is working, we will also show the $scope.message variable that we created.

index.html
        <!DOCTYPE html>

        <!-- define angular app -->
        <html ng-app="scotchApp">
        <head>
          <!-- load bootstrap and fontawesome via CDN -->
          <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
          <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css" />

          <!-- load angular via CDN -->
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
          <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular-route.js"></script>
          <script src="script.js"></script>
        </head>

        <!-- define angular controller -->
        <body ng-controller="mainController">

        ...

        <!-- MAIN CONTENT AND INJECTED VIEWS -->
        <div id="main">
            {{ message }}

            <!-- angular templating -->
            <!-- this is where content will be injected -->
        </div>

Inside of our main div, we will now see the message that we created. Since we have our module and controller set up and we know that Angular is working properly, we will start working on using this layout to show the different pages.

Injecting Pages into the Main Layout

ng-view is an Angular directive that will include the template of the current route (/home, /about, or /contact) in the main layout file. In plain words, it takes the file we want based on the route and injects it into our main layout (index.html).

We will add the ng-view code to our site in the div#main to tell Angular where to place our rendered pages.

index.html
        ...

        <!-- MAIN CONTENT AND INJECTED VIEWS -->
        <div id="main">

            <!-- angular templating -->
            <!-- this is where content will be injected -->
            <div ng-view></div>

        </div>

        ...

Configure Routes and Views

Since we are making a single-page application and we don’t want any page refreshes, we’ll use Angular’s routing capabilities.

Let’s look at our Angular file and add it to our application. We will be using $routeProvider in Angular to handle our routing. This way, Angular will handle all of the magic required to go get a new file and inject it into our layout.

AngularJS 1.2 and Routing The ngRoute module is no longer included in Angular after version 1.1.6. You will need to call the module and add it to the head of your document to use it. This tutorial has been updated for AngularJS 1.2

script.js
        // create the module and name it scotchApp
        // also include ngRoute for all our routing needs
        var scotchApp = angular.module('scotchApp', ['ngRoute']);

        // configure our routes
        scotchApp.config(function($routeProvider) {
            $routeProvider

                // route for the home page
                .when('/', {
                    templateUrl : 'pages/home.html',
                    controller  : 'mainController'
                })

                // route for the about page
                .when('/about', {
                    templateUrl : 'pages/about.html',
                    controller  : 'aboutController'
                })

                // route for the contact page
                .when('/contact', {
                    templateUrl : 'pages/contact.html',
                    controller  : 'contactController'
                });
        });

        // create the controller and inject Angular's $scope
        scotchApp.controller('mainController', function($scope) {
            // create a message to display in our view
            $scope.message = 'Main Controller message.';
        });

        scotchApp.controller('aboutController', function($scope) {
            $scope.message = 'About Controller message.';
        });

        scotchApp.controller('contactController', function($scope) {
            $scope.message = 'Contact Controller message.';
        });

Now we have defined our routes with $routeProvider. As you can see by the configuration, you can specify the route, the template file to use, and even a controller. This way, each part of our application will use its own view and Angular controller.

Clean URLs: By default, Angular will throw a hash (#) into the URL. To get rid of this, we will need to use $locationProvider to enable the HTML History API. This will remove the hash and make pretty URLs. For more information: Pretty URLs in AngularJS: Removing the #.

Our home page will pull the home.html file. About and contact will pull their respective files. Now if we view our app, and click through the navigation, our content will change just how we wanted.

To finish off this tutorial, we just need to define the pages that will be injected. We will also have them each display a message from its respective controller.

home.html
        <div class="jumbotron text-center">
            <h1>Home Page</h1>

            <p>{{ message }}</p>
        </div>
about.html
        <div class="jumbotron text-center">
            <h1>About Page</h1>

            <p>{{ message }}</p>
        </div>
contact.html
        <div class="jumbotron text-center">
            <h1>Contact Page</h1>

            <p>{{ message }}</p>
        </div>

Working Locally: Angular routing will only work if you have an environment set for it. Make sure you are using http://localhost or some sort of environment. Otherwise Angular will spit out a Cross origin requests are only supported for HTTP.

Animating Angular Apps

Once you have all the routing done, you can start to get really fancy with your site and add in animations. To do this, you will need the ngAnimate module provided by Angular. After that, you can animate your pages into view with CSS animations.

For a tutorial on how to get animations on your site, read: Animating AngularJS Apps: ngView.

SEO on Single Page Apps

Ideally, this technique would be used for an application after a person has signed in. You wouldn’t really want those pages indexed since they are personalized to that specific user. For example, you wouldn’t want your Reader account, Facebook logged in pages, or Blog CMS pages indexed.

If you did want SEO for your application though, how does SEO work for applications/sites that get their pages built with Javascript? Search engines have a difficult time processing these applications because the content is built dynamically by the browser and not visible to crawlers.

Making Your App SEO Friendly

Techniques to make JavaScript single-page applications SEO friendly require regular maintenance. According to the official Google suggestions, you would create HTML snapshots. The basic overview of how it would work is that:

  1. A crawler would find a pretty URL (https://scotch.io/seofriendly#key=value)
  2. The crawler would then ask the server for the contents of this URL (in a special modified way)
  3. Web server returns content using an HTML snapshot
  4. HTML snapshot is processed by the crawler
  5. Search results then show the original URL

For more information on this process, be sure to look at Google’s AJAX Crawling and their guide on creating HTML snapshots.

SEO Article: We’ve written up a tutorial on how to make Angular SEO friendly. Give it a read if you’re interested: AngularJS SEO with Prerender.io.

Conclusion

This was a very simple tutorial on how to get Angular routing to work with a layout and separate views. Now you can go ahead and create larger single-page applications. There is much more to learn with Angular and I’ll keep writing about different features along my learning journey of Angular.

If anyone has any suggestions for future Angular articles or different ways to do what we’ve just done here (there are so many ways to write the same thing, it can drive a person insane), sound off in the comments.

Further Reading

If you are looking for more flexibility in routing like nested views and state-based templating instead of route-based, then you’ll definitely be interested in UI Router. For an article on UI Router: AngularJS Routing Using UI-Router

Note: Added information on SEO for using this technique.

Note: Updated article for AngularJS 1.2

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Chris on Code

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel