How to Set Up HelloJS in Ionic Framework with Angular UI Router
UPDATE: I have written another article for Facebook Login with Ionic and Angular UI Router, and integrates with Parse.com as the backend. I believe it is more complete and more useful than this article. Please see How to set up Facebook Connect Plugin and Parse.com in Ionic / Phonegap.
I found HelloJS when I was looking for an easy way to implement Facebook login in Ionic for my Phonegap app. It was really easy to get it working despite my lack of experience with Ionic or Angularjs in general.
HelloJS takes all the heavy lifting away from us and helps us integrate our app easily with most of the popular social login platforms. On top of that, it also comes with some handy api functions to retrieve data from these social platforms, so I really recommend it to everyone out there.
Here, I am going to demonstrate on how you too can get it running within minutes in Ionic by using HelloJS with Angular UI Router.
If you would like to delve straight into the codes, you can have a look at the sample app at Github. I have purposely structured the commits in a step-by-step way for clarity.
Otherwise, let’s get started...
Start an Ionic App
Obvious first step. Let’s start an Ionic App called myapp. Type these into terminal:
$ ionic start myapp blank
Let’s tentatively add iOS support to our Ionic App:
$ ionic platform add ios
Set up the routes for Angular UI Router
We are going to set up 2 states in Angular UI Router. A state is the equivalent of a route for Angular UI Router. What we want to add here is a state for user to login, and a state that only logged in users can see. And if the user enters a unspecified state, he should be redirected to the login state.
For that we have /login
for the login page, and the root path /
for the logged in users. Add the following codes to the bottom of app.js
at this point.
.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'homeCtrl',
data: {
authenticate: true
}
})
.state('login', {
url: '/login',
templateUrl: 'login.html',
controller: 'loginCtrl',
data: {
authenticate: false
}
});
// Send to login if the URL was not found
$urlRouterProvider.otherwise('/login');
})
You can see that we added 2 states named home
and login
respectively here with the following parameters:
- url – The URL to access the state.
- templateUrl – The view file path relative to app.js
- controller – The controller’s name that would be handling this state.
- data.authenticate – This is a custom object we added to check if a specific state requires authentication. True = authentication is required.
Note that by default, ionic.bundle.js
includes angular-ui-router.js
. There is no need to include angular-ui-router.js
as well as adding the angular-ui-router
module into myapp
.
Add the controllers
We have specified homeCtrl
and loginCtrl
to handle our states respectively. We need to add these into app.js
as well. Add the following code at the bottom of app.js
:
.controller('homeCtrl', function() {
})
.controller('loginCtrl', function() {
})
Add the views
Create a new file called home.html
and add the following codes:
<ion-header-bar class="bar-stable">
<h1 class="title">MyApp Home</h1>
</ion-header-bar>
<ion-content>
<div style="padding: 10px;">
Welcome to MyApp, {{user.name}}!
<button class="button button-block button-positive">
Log out from Facebook
</button>
</div>
</ion-content>
Create a new file called login.html
and add the following codes:
<ion-header-bar class="bar-stable">
<h1 class="title">MyApp Login</h1>
</ion-header-bar>
<ion-content>
<div style="padding: 10px; height: 100%;">
<button class="button button-block button-positive">
Log in with Facebook
</button>
</div>
</ion-content>
Change index.html to work with Angular UI Router
Now for these views to work, we need to replace the following codes in index.html
:
<ion-header-bar class="bar-stable">
<h1 class="title">Ionic Blank Starter</h1>
</ion-header-bar>
<ion-content>
</ion-content>
with:
<div ui-view></div>
Basically what this does is that, UI Router would replace <div ui-view></div>
with the content as loaded from the views.
Test Your Routes
By now, the routes should be working. Start the Ionic server in terminal:
$ ionic serve
This should automatically open a tab in your browser for http://localhost:8100/#/login
. This would be the login
state as defined earlier on. You can access the home
state via http://localhost:8100/#/
.
The reason why we ended up with login
state is because UI Router does not recognize http://localhost:8100/
, and such redirected to the login
state as defined in our configurations in app.js
earlier on at this line.
// Send to login if the URL was not found
$urlRouterProvider.otherwise('/login');
Note that Angular UI Router’s URL usually comes with a /#/
in between.
Download and include HelloJS
Go to http://adodson.com/hello.js/#install and download the hello.js
.
Move hello.all.js
or hello.all.min.js
to myapp/www/js/hello.js
.
Then include the javascript file into index.html just before app.js
:
<!-- third party js -->
<script src="js/hello.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
Add authentication checking to Ionic
Go into app.js
, look for this line:
.run(function($ionicPlatform) {
Replace it with these:
.run(function($ionicPlatform, $rootScope, $state, userService) {
Here we are injecting $rootScope
from AngularJS, $state
from Angular UI Router, and userService
which would be created by us later.
Next, let’s add the authentication checking to our .run()
method.
.run(function($ionicPlatform, $rootScope, $state, userService) {
$ionicPlatform.ready(function() {
...
});
// Add these
// UI Router Authentication Check
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
if (toState.data.authenticate && !userService.isLoggedIn()){
// User isn’t authenticated
$state.transitionTo("login");
event.preventDefault();
}
});
})
So what we are checking here are 2 conditions. First, we see if the toState
, aka the state we will be going to has data.authenticate
defined as true. If it is true, then we need to check if user is logged in via userService.isLoggedIn()
method. If user is not logged in, we will redirect him to the login
state.
Add HelloJS to Ionic
Go to app.js
and add the following codes:
.factory('userService', ['$rootScope', '$state', function($rootScope, $state) {
// Hello.js Functions
hello.init({
// Change this to your own facebook app id
facebook : '1234567890'
}, {
redirect_uri:'https://www.facebook.com/connect/login_success.html'
});
var service = {
isLoggedIn: function() {
return $rootScope.userStatus;
},
login: function() {
hello('facebook').login( function() {
hello( 'facebook' ).api( '/me' ).success(function(json) {
console.log(json);
$rootScope.user = json;
$rootScope.$apply($rootScope.user);
$rootScope.userStatus = true;
$state.go('home');
});
});
},
logout: function() {
hello('facebook').logout( function() {
$rootScope.userStatus = false;
$rootScope.user = null;
$state.go('login');
});
}
}
return service;
}])
In-depth look into the codes (optional)
Let’s de-construct the codes and see what we have added. If you are not interested in explanation, feel free to skip this and move onto the next section.
First we are adding a factory method called userService
that is called in our .run()
method as part of authentication checking. It has access to $rootScope
so that we can access user details everywhere in our app once user is authenticated, and $state
so that we can redirect user with UI Router once user is authenticated.
.factory('userService', ['$rootScope', '$state', function($rootScope, $state) {
Next, we initialize HelloJS with our Facebook App Id. This is required so that HelloJS knows which Facebook App it should shake hand with. If you do not yet have your Facebook App created yet, go to Facebook Developers > Apps to create one for free.
hello.init({
// Change this to your own facebook app id
facebook : '354940007993444'
});
Then we have a service{}
object that will be returned each time userService()
is called. Within service{}
, we have 3 methods defined. isLoggedIn
is a method that checks if user is logged in as the name suggests. login
is a method to register user information to our system once user is authenticated, and logout
is to clear user credentials from our system when user logs out.
var service = {
isLoggedIn: function() {},
login: function() {},
logout: function() {}
}
return service;
Taking a closer look into the methods within service{}
, we can see that isLoggedIn()
is a very simple method that returns the $rootScope.userStatus
variable whenever it is called. So where is this variable defined?
isLoggedIn: function() {
return $rootScope.userStatus;
},
A quick look at login()
will reveal the answer. But $rootScope.userStatus
is only set after we do a few things.
First, when the login()
method is called, we will use methods provided by HelloJS, hello().login()
to log in the user to Facebook.
When the login is successful, we would like more details about the user such as his name, email etc right? That’s when we call the hello().api('/me').success()
method. User information will be returned in a json format, and we will promptly save it to our $rootScope.user
. At the same time, we will notify all the view files that are using $rootScope.user
that there is an update, and that they should display the latest value.
Then we set $rootScope.userStatus
to true so that our isLoggedIn()
method would return the correct value to UI Router for authentication checking.
Finally, when everything is done, we redirect user to the home
state.
login: function() {
hello('facebook').login( function() {
hello( 'facebook' ).api( '/me' ).success(function(json) {
console.log(json);
$rootScope.user = json;
$rootScope.$apply($rootScope.user);
$rootScope.userStatus = true;
$state.go('home');
});
});
},
And now to the final service{}
method, logout()
. Again, we utilize a HelloJS method, hello().logout()
to end user’s Facebook session in our app. At the same time, we need to make sure that $rootScope.userStatus
is set to false so that our authentication checking will function correctly, and that user will be redirected based on the right condition.
Finally, we also reset user’s credentials in our app by clearing off the data in $rootScope.user
, the variable which we used to hold all user’s information.
logout: function() {
hello('facebook').logout( function() {
$rootScope.userStatus = false;
$rootScope.user = null;
$state.go('login');
});
}
And the last missing piece
Now that we have all the back-end codes in place, all we still need to do is tie the back-end codes to our front-end view.
To do this, first let’s add a ng-click parameter to our buttons at login.html
and home.html
.
In login.html
:
<button class="button button-block button-positive" ng-click="login()">
In home.html
:
<button class="button button-block button-positive" ng-click="logout()">
For the login()
and logout()
functions to work, we will have to add them in our controllers. So let’s do that in app.js
. Your new controllers should now be replaced and look like these:
.controller('homeCtrl', ['$scope', 'userService',function($scope, userService) {
$scope.logout = userService.logout;
}])
.controller('loginCtrl', ['$scope', 'userService', function($scope, userService) {
$scope.login = userService.login;
}]);
What we have here is that we injected $scope
and userService
into our controllers. This is so that when the buttons in our views are clicked/tapped on, our controllers would translate that into calling the methods in userService
and perform all the relevant authentication actions.
Final verdict
Now let’s test that the authentication is in fact working. First, make sure that ionic serve
is still running in your terminal.
Then go to your browser and open http://localhost:8100/
. You should be redirected to the login state at http://localhost:8100/#/login
since you have not authenticated yourself.
Now login at the login
state. Does it redirect you to the home
state and showing you the right page? If it does, congrats!
Finally, click the logout button. You should be redirected back to the login
state. Now try to go back to http://localhost:8100
again and see if our authentication checking system still work.
With that, you now have a functioning authenticating system that utilizes Facebook Login, by using HelloJS together with Angular UI Router in your Ionic app!
If you are starting on a new Ionic app, feel free to fork or clone my codes in Github as your base app to get started with. May save some time. 🙂