Ionic Framework : Android Mobile Application using AngularJS

Android Mobile Application using AngularJS Ionic Framework

In this tutorial, I will show you how to create a simple notepad android application using framework – Ionic.
Ionic is the most simple and robust way of creating hybrid mobile applications nowadays. It offers the best components for developing native mobile applications.

Before we begin, you need to setup the environment and install the ionic framework on your machine. You can follow the steps as described Here.

After setting up environment, you need to install all the required plugins and platform like SQLite and Android platform. After that create a new project with the name “Textr” which I will be describing here in this tutorial.

Let’s have a look on directory structure of the project :


 

Now let’s start with the code step by step.

First I will start with the AngularJS’s important part which is “app.js”. Inside app.js, we define our application module and inject required modules like ‘ngCordova’ and ‘ionic’ as below :
var app = angular.module('myApp', ['ngCordova', 'ionic']);
After app.js, I created a new file which is app-config.js. Inside App-config, we have defined state, html templates being used by these states and corresponding controllers.

We have fours states defined here :

index : which is the home screen of the application.
viewNotePage : view note screen.
editNotePage : edit note screen.
createNotePage : for creating a new note.

as below :
app.config(function($stateProvider, $urlRouterProvider) {
	$stateProvider
	.state('index', {
		url: '/',
		cache: false,
		templateUrl: 'view/home.html',
		controller: 'HomeCtrl'
	})

	.state('viewNotePage', {
		url: '/viewNote/:id',
		templateUrl: 'view/viewnote.html',
		controller: 'ViewNoteCtrl'
	})

	.state('editNotePage', {
		url: '/editNote/:id',
		templateUrl: 'view/editnote.html',
		controller: 'EditNoteCtrl'
	})

	.state('createNotePage', {
		url: '/createNote',
		templateUrl: 'view/addnote.html'
	});
	$urlRouterProvider.otherwise('/');
});
Now we need some storage in order to store the notes created by application. For that purpose we are going to use $cordovaSQLite plugin which is using SQLite database for storage. I created app-db file for database related configuration as below :
var db = null;

