Smartphone lying on a wood surface

Now for the third and final part of this three part tutorial: How to build an app. If you missed out on the first two instalments, you can read part one here, and part two here. For our third part, I will explain how to build the app using the Ionic framework.

How to build an app ionic

Ionic is a cross platform web framework that allows you to package and deploy apps for iOS and Android. It is based on Angular.

Let’s jump right into it.

Installing Ionic Framework

First, we will install the Ionic framework. The easiest way to install it is to use Node Package Manager (NPM) that comes with Node.js.

Go to https://nodejs.org and click on v4.4.2 LTS link to download the installer.

NodeJS Download for Windows (x64)

Double click the downloaded file to launch the installer.

NodeJS MSI Installer

On the Welcome to the Node.JS Setup Wizard screen, click Next.

Welcome to Node.js setup wizard

Thoroughly read, study, research and understand the license agreement, and (if you agree) check I accept the terms in the License Agreement and then click Next.

Node.js end-user license agreement

On the Destination Folder screen, leave it default and click Next.

Node.js installation destination folder

On the Custom Setup screen, leave everything default and click Next.

Node.js custom setup

Finally, on the Ready to install Node.js screen, click Install.

Ready to install Node.js

The Installation will begin.

If the User Account Control screen pops up, click Yes.

Node.js installation UAC

On the Completed the Node.js Setup Wizard screen, click Finish.

Completed Node.js Setup Wizard

Node.js is now installed. Excellent.

Start our Back-end REST API

It’s been a few weeks since post 2/3 was published, in which we created our back-end server using the Django REST Framework. If you are following straight on from the last post then the server is already running and you should know your IP Address. If it’s not running, then follow the below steps to start it.

Open your favourite command line tool and cd to the location of your vagrant box (in our case it’s c:\workspace\devenv), and run vagrant up to boot our Vagrant box:

cd c:\workspace\devenv
vagrant up
Cmder Vagrant Up Cmder

It may take a few minutes to load. Once it’s loaded, SSH to it:

vagrant ssh

Now get the IP address of your servers eth1 network and write it down:

ifconfig
Ifconfig output for eth1

Note: My network and IP address has changed from my last post. It’s because I’m writing this one from a Megabus between Houston and New Orleans :).

Switch to the virtual environment for our app:

workon env

Now let’s change to the directory that contains our back-end code and start the Django server:

cd /vagrant/project/miab_backend
python manage.py runserver 0.0.0.0:8000
Python runserver shell

Create Our Ionic App

First, let’s install Ionic using the Node Package Manager (npm). Do this by opening up Command Prompt (or your favourite equivalent) and run:

npm install -g ionic

Next, lets go to our Workspace directory, create a new project and then launch that project in the browser simulator:

cd c:\workspace\
ionic start miabApp blank
cd miabApp
ionic serve

The blank ionic app should automatically launch into your web browser (this tutorial assumes you are using Google Chrome as your default browser. If you are not, I would recommend installing it now to get the most out of this guide):

Ionic Starter App

In the Chrome window, press F12 to load the Developer Tools. Then click on Toggle Device Mode to switch to a mobile simulator:

Google Chrome Developer Tools Device Toggle Mode

Note: sometimes the Developer Tools opened up in-line within Google Chrome. You can make it pop out as a separate window by clicking the three vertically stacked dots on the top right, and changing the Dock side.

Once Chrome switches to Device Mode, you will see a drop-down box that allows you to switch between devices. This guide will work with any device. For this demo we will use iPhone 6.

Google Chrome Developer Tools iPhone 6

Now go to Windows Explorer and open the miabApp folder in Atom.io (or your favourite alternative code editor).

Open miabApp

Now it’s time to add some code to our app. Let’s start by adding the proxy which will point to our API. The Ionic proxy is a way to work around any CRSF errors which may occur (learn more here). Edit the ionic.project file and make it look like this:

{
    "name": "miabApp",
    "app_id": "",
    "proxies": [
        {
            "path": "/api",
            "proxyUrl": "http://192.168.43.243:8000/api"
        }
    ]
}

