Wern Ancheta

Adventures in Web Development.

Getting Started With Ionic

| Comments

Hybrid Mobile App Development has been gaining traction lately. With the advent of tools such as Cordova, Sencha Touch and Titanium. There’s no more stopping web developers from creating their own mobile apps with web technologies. Yes I just said web technologies, that’s HTML, CSS, JavaScript and a little bit of talking to a server and you can already create a fancy mobile app. And because of this, lots of mobile frameworks has popped out. There’s Ionic, Onsen UI, Junior, Mobile Angular UI, and Kendo UI to name a few. Of those I’ve only ever tried jQuery Mobile and Ionic. At first I tried jQuery Mobile since I was already using jQuery for a long time. But it didn’t take me long to realize that it wasn’t for me nor the project that I was working on at that time. It just didn’t have what I need. jQuery Mobile is just a set of UI components that I could use in a mobile app. It didn’t have the foundation in which I could build upon. What I needed was a framework that would allow me to just start writing the app without having to worry about laying out the structure myself. This is where Ionic came in. It didn’t take me long to find it since it’s the first result that came up when I googled ‘mobile hybrid app framework’. Ionic utilizes Angular for its UI interactions, gestures and animations. And the best part is you can also use it to structure your app, because Angular itself is a JavaScript framework. Ok this intro is getting long. Let’s proceed with the fun stuff.

Setup

Node

In order to start working with Ionic, you first have to install Node. Go ahead and download the installer for your platform if you don’t already have it. If you’re an Ubuntu user, you can install Node using NVM (Node Version Manager). To install NVM, execute the following commands in order:

1
2
3
4
5
sudo apt-get install build-essential libssl-dev

curl https://raw.githubusercontent.com/creationix/nvm/v0.16.1/install.sh | sh

source ~/.profile

The first command, installs the build tools and SSL development libraries. The second downloads the NVM installer, and the third sources the ~/.profile file so that your current command-line session knows about the changes. This basically allows you to use the NVM command without having to logout.

Next, you can now list the available Node versions:

1
nvm ls-remote

This will list out a whole bunch of Node versions that are available. But usually you would want to install the current version, which is the last item on the list. At the time of writing of this article, the current version is v0.12.7. So you can go ahead and install that using the nvm install command:

1
nvm install v0.12.7

Now when you check the Node version installed on your machine, you would see v0.12.7.

1
node -v

Next you need to set this version as the default, otherwise you’ll have to execute nvm use v0.12.7 every time you need to use Node.

1
2
nvm alias default v0.12.7
nvm use default

Cordova and Ionic

Now we’re ready to install Cordova and Ionic:

1
npm install -g cordova ionic

Once that’s done installing, you can create a new project using the ionic start command. There are currently 3 available starter templates you can use: blank, tabs, and sidemenu. In this tutorial we’re going to use the tabs.

1
ionic start demoApp tabs

Ionic Directory Structure

The command above will create a demoApp directory which contains the following:

1
2
3
4
5
6
7
8
9
hooks
plugins
scss
www
bower.json
config.xml
gulpfile.js
ionic.project
package.json

The hooks directory is where you will put the scripts for customizing Cordova commands. I’ve never had the need to use this feature so I can’t share anything about it. But if you’re just getting started, you wouldn’t normally need to touch this directory.

The platforms directory is where the different platforms in which your app will be compiled to is stored. Note that its not there by default, you have to install a platform first.

The plugins directory is where Cordova plugins gets installed.

The scss directory is where the main Ionic sass file (ionic.app.scss) is stored. It contains the primary variables for customizing the colors used in your app.

The www directory is where you would usually work. This contains the HTML, JavaScript and CSS files. I won’t walk you through each of the contents of the www directory as they’re pretty self-explanatory.

The bower.json file contains the front-end dependencies of your app. By default it depends on Ionic. All bower dependencies are installed on the www/lib directory by default. You can install new one’s by using the bower install command and then link them on the index.html file in the www directory. When you install new libraries using bower, use the --save or --saveDev option so that it will save the package name on the bower.json file. The --save option is used to specify that the library you’re installing is a front-end asset. For example, jQuery or Bootstrap. While the --saveDev option is used for development only. Things like jshint or jasmine.

