├── .bowerrc ├── ionic.project ├── .io-config.json ├── www ├── img │ ├── ionic.png │ └── logo1.png ├── css │ └── style.css ├── templates │ ├── tab-rooms.html │ ├── tabs.html │ ├── signup.html │ ├── login.html │ └── tab-chat.html ├── index.html └── js │ ├── services.js │ ├── controllers.js │ └── app.js ├── README.md ├── .gitignore ├── bower.json ├── package.json ├── config.xml ├── scss └── ionic.app.scss ├── gulpfile.js └── hooks ├── after_prepare └── 010_add_platform_class.js └── README.md /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "www/lib" 3 | } 4 | -------------------------------------------------------------------------------- /ionic.project: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-firebase", 3 | "app_id": "7b31aa8d" 4 | } 5 | -------------------------------------------------------------------------------- /.io-config.json: -------------------------------------------------------------------------------- 1 | {"app_id":"7b31aa8d","api_key":"a897f0826a7cd779be176b110a2dc5baaec56b6eb819ab6a"} -------------------------------------------------------------------------------- /www/img/ionic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mappmechanic/ionic-firebase/HEAD/www/img/ionic.png -------------------------------------------------------------------------------- /www/img/logo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mappmechanic/ionic-firebase/HEAD/www/img/logo1.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ionic-firebase 2 | Real Time multi person Chat App using Ionic & Firebase 3 | 4 | It uses the AngularFire library to connect to firebase. 5 | 6 | Steps: 7 | 8 | clone this repo 9 | ```bash 10 | cd ./ionic-firebase-master 11 | npm start 12 | ``` 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | node_modules/ 5 | platforms/ 6 | plugins/ 7 | ionic.project 8 | .io-config.json 9 | /www/css/ionic.app.css 10 | /www/css/ionic.app.min.css 11 | /www/lib/ -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-firebase", 3 | "private": "true", 4 | "devDependencies": { 5 | "ionic": "driftyco/ionic-bower#1.0.0" 6 | }, 7 | "dependencies": { 8 | "firebase": "2.4.2", 9 | "angularfire": "0.9.1", 10 | "angular-moment": "0.9.0" 11 | }, 12 | "resolutions": { 13 | "firebase": "2.4.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /www/css/style.css: -------------------------------------------------------------------------------- 1 | .logo { 2 | display: block; 3 | position: relative; 4 | width: 60%; 5 | margin: 0 auto; 6 | } 7 | .logoText { 8 | text-align: center; 9 | font-size: 28px; 10 | font-family: fantasy; 11 | } 12 | .item-note { 13 | font-size: 10px; 14 | margin-top: -22px; 15 | margin-right: -35px; 16 | } 17 | .textCenter { 18 | text-align: center; 19 | } -------------------------------------------------------------------------------- /www/templates/tab-rooms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

{{room.name}}

7 |
8 |
9 | 10 | 11 | Loading Rooms 12 | 13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-firebase", 3 | "version": "1.0.0", 4 | "description": "ionic-firebase: An Ionic project", 5 | "dependencies": { 6 | "gulp": "^3.5.6", 7 | "gulp-clean-css": "^2.0.1", 8 | "gulp-concat": "^2.2.0", 9 | "gulp-rename": "^1.2.0", 10 | "gulp-sass": "^2.3.2" 11 | }, 12 | "devDependencies": { 13 | "bower": "^1.3.3", 14 | "gulp-util": "^2.2.14", 15 | "shelljs": "^0.3.0" 16 | }, 17 | "scripts": { 18 | "postinstall": "bower install && gulp", 19 | "update-deps": "npm update", 20 | "postupdate-deps": "bower update", 21 | "prestart": "npm install", 22 | "start": "ionic serve" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ionic-firebase 4 | 5 | An Ionic Framework and Cordova project. 6 | 7 | 8 | Ionic Framework Team 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /scss/ionic.app.scss: -------------------------------------------------------------------------------- 1 | /* 2 | To customize the look and feel of Ionic, you can override the variables 3 | in ionic's _variables.scss file. 4 | 5 | For example, you might change some of the default colors: 6 | 7 | $light: #fff !default; 8 | $stable: #f8f8f8 !default; 9 | $positive: #387ef5 !default; 10 | $calm: #11c1f3 !default; 11 | $balanced: #33cd5f !default; 12 | $energized: #ffc900 !default; 13 | $assertive: #ef473a !default; 14 | $royal: #886aea !default; 15 | $dark: #444 !default; 16 | */ 17 | 18 | // The path for our ionicons font files, relative to the built CSS in www/css 19 | $ionicons-font-path: "../lib/ionic/fonts" !default; 20 | 21 | // Include all of Ionic 22 | @import "www/lib/ionic/scss/ionic"; 23 | 24 | -------------------------------------------------------------------------------- /www/templates/tabs.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /www/templates/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Create New Account

4 | 5 |
6 | 7 |
8 | 12 | 16 | 20 | 21 |
22 |
23 |
-------------------------------------------------------------------------------- /www/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | myChat 7 |
8 |
9 |
10 | 14 | 18 | 21 | 24 |
25 |
26 | 29 |
30 |
31 |
-------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var bower = require('bower'); 4 | var concat = require('gulp-concat'); 5 | var sass = require('gulp-sass'); 6 | var minifyCss = require('gulp-clean-css'); 7 | var rename = require('gulp-rename'); 8 | var sh = require('shelljs'); 9 | 10 | var paths = { 11 | sass: ['./scss/**/*.scss'] 12 | }; 13 | 14 | gulp.task('default', ['sass']); 15 | 16 | gulp.task('sass', function(done) { 17 | gulp.src('./scss/ionic.app.scss') 18 | .pipe(sass()) 19 | .pipe(gulp.dest('./www/css/')) 20 | .pipe(minifyCss({ 21 | keepSpecialComments: 0 22 | })) 23 | .pipe(rename({ extname: '.min.css' })) 24 | .pipe(gulp.dest('./www/css/')) 25 | .on('end', done); 26 | }); 27 | 28 | gulp.task('watch', function() { 29 | gulp.watch(paths.sass, ['sass']); 30 | }); 31 | 32 | gulp.task('install', ['git-check'], function() { 33 | return bower.commands.install() 34 | .on('log', function(data) { 35 | gutil.log('bower', gutil.colors.cyan(data.id), data.message); 36 | }); 37 | }); 38 | 39 | gulp.task('git-check', function(done) { 40 | if (!sh.which('git')) { 41 | console.log( 42 | ' ' + gutil.colors.red('Git is not installed.'), 43 | '\n Git, the version control system, is required to download Ionic.', 44 | '\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.', 45 | '\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.' 46 | ); 47 | process.exit(1); 48 | } 49 | done(); 50 | }); 51 | -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /www/templates/tab-chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 12 | 13 | Loading Chats 14 | 15 | 16 |

No messages in this room. Send message to start.

17 |
18 | 19 |

{{chat.from}} :

20 | 21 | 22 |

{{chat.message}}

23 | 24 | Delete 25 | 26 |
27 |
28 | 29 | 30 |

Please select a room to chat first.

31 |
32 |
33 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /www/js/services.js: -------------------------------------------------------------------------------- 1 | angular.module('mychat.services', ['firebase']) 2 | .factory("Auth", ["$firebaseAuth", "$rootScope", 3 | function ($firebaseAuth, $rootScope) { 4 | var ref = new Firebase(firebaseUrl); 5 | return $firebaseAuth(ref); 6 | }]) 7 | 8 | .factory('Chats', function ($firebase, Rooms) { 9 | 10 | var selectedRoomId; 11 | 12 | var ref = new Firebase(firebaseUrl); 13 | var chats; 14 | 15 | return { 16 | all: function () { 17 | return chats; 18 | }, 19 | remove: function (chat) { 20 | chats.$remove(chat).then(function (ref) { 21 | ref.key() === chat.$id; // true item has been removed 22 | }); 23 | }, 24 | get: function (chatId) { 25 | for (var i = 0; i < chats.length; i++) { 26 | if (chats[i].id === parseInt(chatId)) { 27 | return chats[i]; 28 | } 29 | } 30 | return null; 31 | }, 32 | getSelectedRoomName: function () { 33 | var selectedRoom; 34 | if (selectedRoomId && selectedRoomId != null) { 35 | selectedRoom = Rooms.get(selectedRoomId); 36 | if (selectedRoom) 37 | return selectedRoom.name; 38 | else 39 | return null; 40 | } else 41 | return null; 42 | }, 43 | selectRoom: function (roomId) { 44 | console.log("selecting the room with id: " + roomId); 45 | selectedRoomId = roomId; 46 | if (!isNaN(roomId)) { 47 | chats = $firebase(ref.child('rooms').child(selectedRoomId).child('chats')).$asArray(); 48 | } 49 | }, 50 | send: function (from, message) { 51 | console.log("sending message from :" + from.displayName + " & message is " + message); 52 | if (from && message) { 53 | var chatMessage = { 54 | from: from.displayName, 55 | message: message, 56 | createdAt: Firebase.ServerValue.TIMESTAMP 57 | }; 58 | chats.$add(chatMessage).then(function (data) { 59 | console.log("message added"); 60 | }); 61 | } 62 | } 63 | } 64 | }) 65 | 66 | /** 67 | * Simple Service which returns Rooms collection as Array from Salesforce & binds to the Scope in Controller 68 | */ 69 | .factory('Rooms', function ($firebase) { 70 | // Might use a resource here that returns a JSON array 71 | var ref = new Firebase(firebaseUrl); 72 | var rooms = $firebase(ref.child('rooms')).$asArray(); 73 | 74 | return { 75 | all: function () { 76 | return rooms; 77 | }, 78 | get: function (roomId) { 79 | // Simple index lookup 80 | return rooms.$getRecord(roomId); 81 | } 82 | } 83 | }); -------------------------------------------------------------------------------- /hooks/after_prepare/010_add_platform_class.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Add Platform Class 4 | // v1.0 5 | // Automatically adds the platform class to the body tag 6 | // after the `prepare` command. By placing the platform CSS classes 7 | // directly in the HTML built for the platform, it speeds up 8 | // rendering the correct layout/style for the specific platform 9 | // instead of waiting for the JS to figure out the correct classes. 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | 14 | var rootdir = process.argv[2]; 15 | 16 | function addPlatformBodyTag(indexPath, platform) { 17 | // add the platform class to the body tag 18 | try { 19 | var platformClass = 'platform-' + platform; 20 | var cordovaClass = 'platform-cordova platform-webview'; 21 | 22 | var html = fs.readFileSync(indexPath, 'utf8'); 23 | 24 | var bodyTag = findBodyTag(html); 25 | if(!bodyTag) return; // no opening body tag, something's wrong 26 | 27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added 28 | 29 | var newBodyTag = bodyTag; 30 | 31 | var classAttr = findClassAttr(bodyTag); 32 | if(classAttr) { 33 | // body tag has existing class attribute, add the classname 34 | var endingQuote = classAttr.substring(classAttr.length-1); 35 | var newClassAttr = classAttr.substring(0, classAttr.length-1); 36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote; 37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr); 38 | 39 | } else { 40 | // add class attribute to the body tag 41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">'); 42 | } 43 | 44 | html = html.replace(bodyTag, newBodyTag); 45 | 46 | fs.writeFileSync(indexPath, html, 'utf8'); 47 | 48 | process.stdout.write('add to body class: ' + platformClass + '\n'); 49 | } catch(e) { 50 | process.stdout.write(e); 51 | } 52 | } 53 | 54 | function findBodyTag(html) { 55 | // get the body tag 56 | try{ 57 | return html.match(/])(.*?)>/gi)[0]; 58 | }catch(e){} 59 | } 60 | 61 | function findClassAttr(bodyTag) { 62 | // get the body tag's class attribute 63 | try{ 64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0]; 65 | }catch(e){} 66 | } 67 | 68 | if (rootdir) { 69 | 70 | // go through each of the platform directories that have been prepared 71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []); 72 | 73 | for(var x=0; x 21 | # Cordova Hooks 22 | 23 | This directory may contain scripts used to customize cordova commands. This 24 | directory used to exist at `.cordova/hooks`, but has now been moved to the 25 | project root. Any scripts you add to these directories will be executed before 26 | and after the commands corresponding to the directory name. Useful for 27 | integrating your own build systems or integrating with version control systems. 28 | 29 | __Remember__: Make your scripts executable. 30 | 31 | ## Hook Directories 32 | The following subdirectories will be used for hooks: 33 | 34 | after_build/ 35 | after_compile/ 36 | after_docs/ 37 | after_emulate/ 38 | after_platform_add/ 39 | after_platform_rm/ 40 | after_platform_ls/ 41 | after_plugin_add/ 42 | after_plugin_ls/ 43 | after_plugin_rm/ 44 | after_plugin_search/ 45 | after_prepare/ 46 | after_run/ 47 | after_serve/ 48 | before_build/ 49 | before_compile/ 50 | before_docs/ 51 | before_emulate/ 52 | before_platform_add/ 53 | before_platform_rm/ 54 | before_platform_ls/ 55 | before_plugin_add/ 56 | before_plugin_ls/ 57 | before_plugin_rm/ 58 | before_plugin_search/ 59 | before_prepare/ 60 | before_run/ 61 | before_serve/ 62 | pre_package/ <-- Windows 8 and Windows Phone only. 63 | 64 | ## Script Interface 65 | 66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: 67 | 68 | * CORDOVA_VERSION - The version of the Cordova-CLI. 69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). 70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) 71 | * CORDOVA_HOOK - Path to the hook that is being executed. 72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) 73 | 74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted. 75 | 76 | 77 | ## Writing hooks 78 | 79 | We highly recommend writting your hooks using Node.js so that they are 80 | cross-platform. Some good examples are shown here: 81 | 82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) 83 | 84 | -------------------------------------------------------------------------------- /www/js/controllers.js: -------------------------------------------------------------------------------- 1 | angular.module('mychat.controllers', []) 2 | 3 | .controller('LoginCtrl', function ($scope, $ionicModal, $state, $firebaseAuth, $ionicLoading, $rootScope) { 4 | //console.log('Login Controller Initialized'); 5 | 6 | var ref = new Firebase($scope.firebaseUrl); 7 | var auth = $firebaseAuth(ref); 8 | 9 | $ionicModal.fromTemplateUrl('templates/signup.html', { 10 | scope: $scope 11 | }).then(function (modal) { 12 | $scope.modal = modal; 13 | }); 14 | 15 | $scope.createUser = function (user) { 16 | console.log("Create User Function called"); 17 | if (user && user.email && user.password && user.displayname) { 18 | $ionicLoading.show({ 19 | template: 'Signing Up...' 20 | }); 21 | 22 | auth.$createUser({ 23 | email: user.email, 24 | password: user.password 25 | }).then(function (userData) { 26 | alert("User created successfully!"); 27 | ref.child("users").child(userData.uid).set({ 28 | email: user.email, 29 | displayName: user.displayname 30 | }); 31 | $ionicLoading.hide(); 32 | $scope.modal.hide(); 33 | }).catch(function (error) { 34 | alert("Error: " + error); 35 | $ionicLoading.hide(); 36 | }); 37 | } else 38 | alert("Please fill all details"); 39 | } 40 | 41 | $scope.signIn = function (user) { 42 | 43 | if (user && user.email && user.pwdForLogin) { 44 | $ionicLoading.show({ 45 | template: 'Signing In...' 46 | }); 47 | auth.$authWithPassword({ 48 | email: user.email, 49 | password: user.pwdForLogin 50 | }).then(function (authData) { 51 | console.log("Logged in as:" + authData.uid); 52 | ref.child("users").child(authData.uid).once('value', function (snapshot) { 53 | var val = snapshot.val(); 54 | // To Update AngularJS $scope either use $apply or $timeout 55 | $scope.$apply(function () { 56 | $rootScope.displayName = val; 57 | }); 58 | }); 59 | $ionicLoading.hide(); 60 | $state.go('tab.rooms'); 61 | }).catch(function (error) { 62 | alert("Authentication failed:" + error.message); 63 | $ionicLoading.hide(); 64 | }); 65 | } else 66 | alert("Please enter email and password both"); 67 | } 68 | 69 | $scope.reSet = function (user) { 70 | if (user.email) { 71 | auth.$sendPasswordResetEmail(user.email).then(function() { 72 | console.log("reset email sent"); 73 | alert("reset email sent"); 74 | }).catch(function(error) { 75 | alert("reset email failed:" + error.message); 76 | }); 77 | } else 78 | alert("Please enter email"); 79 | } 80 | }) 81 | 82 | .controller('ChatCtrl', function ($scope, Chats, $state) { 83 | //console.log("Chat Controller initialized"); 84 | 85 | $scope.IM = { 86 | textMessage: "" 87 | }; 88 | 89 | Chats.selectRoom($state.params.roomId); 90 | 91 | var roomName = Chats.getSelectedRoomName(); 92 | 93 | // Fetching Chat Records only if a Room is Selected 94 | if (roomName) { 95 | $scope.roomName = " - " + roomName; 96 | $scope.chats = Chats.all(); 97 | } 98 | 99 | $scope.sendMessage = function (msg) { 100 | console.log(msg); 101 | Chats.send($scope.displayName, msg); 102 | $scope.IM.textMessage = ""; 103 | } 104 | 105 | $scope.remove = function (chat) { 106 | Chats.remove(chat); 107 | } 108 | }) 109 | 110 | .controller('RoomsCtrl', function ($scope, Rooms, Chats, $state) { 111 | //console.log("Rooms Controller initialized"); 112 | $scope.rooms = Rooms.all(); 113 | 114 | $scope.openChatRoom = function (roomId) { 115 | $state.go('tab.chat', { 116 | roomId: roomId 117 | }); 118 | } 119 | }); -------------------------------------------------------------------------------- /www/js/app.js: -------------------------------------------------------------------------------- 1 | // MyChat App - Ionic & Firebase Demo 2 | 3 | var firebaseUrl = "https://sizzling-inferno-3944.firebaseio.com"; 4 | 5 | function onDeviceReady() { 6 | angular.bootstrap(document, ["mychat"]); 7 | } 8 | //console.log("binding device ready"); 9 | // Registering onDeviceReady callback with deviceready event 10 | document.addEventListener("deviceready", onDeviceReady, false); 11 | 12 | // 'mychat.services' is found in services.js 13 | // 'mychat.controllers' is found in controllers.js 14 | angular.module('mychat', ['ionic', 'firebase', 'angularMoment', 'mychat.controllers', 'mychat.services']) 15 | 16 | .run(function ($ionicPlatform, $rootScope, $location, Auth, $ionicLoading) { 17 | $ionicPlatform.ready(function () { 18 | // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard 19 | // for form inputs) 20 | if (window.cordova && window.cordova.plugins.Keyboard) { 21 | cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 22 | } 23 | if (window.StatusBar) { 24 | // org.apache.cordova.statusbar required 25 | StatusBar.styleDefault(); 26 | } 27 | // To Resolve Bug 28 | ionic.Platform.fullScreen(); 29 | 30 | $rootScope.firebaseUrl = firebaseUrl; 31 | $rootScope.displayName = null; 32 | 33 | Auth.$onAuth(function (authData) { 34 | if (authData) { 35 | console.log("Logged in as:", authData.uid); 36 | } else { 37 | console.log("Logged out"); 38 | $ionicLoading.hide(); 39 | $location.path('/login'); 40 | } 41 | }); 42 | 43 | $rootScope.logout = function () { 44 | console.log("Logging out from the app"); 45 | $ionicLoading.show({ 46 | template: 'Logging Out...' 47 | }); 48 | Auth.$unauth(); 49 | } 50 | 51 | 52 | $rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) { 53 | // We can catch the error thrown when the $requireAuth promise is rejected 54 | // and redirect the user back to the home page 55 | if (error === "AUTH_REQUIRED") { 56 | $location.path("/login"); 57 | } 58 | }); 59 | }); 60 | }) 61 | 62 | .config(function ($stateProvider, $urlRouterProvider) { 63 | console.log("setting config"); 64 | // Ionic uses AngularUI Router which uses the concept of states 65 | // Learn more here: https://github.com/angular-ui/ui-router 66 | // Set up the various states which the app can be in. 67 | // Each state's controller can be found in controllers.js 68 | $stateProvider 69 | 70 | // State to represent Login View 71 | .state('login', { 72 | url: "/login", 73 | templateUrl: "templates/login.html", 74 | controller: 'LoginCtrl', 75 | resolve: { 76 | // controller will not be loaded until $waitForAuth resolves 77 | // Auth refers to our $firebaseAuth wrapper in the example above 78 | "currentAuth": ["Auth", 79 | function (Auth) { 80 | // $waitForAuth returns a promise so the resolve waits for it to complete 81 | return Auth.$waitForAuth(); 82 | }] 83 | } 84 | }) 85 | 86 | 87 | // setup an abstract state for the tabs directive 88 | .state('tab', { 89 | url: "/tab", 90 | abstract: true, 91 | templateUrl: "templates/tabs.html", 92 | resolve: { 93 | // controller will not be loaded until $requireAuth resolves 94 | // Auth refers to our $firebaseAuth wrapper in the example above 95 | "currentAuth": ["Auth", 96 | function (Auth) { 97 | // $requireAuth returns a promise so the resolve waits for it to complete 98 | // If the promise is rejected, it will throw a $stateChangeError (see above) 99 | return Auth.$requireAuth(); 100 | }] 101 | } 102 | }) 103 | 104 | // Each tab has its own nav history stack: 105 | 106 | .state('tab.rooms', { 107 | url: '/rooms', 108 | views: { 109 | 'tab-rooms': { 110 | templateUrl: 'templates/tab-rooms.html', 111 | controller: 'RoomsCtrl' 112 | } 113 | } 114 | }) 115 | 116 | .state('tab.chat', { 117 | url: '/chat/:roomId', 118 | views: { 119 | 'tab-chat': { 120 | templateUrl: 'templates/tab-chat.html', 121 | controller: 'ChatCtrl' 122 | } 123 | } 124 | }) 125 | 126 | // if none of the above states are matched, use this as the fallback 127 | $urlRouterProvider.otherwise('/login'); 128 | 129 | }); --------------------------------------------------------------------------------