app.run(function($ionicPlatform, $cordovaSQLite, $window) {
        $ionicPlatform.ready(function() {

            db = $cordovaSQLite.openDB({name : "textrnote.db", key: 'textrdatabase', location: 1});
            $cordovaSQLite.execute(db, "CREATE TABLE IF NOT EXISTS notes (id integer primary key AUTOINCREMENT, title text, description text, date_created DATETIME DEFAULT CURRENT_TIMESTAMP)");

        	if (window.cordova && window.cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
            }
            if (window.StatusBar) {
                StatusBar.styleDefault();
            }
        });
});
After database and application configuration, now we need to define our service for notepad. For that purpose I have created a separate service file app-service.js as below :
app.factory('NotesFactory', function($ionicPlatform,$cordovaSQLite,$q,$window) {

	var obj = {};

	obj.listAllNotes = function() {
			var query = "select id,title,description,date_created from notes order by date_created desc";
			var q = $q.defer();
			$cordovaSQLite.execute(db,query).then(function(res) {
				if(res.rows.length > 0) {
					var data = res.rows;
					q.resolve(res.rows);
				    return data;
				} else {
					q.reject("No results found");
		            return false;
				}
			}, function(err) {
				q.reject(err);
				return false;
			});
			return q.promise;
	};

	obj.searchNotes = function(sinput) {
		var query = "select id,title,description,date_created from notes where title like '%"+sinput+"%' order by date_created desc";
		var q = $q.defer();
		$cordovaSQLite.execute(db,query).then(function(res) {
			if(res.rows.length > 0) {
				var data = res.rows;
				q.resolve(res.rows);
			    return data;
			} else {
				q.reject("No results found");
	            return false;
			}
		}, function(err) {
			q.reject(err);
			return false;
		});
		return q.promise;
    };

    obj.getNoteOnId = function(noteId) {
		var query = "select id,title,description,date_created from notes where id = " + noteId;
		var q = $q.defer();
		$cordovaSQLite.execute(db,query).then(function(res) {
			if(res.rows.length > 0) {
				var data = res.rows.item(0);
				q.resolve(res.rows.item(0));
			    return data;
			} else {
				q.reject("No results found");
	            return false;
			}
		}, function(err) {
			q.reject(err);
			return false;
		});
		return q.promise;
    };

	obj.insertNote = function(title, description) {
			var query = "insert into notes(title, description) values(?,?)";
			var q = $q.defer();
		    $cordovaSQLite.execute(db,query,[title,description]).then(function(res) {
		    	var data = res.insertId;
		    	q.resolve(res.insertId);
		    	return data;
			}, function(err) {
				 q.reject("No results found");
				return false;
			});
		    return q.promise;
	};

	obj.updateNote = function(note) {
		var query = "update notes set title = ?, description = ? where id = ?";
		var q = $q.defer();
	    $cordovaSQLite.execute(db,query,[note.title,note.description,note.id]).then(function(res) {
	    	var data = res.insertId;
	    	q.resolve(res.insertId);
	    	return data;
		}, function(err) {
			 q.reject("No results found");
			return false;
		});
	    return q.promise;
    };

    obj.deleteNote = function(noteId) {
		var query = "delete from notes where id = ?";
		var q = $q.defer();
	    $cordovaSQLite.execute(db,query,[noteId]).then(function(res) {
	    	var data = res.insertId;
	    	q.resolve(res.insertId);
	    	return data;
		}, function(err) {
			 q.reject("No results found");
			return false;
		});
	    return q.promise;
    };

	return obj;
});
Now when we have our service ready to serve, it is time for the controller to come into the picture. Our controller will use this service with the states and perform the related actions. Our controller app-controller.js is as below :
app.controller('HomeCtrl', function($scope,$cordovaSQLite,$rootScope,$state,$window,$timeout,NotesFactory) {
	 $scope.shouldShowDelete = false;
	 $scope.shouldShowReorder = false;
	 $scope.listCanSwipe = true;

	 $scope.searchData = {};

	 $scope.noteList = [];

	 $scope.$on('$ionicView.beforeEnter', function(){
		 $timeout(function() {
			 $scope.loadNotes();
		 },500);
	 });

	 $scope.searchNotes = function() {
		 $scope.noteList = [];

		 NotesFactory.searchNotes($scope.searchData.searchInput).then(function(res) {
			 for(var i=0; i<res.length; i++) {
				 $scope.noteList.push({id : res.item(i).id, title : res.item(i).title, description : res.item(i).description});
			 }
		 }, function(err) {
			 console.log(err);
		 });
	 }

	 /* Page Action Controller Functions */
	 $scope.openCreateNote = function() {
		 $state.go("createNotePage");
	 }

	 /* Load and Search Notes */
	 $scope.loadNotes = function() {
		 $scope.noteList = [];
		 NotesFactory.listAllNotes().then(function(res) {
			 for(var i=0; i<res.length; i++) {
				 $scope.noteList.push({id : res.item(i).id, title : res.item(i).title, description : res.item(i).description});
			 }
		 }, function(err) {
			 console.log(err);
		 });
	 }	 

	 $scope.viewNote = function(id) {
		 $state.go('viewNotePage', {id : id});
	 }
});

app.controller('ViewNoteCtrl', function($scope,$state,$stateParams,$window,$timeout,NotesFactory) {	

	$scope.note = null;

	$scope.$on('$ionicView.afterEnter', function(){
		 $timeout(function() {
			 $scope.getNoteOnId();
		 },5);
	 });

	$scope.getNoteOnId = function() {
		NotesFactory.getNoteOnId($stateParams.id).then(function(res) {
			$scope.note = res;
		});
	}

	$scope.deleteNote = function() {
		NotesFactory.deleteNote($stateParams.id).then(function(res) {
			$window.alert("Note Deleted.");
			$state.go('index');
		}, function(err) {
			$window.alert("Problem");
		});
	}

	$scope.editNote = function() {
		$state.go('editNotePage', {id : $scope.note.id});
	}

	$scope.cancelAction = function() {
		 $state.go("index");
	}
});