The config.xml file is where you can change the name, description and author of your app. You can also set your preference for device orientation (either portrait or landscape), features and URL’s which your app is allowed to access.

The gulpfile.js file is the Gulp config file used by Ionic. Normally you wouldn’t need to touch this. What you need to understand is that this is used by Ionic to execute tasks such as compiling sass files to CSS or watching a specific directory for changes.

The ionic.project file is where you can update the name and app_id of your app. You won’t really need to touch this.

Lastly, the package.json file. This contains the dependencies of the Ionic framework. You won’t really need to touch this.

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
{
  "name": "demoapp",
  "version": "1.0.0",
  "description": "demoApp: An Ionic project",
  "dependencies": {
    "gulp": "^3.5.6",
    "gulp-sass": "^1.3.3",
    "gulp-concat": "^2.2.0",
    "gulp-minify-css": "^0.3.0",
    "gulp-rename": "^1.2.0"
  },
  "devDependencies": {
    "bower": "^1.3.3",
    "gulp-util": "^2.2.14",
    "shelljs": "^0.3.0"
  },
  "cordovaPlugins": [
    "cordova-plugin-device",
    "cordova-plugin-console",
    "cordova-plugin-whitelist",
    "cordova-plugin-splashscreen",
    "com.ionic.keyboard"
  ],
  "cordovaPlatforms": []
}

Platforms

With Cordova there’s only a select few platforms that it supports. So it’s not completely write once, compile to all kind of thing. There are different sets of problems to solve for each platform in which you plan to release your app. The common platforms that you may want to install are android, ios and browser. For a list of all the platforms supported by Cordova, you can check out the Cordova Platform Guides. Each platform has a different dependency. Usually it’s the SDK or the recommended developer tool for that platform. For Android, it’s the Android SDK, for iOS it’s Xcode, for Windows it’s Visual Studio. I’m only going to walk you through the Android platform in this tutorial.

You can download the Android SDK installer from this page. Under the SDK Tools Only section, download the package for your platform. I’m on Ubuntu so I will download the one for Linux. Once the download is done, extract the files using the tar command or you can also right click on the file and select the archive manager of your choice.

1
tar -xvzf android-sdk_r24.3.3-linux.tgz

After extraction, it would yield an android-sdk-linux folder which contains the following:

1
2
3
4
add-ons
platforms
tools
SDK Readme.txt

From that directory, navigate to the tools directory and execute the android command:

1
./tools/android

This will open up the Android SDK Manager which you can use to install the tools that you need to develop Android apps. At this point you might wonder why we need to install the same things that Android developers need to install. Well, that’s because we’re still subjected to the same rules even if we write our apps using HTML, CSS, and JavaScript. Since apps created with Cordova and Ionic are just utilizing the Android WebView. Which is basically just a browser without a frame. That’s where the HTML, CSS and JavaScript are used. And Cordova just acts as a middleman between the WebView and the native Android functionalities. So if you need to use the camera for your app, Cordova uses the Android API to call for the camera. And once you’re done taking a picture it’s also the one responsible for returning the data back to your app. This means that Cordova just abstracts away the parts which we usually need to work on as native app developers so we can write our code in JavaScript instead of Java.

Back to where we left. Let’s now install the tools we need to get Cordova do its job. Check the following items on the Android SDK Manager and click on Install. This might take a while depending on your download speed.

Tools – Android SDK Tools

Android 5.1.1 (API 22) – SDK Platform

Android 5.0.1 (API 21) – SDK Platform – Google APIs

Android 4.4W.2 (API 20) – SDK Platform

Android 4.4.2 (API 19) – SDK Platform – Google APIs (ARM System Image)

Extras – Android Support Repository – Android Support Library – Google Repository

Once that’s done installing, add the path in which the Android SDK is installed to your environment. In Ubuntu and OSX, you can add the following on your .bashrc file:

1
2
3
export ANDROID_HOME=/path/to/android-sdk-linux/sdk
PATH=$PATH:/path/to/android-sdk-linux/sdk/tools
export PATH

In Windows, there’s something called the Environment Variables. I’ve written about it in my old blog: How to set environment variables.

Once that’s done, you can now install the Android platform, you can use the ionic platform add command followed by the name of the platform you want to install.

1
ionic platform add android

Using Sass

You can use sass with ionic by executing the following command while inside your project directory:

1
ionic setup sass

What this does is install the packages and tasks needed to compile sass. Then remove the following from your index.html file:

1
2
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">

It also adds the link to the ionic.app.css file which is basically just the compiled version of the ionic.app.scss file found in the scss directory.

1
<link href="css/ionic.app.css" rel="stylesheet">

Finally, it adds the following in your ionic.project file. This tells ionic to start the sass and watch command when gulp starts. It also specifies the watch patterns, so that every time you make a change to a file that matches the pattern, the sass command gets executed and compiles the sass files to css.

1
2
3
4
5
6
7
8
  "gulpStartupTasks": [
    "sass",
    "watch"
  ],
  "watchPatterns": [
    "www/**/*",
    "!www/lib/**/*"
  ]

If you want to change the default colors used by Ionic, this is where you can do that. Be sure to uncomment the variables just like what we have below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.

For example, you might change some of the default colors:
*/

$light:                           #fff !default;
$stable:                          #f8f8f8 !default;
$positive:                        #387ef5 !default;
$calm:                            #11c1f3 !default;
$balanced:                        #33cd5f !default;
$energized:                       #ffc900 !default;
$assertive:                       #ef473a !default;
$royal:                           #886aea !default;
$dark:                            #444 !default;


// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;

// Include all of Ionic
@import "www/lib/ionic/scss/ionic";

Now anytime you make a change to the file while running ionic serve, it will compile it to the ionic.app.css found at the www/css directory.

Developing an App

You can start developing your app by executing ionic serve from the root directory of your project. This will launch a new browser tab containing the app. If you’re using Chrome, you can click on the phone icon on the left of the elements tab when you open the developer tools. This would show your app inside a smaller screen depending on the device that you specify. You can change the device by clicking on the drawer icon which looks like this: >__. And then click on the emulation tab then select the device from the model dropdown. You might need to refresh the page after doing this so that it will render correctly.

app window

Now open the index.html file in the root directory of your project. This is where every thing is hooked up. If you have ever developed a single-page app before, this would be familiar to you. Basically how a single-page app works is that every script that you need is linked in the index.html file. You might be thinking this is a bad practice since it will take too long for the page to load. Well it’s not since the front-end assets are included in the app locally. It wouldn’t need to download it over the internet so it’s fast even if we have a lot of files linked in there.

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
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>


    <!-- compiled css output -->
    <link href="css/ionic.app.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/services.js"></script>
  </head>
  <body ng-app="starter">
    <!--
      The nav bar that will be updated as we navigate between views.
    -->
    <ion-nav-bar class="bar-stable">
      <ion-nav-back-button>
      </ion-nav-back-button>
    </ion-nav-bar>
    <!--
      The views will be rendered in the <ion-nav-view> directive below
      Templates are in the /templates folder (but you could also
      have templates inline in this html file if you'd like).
    -->
    <ion-nav-view></ion-nav-view>
  </body>
</html>

Ok let’s break this file down. First we set the charset to utf-8 and viewport so that the initial and maximum scale is 1, we also set the user-scalable option to no. This basically means the user wouldn’t be able to resize or zoom the app.

1
2
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

Next we have the title. This means nothing since we’re on an app not a website. So users wouldn’t be able to see this. You can leave it as blank.

1
<title></title>

And we also have the main ionic css file.

1
2
 <!-- compiled css output -->
<link href="css/ionic.app.css" rel="stylesheet">

Angular is bundled together with the Ionic JavaScript.

1
2
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>

We also need to link the cordova.js file so we can use Cordova within our app. This would allow us to use Cordova plugins as well via cordova.plugins.

1
2
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>

Then we have our custom JavaScript files. This is where we put code that makes the app do things for us. Note that the js/app.js file is the main JavaScript file. It is where we link every thing together. This is where we intialize a new module in which we could hook up different parts of our app. If we need to use a new service, this is where we hook it up. If we want to add a new state, this is where we add it. If we need to call a specific function every time the app starts, this is where we do it. Next we have the js/controllers.js file, in the default controller created by Ionic, all the controllers are added in a single file. This is fine for really small apps but for medium to large size apps it’s recommended to have a single controller for each entity in your app. For example, you might have a user controller where you put all the code that has something to do with the user. Things like updating user settings. The controller is where you usually put code that responds to a specific event such as clicking a button or pulling to refresh. Lastly, we have the js/services.js file. A service is responsible for adding a specific functionality to your app. You would want to create a service for making requests to your server, or storing data in local storage. It’s recommended that you search for existing solutions first before writing your own services. So you won’t waste time re-implementing the same thing.

1
2
3
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>

Then we have the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body ng-app="starter">
    <!--
      The nav bar that will be updated as we navigate between views.
    -->
    <ion-nav-bar class="bar-stable">
      <ion-nav-back-button>
      </ion-nav-back-button>
    </ion-nav-bar>
    <!--
      The views will be rendered in the <ion-nav-view> directive below
      Templates are in the /templates folder (but you could also
      have templates inline in this html file if you'd like).
    -->
    <ion-nav-view></ion-nav-view>
</body>

In a typical Angular app we set the ng-app attribute to the name of the module. Ionic has used starter as the name of the module by default. You can change that on your app.js file. Here the name of the module is starter.

1
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

You can change it to the following if you want. Here the name of the module is changed to my_awesome_app:

1
angular.module('my_awesome_app', ['ionic', 'my_awesome_app.controllers', 'my_awesome_app.services'])

If you did change the name of the module. You also need to change the value of the ng-app attribute:

1
<body ng-app="my_awesome_app">

As well as your controllers and services:

1
2
angular.module('my_awesome_app.controllers', [])
angular.module('my_awesome_app.services', [])

Going back to the app.js file. This is the code responsible for setting the name of the module and the services and controllers it depends on. By default it depends on the ionic service, and your custom controllers and services.

1
angular.module('my_awesome_app', ['ionic', 'my_awesome_app.controllers', 'my_awesome_app.services'])

You can think of my_awesome_app.controllers and my_awesome_app.services as a submodule of the my_awesome_app module. We declared those two modules in the js/controllers.js and js/services.js file.

1
2
angular.module('my_awesome_app.controllers', [])
angular.module('my_awesome_app.services', [])

You might be wondering what’s the need for these sub-modules? Well, their main purpose is to have a different parent module for each controller and service. So every controller would depend on the my_awesome_app.controllers module and all services would depend on the my_awesome_app.services module. We do this because simply depending on the main module wouldn’t work:

1
angular.module('my_awesome_app', [])

Next we have the run function. This is where Ionic executes functions which needs to be executed every time the app is opened. All function calls should be wrapped in the $ionicPlatform.ready event to make sure all the plugins and other features that we need are loaded. Inside the event, we check if the Cordova keyboard plugin is accessible. If it is then we hide the keyboard accessory bar. Finally we use the lightContent statusbar (light text for dark backgrounds) by calling the styleLightContent method provided by the StatusBar plugin.

1
2
3
4
5
6
7
8
9
10
11
12
13
.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleLightContent();
    }
  });
})

Next we set the app configuration by calling the config method in the Angular module. You can use this to set the routes of your app.

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
    .state('tab', {
    url: "/tab",
    abstract: true,
    templateUrl: "templates/tabs.html"
  })

  // Each tab has its own nav history stack:

  .state('tab.dash', {
    url: '/dash',
    views: {
      'tab-dash': {
        templateUrl: 'templates/tab-dash.html',
        controller: 'DashCtrl'
      }
    }
  })

  .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('tab.chat-detail', {
      url: '/chats/:chatId',
      views: {
        'tab-chats': {
          templateUrl: 'templates/chat-detail.html',
          controller: 'ChatDetailCtrl'
        }
      }
    })

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/dash');

});

Breaking it down, we use the $stateProvider to set different states. A state is equivalent to a route in your app. You can call the state method to create a new route, this accepts the name of the state as its first argument and the config as its second.

1
2
3
4
5
6
 // setup an abstract state for the tabs directive
    .state('tab', {
    url: "/tab",
    abstract: true,
    templateUrl: "templates/tabs.html"
})

A state can be abstract or not. You usually declare a state as an abstract one if it has a child state. In the above example the tab state is an abstract one. This means you don’t access it directly from your browser. Instead, you access its child states. In this case the child states are dash, chats, chat-detail and account.

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
30
31
32
33
34
35
36
37
  .state('tab.dash', {
    url: '/dash',
    views: {
      'tab-dash': {
        templateUrl: 'templates/tab-dash.html',
        controller: 'DashCtrl'
      }
    }
  })
 .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('tab.chat-detail', {
      url: '/chats/:chatId',
      views: {
        'tab-chats': {
          templateUrl: 'templates/chat-detail.html',
          controller: 'ChatDetailCtrl'
        }
      }
    })

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  });

An abstract state takes the following options:

  • url – the URL that you will use to access the state. For an abstract state, this would be the parent URL that each child state will use.
  • abstract – a boolean value that is set to true to specify that the state is an abstract one.
  • templateUrl – the path to where the template is located locally.

A child state would accept the same options, the only difference is that you have to set the views option and the add a single property with the name of the view. Then that property would have the templateUrl property and controller which is basically the name of the controller that the state uses. The controller property is optional, you can set this on the template if you want. But you have to note that you can’t specify the controller name on both the template and the app.js file. Otherwise methods that run every time the controller is executed is called twice. Here is a sample child state. As you can see the url is set to /chats but you would need to specify the URL of the abstract state first. So accessing it in the brower would be tab/chats.

1
2
3
4
5
6
7
  url: '/chats',
  views: {
    'tab-chats': {
      templateUrl: 'templates/tab-chats.html',
      controller: 'ChatsCtrl'
    }
  }

Next we specify the views with the view property. As I’ve said earlier, this accepts the name of the view as its property. This is tied with the name of the view in the ion-tabs directive. You can find it in the templates/tabs.html file. The view name property in the ion-nav-view directive should be the same as the name of view in your state declaration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--
Create tabs with an icon and label, using the tabs-positive style.
Each tab's child <ion-nav-view> directive will have its own
navigation history that also transitions its views in and out.
-->
<ion-tabs class="tabs-icon-top tabs-color-active-positive">

  <!-- Dashboard Tab -->
  <ion-tab title="Status" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tab/dash">
    <ion-nav-view name="tab-dash"></ion-nav-view>
  </ion-tab>

  <!-- Chats Tab -->
  <ion-tab title="Chats" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tab/chats">
    <ion-nav-view name="tab-chats"></ion-nav-view>
  </ion-tab>

  <!-- Account Tab -->
  <ion-tab title="Account" icon-off="ion-ios-gear-outline" icon-on="ion-ios-gear" href="#/tab/account">
    <ion-nav-view name="tab-account"></ion-nav-view>
  </ion-tab>


</ion-tabs>

Now open up the controllers.js file. On the first line we’re declaring a new module called my_awesome_app.controllers. If you remember from earlier, this is one of the modules that we specified as a dependency for the main module in the app.js file.

1
angular.module('my_awesome_app.controllers', [])

Then we create a new controller by using the controller method. This accepts the name of the controller as its first argument and the function to execute when the controller is accessed as its second. For the DashCtrl, we have an empty function body as we do not need to execute anything.

1
.controller('DashCtrl', function($scope) {})

For the ChatCtrl, we get a list of chat messages using the Chats services. We’ll go through that in a moment, but for now understand that to use a service you need to declare it as a parameter in the function body of the controller. This way you can access it from inside the function and call the different methods that are accessible from that service. Also notice that we have also declared a $scope variable as a parameter. This allows us to pass in data to the current scope. We do this so we can access the data in the view. Back to the Chats service, we are calling the all method in the Chats service. This returns an array of messages. We then assign whatever it returns to the chats property in the $scope. Note that you can name it anything you want. Next we’re also assigning a remove method to the $scope. What this does is remove a specific chat message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.controller('ChatsCtrl', function($scope, Chats) {
  // With the new view caching in Ionic, Controllers are only called
  // when they are recreated or on app start, instead of every page change.
  // To listen for when this page is active (for example, to refresh data),
  // listen for the $ionicView.enter event:
  //
  //$scope.$on('$ionicView.enter', function(e) {
  //});

  $scope.chats = Chats.all();
  $scope.remove = function(chat) {
    Chats.remove(chat);
  }
})