Note: Replace with the IP address for your back-end server that we started in the last step.

Next, modify the js/app.js file to look like this (comments in-line explain what is going on):

// Define our app and include the following:
// - ionic - the framework.
// - ui.router - angular JS UI router for URLs.
// - miabApp.controllers - our custom controllers for adding functionality to our screens.
// - miabApp.services - our custom services for accessing the REST API.
app = angular.module('miabApp', [
    'ionic',
    'ui.router',
    'miabApp.controllers',
    'miabApp.services',
]);

app.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
      // for form inputs)
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);

      // Don't remove this line unless you know what you are doing. It stops the viewport
      // from snapping when text inputs are focused. Ionic handles this internally for
      // a much nicer keyboard experience.
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
});

app.config(function($stateProvider, $urlRouterProvider) {

    // Default to the home state.
    $urlRouterProvider.otherwise('/');

    // Assign the home state to '/' for displaying the enter message screen.
    $stateProvider.state('home', {
        url: '/',
        templateUrl: 'templates/enter_message.html',
        controller: 'EnterMsgCtrl',
        cache: false
    });

    // Assign the message state to '/message' for displaying a message.
    $stateProvider.state('message', {
        url: '/message',
        templateUrl: 'templates/view_message.html',
        controller: 'ViewMsgCtrl'
    });

});

Next, create a new file at js/controller.js. Then fill it with the following code:

// Define our app module.
var app = angular.module('miabApp.controllers', []);

// Define our 'EnterMsgCtrl' controller and pass it the app $scope, $state and our
// WebService service.
app.controller('EnterMsgCtrl', function($scope, $state, WebService) {

    // By default there is no error.
    $scope.isError = false;

    // Define a function for sending a message using the WebService.
    $scope.sendMessage = function(msg) {
        // Check the input is valid, if not then return null.
        if ((msg === undefined) || (msg === null) || (msg === '')) {
            return
        }

        // Use the WebService to trade a message, and when the response is
        // called, call our handleSuccessResponse() function. If an error
        // happens, then call handlErrorResponse()
        WebService.tradeMessage(msg, handleSuccessResponse, handleErrorResponse);
    };

    // This is our function for handling a successful web service call.
    function handleSuccessResponse(response) {
        // Set the message in localStorage.
        window.localStorage.setItem("message", response.data.message);
        // Move onto the message screen.
        $state.go('message');
    };

    // This is our function for handling a failed web service call.
    function handleErrorResponse(response) {
        // Set the scopes isError variable to true.
        $scope.isError = true;
        // Set the scropes error message. NOTE: Ideally we should set the error
        // message based on the response. In the interest of simplicity for
        // this article I will just set it to display the hard coded message
        // below.
        $scope.error = 'An error occured.';
    };

});

// This is our 'ViewMsgController' for displaying a message.
app.controller('ViewMsgCtrl', function($scope) {
    // The message is set in localStorage, so all we need to do is set it.
    $scope.message = window.localStorage.getItem('message');
});

Now, create a file at js/services.js and add the following code:

// Get our app module.
var app = angular.module('miabApp.services', []);

// Create our WebService service.
app.service('WebService', function($http) {

    // This is the base URL for our REST API. Since we will be using the
    // ionic proxy, we can exclude the FQDN and port number.
    var WS_BASE_URL = '/api';

    // All 'public' functions need to be inside a return statement.
    return {

        // This is our function for trading a message.
        tradeMessage: function(message, onSuccess, onError) {
            // Create our payload variable called 'data'.
            var data = {'message': message};
            // Use $http to post to our /message endpoint.
            $http.post(WS_BASE_URL + '/message/', data).then(
                // Call the onSuccess function if it's successful.
                onSuccess,
                // Call the onError function if it fails.
                onError
            );
        }
    }

});

Now that most of the code is done, let’s pull it all together and make it look more presentable. Let’s start by adding the bottle.jpg file inside the img directory.

Add bottle Atom

The index.html file is the main template file that is loaded. This file defines the basic layout of our app, and has a space called the ion-nav-view which will load the relevant template for the URLs defined in our app.js file (earlier).