app.controller('EditNoteCtrl', function($scope,$state,$stateParams,$window,$timeout,NotesFactory) {	

    $scope.note = null;

	$scope.$on('$ionicView.afterEnter', function(){
		 $timeout(function() {
			 $scope.getNoteOnId();
		 },5);
	 });

	$scope.getNoteOnId = function() {
		NotesFactory.getNoteOnId($stateParams.id).then(function(res) {
			$scope.note = res;
		});
	}

	$scope.updateNote = function() {
		NotesFactory.updateNote($scope.note).then(function(res) {
			$window.alert("Updated.");
			$state.go('index');
		}, function(err) {
			$window.alert("Problem");
		});
	}

	$scope.cancelAction = function() {
		 $state.go("index");
	}

});

app.controller('AddNoteCtrl', function($scope,$state,$window,NotesFactory) {
	$scope.noteData = {};

	$scope.addNote = function() {
		if($scope.noteData.title) {
			NotesFactory.insertNote($scope.noteData.title, $scope.noteData.description).then(function(res) {
				$window.alert("Note Saved.");
				$state.go('index');
			}, function(err) {
				$window.alert("Note has not been created. Try again.");
			});
		} else {
			$window.alert("Please provide title for note.");
		}
	}

	 $scope.cancelAction = function() {
		 $state.go("index");
	 }
});
Now we have defined our application modules, created separate service and controller and application database configuration. Our back end work has been completed. Now it is time for the view to play it’s role.

For the view purpose, we have one main index.html. Since, it is single page application so index.html will be our main entry for the view. States will include their views later when application will run. index.html
<!DOCTYPE html>
<html ng-app="myApp">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    			<link rel="manifest" href="manifest.json">

    <!-- un-comment this code to enable service worker
    <script>
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('service-worker.js')
          .then(() => console.log('service worker installed'))
          .catch(err => console.log('Error', err));
      }
    </script>-->

    			<link href="lib/ionic/css/ionic.css" rel="stylesheet">
    			<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="lib/ionic/js/ngCordova/ng-cordova.min.js"></script>
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
    <script src="js/config/app-config.js"></script>

    <!-- Database config -->
    <script src="js/config/app-db-config.js"></script>

    <!-- Application Service -->
    <script src="js/service/app-service.js"></script>

    <!-- Application Controller -->
    <script src="js/controller/app-controller.js"></script>

  </head>
  <body class="platform-android platform-cordova platform-webview">
<div>
    	<ion-nav-view animation="slide-left-right"></ion-nav-view></div>
</body>
</html>

Now I have created separate views for different purpose like view, add and delete notes as described below : home.html
<ion-view>
	<ion-header-bar class="bar-assertive">
<h1 class="title">Textr</h1>
<div class="buttons">
		    <button class="button" ng-click="loadNotes()"><i class = "icon icon ion-refresh"></i></button>
			<button class="button" ng-click="openCreateNote()"><i class = "icon icon ion-compose"></i></button></div>
</ion-header-bar>
    <ion-content has-header="true" padding="false" style="background-color:#dedede;">
<div class="list" style="margin: 0px">
  			<label class="item item-input">
    			<i class="icon ion-search placeholder-icon"></i>
    			<input type="text" ng-model="searchData.searchInput" ng-keyup="searchNotes()" placeholder="Search">
  			</label></div>
<ion-list           show-delete="shouldShowDelete"           show-reorder="shouldShowReorder"           can-swipe="listCanSwipe" padding="false">

  			<ion-item ng-repeat="item in noteList" style="border:none; padding: 0px; margin: 0px" item="item" ng-click="viewNote(item.id)">
<div class="list-cont">
<div class="list-item-left">
<h1 class="subheader">{{item.title}}</h1>
</div>
<div class="list-item-right">
            			<i class = "icon icon ion-chevron-right"></i></div>
</div>
</ion-item>
		</ion-list>

    </ion-content>
</ion-view>
viewnote.html
<ion-view>
	<ion-header-bar class="bar-assertive">
<div class="buttons">
	    	<button class="button" ng-click="cancelAction()">Back</button></div>
<h1 class="title">Read Note</h1>
<div class="buttons">
  			<button class="button" ng-click="editNote()"><i class = "icon icon ion-edit"></i></button>
        	<button class="button" ng-click="deleteNote()"><i class = "icon icon ion-trash-a"></i></button></div>
</ion-header-bar>
	<ion-content has-header="true" padding="false">
<h3>{{note.title}}</h3>
<h4>{{note.description}}</h4>
</ion-content>
</ion-view>
editnote.html
<ion-view>
	<ion-header-bar class="bar-assertive">
<div class="buttons">
	    	<button class="button" ng-click="cancelAction()">Cancel</button></div>
<h1 class="title">Edit Note</h1>
<div class="buttons">
  			<button class="button" ng-click="updateNote()">Save</button></div>
</ion-header-bar>
	<ion-content has-header="true" padding="false">
<div class="list">
            	<label class="item item-input item-stacked-label">
    				<span class="input-label">Title</span>
    				<input type="text" ng-model="note.title" placeholder="title">
  				</label>

  				<label class="item item-input item-stacked-label">
    				<span class="input-label">Note</span>
    				<textarea ng-model="note.description" placeholder="notes" rows="4"></textarea>
  				</label></div>
</ion-content>
</ion-view>
addnote.html
<ion-view ng-controller="AddNoteCtrl">
	<ion-header-bar align-title="left" class="bar-assertive">
<div class="buttons">
	    	<button class="button" ng-click="cancelAction()">Cancel</button></div>
<h1 class="title">Create Note</h1>
<div class="buttons">
  			<button class="button" ng-click="addNote()"><i class = "icon icon ion-checkmark"></i></button></div>
</ion-header-bar>
	<ion-content has-header="true" padding="false">
<div class="list">
            	<label class="item item-input item-stacked-label">
    				<span class="input-label">Title</span>
    				<input type="text" ng-model="noteData.title" placeholder="title">
  				</label>

  				<label class="item item-input item-stacked-label">
    				<span class="input-label">Note</span>
    				<textarea ng-model="noteData.description" placeholder="notes" rows="4"></textarea>
  				</label></div>
</ion-content>
</ion-view>
And the final part is to include css for the application which is style.css
/* Empty. Add your own CSS if you like */
ion-buttons {
order: 1
}

h2,h4,h3 {
	padding: 5px;
	text-align:justify;
}

.white {
	background-color:#fff;
}

.icon-padding {
	padding-left:5px;
}

.list-cont {
	padding: 0px; margin: 0px;
	width: 100%;
}

.subheader { color: #1e1e1e; font-family: 'Source Sans Pro', sans-serif; font-size: 23px; font-weight: 300 }

.list-item-left {
	width: 85%;
	float: left;

	padding: 10px;
	font-family: helvetica;
	border-bottom: 1px solid #dedede;
	background-color:#fff;

}

.list-item-right {
    background-color:#fff;
    border-bottom: 1px solid #dedede;
    border-left: 1px solid #dedede;
	width: 15%;
	float: right;
	font-size: 27px;
	text-align:center;
	padding: 10px;
}

.div {
  margin: 10px;
}

ul {
  list-style-type: none;
  width: 100%;
}

h3 {
  font: bold 25px Helvetica, Verdana, sans-serif;
}

li .left-dt {
  float: left;
  margin: 0 10px 0 0;
}

li p {
  font: 200 12px Georgia, Times New Roman, serif;
}

li {
  padding: 10px;
  overflow: auto;
}

li:hover {
  background: #eee;
  cursor: pointer;
}

.hp-daily__tz-list {
    width: 100%;
    padding: 0;
    margin: 0;
    counter-reset: ind-counter 0;
    list-style: none;
}

.hp-daily__tz {
    border-bottom: 0;
}

.hp-daily__tz {
    position: relative;
    counter-increment: ind-counter 1;
    border-bottom: 1px solid #000;
}

.hp-daily__tz__title {
    font-family: "NeueHaas",sans-serif;
    font-size: 18px;
    font-weight: 700;
    transition: .1s;
    margin-bottom: 7px;
}

.hp-daily__tz__subtitle {
    font-family: "NeueHaas",sans-serif;
    font-size: 16px;
    font-weight: 300;
    line-height: 1.45;
    margin-bottom: 10px;
}
That’s it, now android application is ready to run 🙂

Related Post

Leave a Reply

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