Here’s the view utilizing the ChatsCtrl. It’s in the templates/tab-chats.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ion-view view-title="Chats">
  <ion-content>
    <ion-list>
      <ion-item class="item-remove-animate item-avatar item-icon-right" ng-repeat="chat in chats" type="item-text-wrap" href="#/tab/chats/">
        <img ng-src="">
        <h2></h2>
        <p></p>
        <i class="icon ion-chevron-right icon-accessory"></i>

        <ion-option-button class="button-assertive" ng-click="remove(chat)">
          Delete
        </ion-option-button>
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

The ChatDetailCtrl is the controller responsible for showing the details of a specific chat message. Here we’re using a new parameter in the function body called $stateParams. This allows us to get the value of a specific route parameter. Route parameters are passed in the URL of the app. If you go back to the app.js file, you can see from the tab.chat-detail state’s URL is /chats/:chatId. The :chatId here is the route parameter. Every route parameter in Angular always starts in a colon followed by the name. So in the ChatDetailCtrl we are merely getting the value passed in this route parameter and then using it as an argument for the get method in the Chats service. This method basically fetches a specific chat message from the array of chats. We then just assign the value to the chat variable in the $scope.

1
2
3
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
  $scope.chat = Chats.get($stateParams.chatId);
})

You can see this being used in the templates/chat-detail.html.

1
2
3
4
5
6
7
8
<ion-view view-title="">
  <ion-content class="padding">
    <img ng-src="" style="width: 64px; height: 64px">
    <p>
      
    </p>
  </ion-content>
</ion-view>

Finally we have the AccountCtrl. Nothing fancy here. All we’re doing is passing in an object to the scope.

1
2
3
4
5
.controller('AccountCtrl', function($scope) {
  $scope.settings = {
    enableFriends: true
  };
});

We can see this being used from the view in templates/tab-account.html:

1
2
3
4
5
6
7
8
9
<ion-view view-title="Account">
  <ion-content>
    <ion-list>
    <ion-toggle  ng-model="settings.enableFriends">
        Enable Friends
    </ion-toggle>
    </ion-list>
  </ion-content>
</ion-view>

From the above HTML, the enableFriends property is used as the model for the ion-toggle directive which basically just outputs a switch UI. In this case the switch should be turned on since the value of the enableFriends property is true.

Now we take a look at the service file at js/services.js. Same with the controllers, we declare a new module called my_awesome_app.services. From there we call the factory method in order to create a service. We call this service Chats. Inside the function body, we have an array of objects containing the details for each chat message. After that, we expose the methods that we want the controllers that will use this service to use by returning them. Here we have 3 methods, the all method which just returns all the chat messages. The remove method which removes a specific chat message from the array of chat messages. And last is the get method, which returns a specific chat message based on the id.

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
angular.module('my_awesome_app.services', [])

.factory('Chats', function() {
  // Might use a resource here that returns a JSON array

  // Some fake testing data
  var chats = [{
    id: 0,
    name: 'Ben Sparrow',
    lastText: 'You on your way?',
    face: 'https://pbs.twimg.com/profile_images/514549811765211136/9SgAuHeY.png'
  }, {
    id: 1,
    name: 'Max Lynx',
    lastText: 'Hey, it\'s me',
    face: 'https://avatars3.githubusercontent.com/u/11214?v=3&s=460'
  },{
    id: 2,
    name: 'Adam Bradleyson',
    lastText: 'I should buy a boat',
    face: 'https://pbs.twimg.com/profile_images/479090794058379264/84TKj_qa.jpeg'
  }, {
    id: 3,
    name: 'Perry Governor',
    lastText: 'Look at my mukluks!',
    face: 'https://pbs.twimg.com/profile_images/598205061232103424/3j5HUXMY.png'
  }, {
    id: 4,
    name: 'Mike Harrington',
    lastText: 'This is wicked good ice cream.',
    face: 'https://pbs.twimg.com/profile_images/578237281384841216/R3ae1n61.png'
  }];

  return {
    all: function() {
      return chats;
    },
    remove: function(chat) {
      chats.splice(chats.indexOf(chat), 1);
    },
    get: function(chatId) {
      for (var i = 0; i < chats.length; i++) {
        if (chats[i].id === parseInt(chatId)) {
          return chats[i];
        }
      }
      return null;
    }
  };
});