Update the file to look like this:

<!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>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <!-- Point to our CSS style file -->
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <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>

    <!-- These are the 'includes' that make up our app. -->
    <script src="js/app.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/services.js"></script>

  </head>
  <!-- Our app is called 'miabApp' -->
  <body ng-app="miabApp">
      <!-- Create a ion-nav-bar -->
      <ion-nav-bar class="bar-stable">
          <!-- Include a back button (Ionic takes care of showing the button at the correct times) -->
          <ion-nav-back-button></ion-nav-back-button>
      </ion-nav-bar>
      <!-- The 'ion-nav-view' will load the necessary template based on the URL. -->
      <!-- The template are defined in our app.js file. -->
      <ion-nav-view></ion-nav-view>
  </body>
</html>

Create a directory at www/templates to hold our template files.

Template directory

Create a new file in the templates directory called enter_message.html which will contain our message entry page. Populate it with the following code:

<!-- This is our 'ion-view' which is loaded into the  'ion-nav-view' inside our index.html file. -->
<ion-view view-title="Message In a Bottle" class="view">
    <ion-content>
        <div class="list list-inset message-form">
            <!-- This 'p' tag will show any errors that occur. -->
            <p ng-show="isError" class="form-error">{{ error }}</p>
            <label class="item item-input">
                <!-- This will be our text input box for entering a message. -->
                <textarea ng-model="message" type="text" placeholder="Enter a message" maxlength="120" rows="4"></textarea>
            </label>
            <!-- This is our button for sending a message. -->
            <button ng-click="sendMessage(message);" class="button button-block button-positive">
                <i class="icon ion-email"></i>
            </button>
        </div>
    </ion-content>
</ion-view>

Now create a new file in our templates directory called view_message.html which will contain our message viewing page. Populate it with the following code:

<!-- This is our 'ion-view' which is loaded into the  'ion-nav-view' inside our index.html file. -->
<ion-view view-title="Message In a Bottle" class="view">
    <ion-content>
        <div class="card">
            <div class="item item-text-wrap">
                <!-- This is the variable that will hold our message -->
                {{ message }}
            </div>
        </div>
    </ion-content>
</ion-view>

Now let’s add a bit of style to our project. Edit the style.css file (inside the www/css directory) and fill it with the following:

/* Add our background image to our view background */
.view {
    background-image: url('../img/bottle.jpg');
    background-size: cover;
    background-repeat: no-repeat;
}

/* Back the background of our views and lists white. */
.view .list-inset {
    background-color: rgba(255, 255, 255, 0);
}

/* Center the content. */
.view .scroll-content {
  display: table !important;
  width: 100% !important;
  height: 100% !important;
  margin-top: -60px;
}

/* Center the content. */
.view .scroll {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
 /* Style the errors, nice and red. */
.form-error {
    color: #a94442;
    font-weight: bold;
    background-color: #f2dede;
    padding: 10px;
    border: 1px solid #ebccd1;
}

Testing the App

Finally let’s test our app. It should refresh automatically in the browser each time you make a change, but just to be sure, switch to the browser and press F5 to refresh the page, and then type a message and click the send button:

Message In a Bottle

You should be presented with a random message. Ta-da! Your app works!

App working screenshot

Now that concludes our How to Build an App blog series. You can find the final code for the app here: https://github.com/LondonAppDev/miabApp

I hope you have found it useful. If you run into any issues or have any ideas on how I can improve on these posts, please leave a comment below!

Cheers,
Mark

1 reply
  1. ed moehlenpah
    ed moehlenpah says:

    I had some trouble following this last part, perhaps because being required to use a newer version of node.js

    in any case
    more ionic.config.json
    {
    “name”: “mibApp”,
    “app_id”: “”,
    “proxies”: [
    {
    “path”: “/api”,
    “proxyUrl”: “http://192.168.35.212:8000/api”
    }
    ]
    }

    instead of the ionic.project file

    But, was able to get it work. Thanks for these posts!

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *