So You Want to Build a SPA

by John Tucker

HTML

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-route.min.js"></script>
<script src="//cdn.firebase.com/js/client/2.0.6/firebase.js"></script>
<!-- index.html -->
<!-- normally files are stored in separate files; need to src js
<script src="controllers/my_controllers.js"></script>
<script src="app.js"></script>
<script src="routes/routes.js"></script>
-->
<div ng-app="myApp">
   <div ng-view></div>
    
    <!-- /views/home.html (obmit work-around script tag)-->
    <script type="text/ng-template" id="views/home.html">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Home</h3>
            </div>
            <ul class="list-group">
                <li ng-if="! authenticated" ng-click="navigate('/login');" class="list-group-item">Login</li>
                <li ng-if="authenticated" ng-click="logout();" class="list-group-item">Logout</li>
                <li ng-click="navigate('/wineries');" class="list-group-item">Wineries</li>
                <li ng-click="navigate('/wines');" class="list-group-item">Wines</li>
            </ul>
        </div>
    </script>
    <!-- EOF -->
    
    <!-- /views/login.html (obmit work-around script tag)-->
    <script type="text/ng-template" id="views/login.html">      
        <div class="panel panel-default">
            <div class="panel-heading">
                 <h3 class="panel-title"><button ng-click="navigate('/');" class="btn btn-default"><span class="glyphicon glyphicon-chevron-left"></span> Back</button> Login</h3>                
            </div>
            <div class="panel-body">
                <form name="login_form" role="form" novalidate>
                    <div ng-class="{'form-group': true, 'has-feedback': true, 'has-error': login_form.email.$invalid}">
                        <label class="control-label"...

CSS

</style>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<style>

JavaScript

// controllers/my_controllers.js
var controllers = angular.module('myControllers', []);
controllers.controller('HomeCntrl', ['$scope', '$location', '$window', function($scope, $location, $window) {
    var myDataRef;
    $scope.navigate = function(path) {
        $location.path(path);
    };
    $scope.authenticated = false;
    myDataRef = new $window.Firebase('https://wineapp.firebaseio.com');
    $scope.logout = function() {
        $scope.authenticated = false;
        myDataRef.unauth();
    };
    var authData = myDataRef.getAuth();
	if (authData != null) {
        $scope.authenticated = true;
    }
}]);
controllers.controller('LoginCntrl', ['$scope', '$location', '$window', '$timeout', function($scope, $location, $window, $timeout) {
    var myDataRef;
    $scope.navigate = function(path) {
        $location.path(path);
    };
    $scope.failed = false;
    myDataRef = new $window.Firebase('https://wineapp.firebaseio.com');
    $scope.login = function() {
        myDataRef.authWithPassword({
            email: $scope.email,
            password: $scope.password
        }, function(error, authData) {
            $timeout(function() {			
                if (! error) {
                    $scope.navigate('/');
                } else {
                    $scope.failed = true;
                    $scope.password = '';
                }
            });
        });;
    };
}]);
controllers.controller('WineriesCntrl', ['$scope', '$location', '$window', '$timeout', function($scope, $location, $window, $timeout) {                       
    var myDataRef;
    $scope.wineries;
    $scope.navigate = function(path) {
        $location.path(path);        
    };
    myDataRef = new $window.Firebase('https://wineapp.firebaseio.com');
    myDataRef.child('wineries').once('value', function(snapshot) {
        $timeout(function() {
            $scope.wineries = Object.keys(snapshot.val()).map(function(key) {
                return {key: key, val: snapshot.val()[key]};
    ...