Plugins

Plugins allows you to add native functionalities to your app. Things like the camera, calendar, contacts, or flashlight can be controlled using JavaScript through the use of plugins.

You can install plugins by using the ionic plugin add command. Here’s an example of how we might add the camera plugin:

1
ionic plugin add cordova-plugin-camera

If you decide later on that you no longer need a plugin, you can use the ionic plugin rm command:

1
ionic plugin rm cordova-plugin-camera

Every plugin already has the necessary instructions which will setup everything that is needed in order for it to work when installed. Things like putting the necessary permissions in the AndroidManifest.xml file so that you can use specific features of the device.

I won’t dive in much into plugins, what’s important is that you know they are available and you can use Google to look for them. There’s the Cordova Plugin Repository and Github if you want to look for a plugin that can solve your specific problem.

Changing the App Icon and Splash Screens

To change the icon of the app, simply put an icon.png, icon.psd, or icon.ai on the resources directory in the root of your app. For the splash it’s splash.png, splash.psd, or splash.ai. The recommended icon size is 500x500 and the splash image is 1200x1200. Once you’ve added the files, execute ionic resources from the terminal to generate your icons and splash screens.

Compiling to Android

You can create an apk file using the ionic build android command. This will create the android-debug.apk file under the platforms/android/build/outputs/apk directory. Note that this is the debug version of the app. You can use this for testing on your mobile device. But you cannot submit it to the Google Play Store. To do that you’ll have to build a release version for your apk by adding the --release option when using the cordova build. Note that we’re using cordova instead of ionic. Ionic simply wraps the Cordova commands so you can use them interchangeably.

1
cordova build --release android

Next, generate a keystore for the app by using keytool. Breaking down the command below, we’re setting the following options:

  • genkey – not actually an option, but a command to generate the key.
  • keystore – the file name you want to give to the keystore
  • alias – the alias of the key.
  • keyalg – the algorithm to be used to generate the key.
  • keysize – the size of the key in bytes.
  • validity – the number of days in which this keystore will be valid.
1
keytool -genkey -v -keystore demoApp.keystore -alias demoApp -keyalg RSA -keysize 2048 -validity 10000

Executing the command above will ask you for the keystore password and some questions. Just provide an answer to each question since the information that you supply will be used to generate the keystore. Here’s how it looks like in my machine:

keytool

If you cannot use keytool, then maybe you don’t have Java installed yet. You can install it by executing the following commands in order.

1
2
3
4
5
6
7
sudo apt-get install default-jre

sudo apt-get install default-jdk

sudo apt-get install openjdk-7-jre

sudo apt-get install openjdk-7-jdk

Now we’re ready to sign the apk file with the keystore that we generated. To do that, first copy the demoApp.keystore to the platforms/android/build/outputs/apk directory, open a terminal on that directory then execute the following command:

1
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore demoApp.keystore android-release-unsigned.apk demoApp

This will ask you for the password that you entered earlier when you created the keystore.

Finally, to generate the apk that you can submit in the Google Play Store, use zipalign. This accepts the name of the unsigned apk file and the name of the signed apk which it will generate.

1
zipalign -v 4 android-release-unsigned.apk demoApp.apk

If you need the key you can execute the following:

1
keytool -exportcert -alias demoApp -keystore demoApp.keystore | openssl sha1 -binary | openssl base64

Conclusion

That’s it! In this tutorial you’ve learned the basics of working with the Ionic framework. We have only scratched the surface in this tutorial, be sure to check out the resources below to learn more.

Resources

Comments