Building A Hybrid Mobile App With Parse and PhoneGap

In this tutorial, I will show you how to build a hybrid mobile app with Parse and Phonegap.

What is Parse?

Parse is a cloud app platform that enables users to add a scalable and powerful backend to launch a full-featured app.

Reference: https://www.parse.com/

What is Phonegap?

PhoneGap is a free and open source framework that allows you to create mobile apps using standardized web APIs for the platforms you care about.

Reference: http://en.wikipedia.org/wiki/PhoneGap

Download and install Eclipse Juno SR2 and Xcode 6.3.1 (if you using Mac for mobile development).

Eclipse Juno SR2 – http://www.eclipse.org/downloads/packages/release/juno/sr2
Xcode 6.3.1 – https://developer.apple.com/xcode/downloads/

Setup ADT and Android SDK into your eclipse. You can refer here how to setup, http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/. Then you need to setup cordova using NPM (node package manager) from that link.

Download Jquery and Ratchet from their official website. You should unzip it to proper location. For this tutorial, we using Jquery 1.11.3 and Ratchet 2.0.2.

Sign up for your new account here, https://www.parse.com/.

Parse

Parse

Click Create a New App.

Create a New App

Create a New App

Go to Keys and save your Application ID and Client Key.

Setting up your development environment

Create a cordova project using command below in your terminal/cmd:

cordova create com.revivalx.todolist.parse
cordova create project

cordova create project

Open config.xml inside com.revivalx.todolist.parse folder and replace with this code.

<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>ToDo</name>
    <description>
        This source code provides example for todolist app using parse.
    </description>
    <author email="mohammadnrdn@gmail.com" href="http://revivalx.com">
        Mohammad Nurdin bin Norazan
    </author>
    <content src="index.html" />
    <access origin="*" />
</widget>

Add platform for iOS and android.

cordova platform add ios
cordova platform add android
cordova platform add ios

cordova platform add ios

cordova platform add android

cordova platform add android

Create a new project inside your eclipse.

create a new eclipse project

create a new eclipse project

Select General > Project.

new eclipse project

new eclipse project

Enter following details and click Finish.

Project name: com.revivalx.todolist.parse .

Location: your project location.

new eclipse project

new eclipse project

Overview of Cordova directory structures

Here is the Cordova directory structure:

cordova structure

cordova structure

hooks – This directory may contains scripts used to customize cordova commands.

platforms (android and iOS) – Platforms added to your application will have the native application project structures laid out within this directory.

plugins – Any added plugins will be extracted or copied into this directory.

www (css) – The main application CSS directory.

www (img) – The main application image directory.

www (js) – The main application javascript directory.

index.html – The main HTML file.

config.xml – A global configuration file.

Preview your app (android)

Import android project into your eclipse.

import cordova project

import cordova project

Select AndroidExisting Android Code Into Workspace.

import existing android code into workspace

import existing android code into workspace

Browse your project and click Finish.

import android project

import android project

Follow this tutorial how to run android app in android simulator.

http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/

Preview your app (ios)

Go to your project directory and browse for xcode project, platforms > ios > ToDo.xcodeproj then run xcode project.

Click Play on top left side to preview the app on your simulator.

xcode project

xcode project

Learning client side API and building a multi page application

Right click js folder on your project. Go to New Other.

Javascript Source File

Javascript Source File

Select JavaScript > JavaScript Source File and click Next.

javascript source file

javascript source file

Create 3 javascript files.

  • main.js – initialize function.
  • AddPage.js – to add user details.
  • ListPage.js – to retrieve user list.
  • DetailPage.js – to retrieve user details.

Click Finish.

javascript source file

javascript source file

Right click www folder and go to New > Folder to create a new folder.

add folder

add folder

Name it pages and click Finish.

add folder pages

add folder pages

Then create a few of html pages inside page folder that we already created just now. Right click pages folder and go to New > HTML File.

HTML Files

HTML Files

Select Web > HTML File and click Next.

new html file

new html file

Create 3 html files and click Finish. Repeat.

  • AddPage.html – to add task details.
  • ListPage.html – to retrieve task list.
  • DetailPage.html – to retrieve task details.
new html file

new html file

Copy Jquery javascript files that you already extract from proper location into js folder.

jquery

jquery

Go to extracted Ratchet directory and select/copy all folders inside ratchet-2.0.2 > dist .

ratchet directory

ratchet directory

Then paste it inside www folder.

ratchet

ratchet

Open your index.html and replace with this code.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <!-- Sets initial viewport load and disables zooming  -->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Include the compiled Ratchet CSS -->
    <link href="css/ratchet.css" rel="stylesheet">
    <script src="cordova.js" type="text/javascript"></script>
    <script src="js/jquery-1.11.3.min.js"></script>
    <script src="//www.parsecdn.com/js/parse-1.4.2.min.js"></script>
    <script type="text/javascript">
    	Parse.initialize("Application ID", "Client Key");
    </script>
    <script src="js/ratchet.js"></script>
    <script src="js/main.js"></script>
  </head>
  <body onload="init()">

  </body>
</html>

Replace all codes with given codes for each javascript files.

AddPage.js

currentPage = {};
currentPage.init = function() {
	console.log("AddPage :: init");
};
currentPage.back = function() {
	console.log("AddPage :: back");
	$("body").load(path + "pages/ListPage.html", function() {
		$.getScript(path + "js/ListPage.js", function() {
			if (currentPage.init) {
				currentPage.init();
			}
		});
	});
};
currentPage.add = function() {
	console.log("AddPage :: add");
	var name = $("#name").val();
	var description = $("#description").val();
	formData = {
		name: $("#name").val(),
		description: $("#description").val(),
	}
	if (name == "") {
		alert("Please enter name");
	} else if (description == "") {
		alert("Please enter description");
	} else {
		var Task = Parse.Object.extend("Task");
		var task = new Task();
		task.set("name", name);
		task.set("description", description);
		task.save(null, {
			success: function(task) {
				// Execute any logic that should take place after the object is saved.
				alert("Add task success");
				$("body").load(path + "pages/ListPage.html", function() {
					$.getScript(path + "js/ListPage.js", function() {
						if (currentPage.init) {
							currentPage.init();
						}
					});
				});
			},
			error: function(task, error) {
				// Execute any logic that should take place if the save fails.
				// error is a Parse.Error with an error code and message.
				alert('Failed to create new object, with error code: ' + error.message);
			}
		});
	}
};

DetailPage.js

currentPage = {};
currentPage.init = function() {
	console.log("DetailPage :: init");
	detailTask();
};
currentPage.back = function() {
	console.log("DetailPage :: back");
	$("body").load(path + "pages/ListPage.html", function() {
		$.getScript(path + "js/ListPage.js", function() {
			if (currentPage.init) {
				currentPage.init();
			}
		});
	});
};
currentPage.edit = function() {
	console.log("DetailPage :: edit");
	var taskId = sessionStorage.taskId;
	var name = $("#name").val();
	var description = $("#description").val();
	formData = {
		taskId: sessionStorage.taskId,
		name: $("#name").val(),
		description: $("#description").val()
	}
	if (name == "") {
		alert("Please enter name");
	} else if (description == "") {
		alert("Please enter description");
	} else {
		var Task = Parse.Object.extend("Task");
		var query = new Parse.Query(Task);
		query.get(taskId, {
			success: function(task) {
				// The object was retrieved successfully.
				// Create the object.
				task.set("name", name);
				task.set("description", description);
				task.save(null, {
					success: function(task) {
						alert("Edit task success");
						$("body").load(path + "pages/ListPage.html", function() {
							$.getScript(path + "js/ListPage.js", function() {
								if (currentPage.init) {
									currentPage.init();
								}
							});
						});
					}
				});
			},
			error: function(object, error) {
				// The object was not retrieved successfully.
				// error is a Parse.Error with an error code and message.
				alert(error);
			}
		});
	}
};

function detailTask() {
	formData = {
		taskId: sessionStorage.taskId
	}
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.get(taskId, {
		success: function(task) {
			// The object was retrieved successfully.
			$('#name').val(task.get("name"));
			$('#description').val(task.get("description"));
		},
		error: function(object, error) {
			// The object was not retrieved successfully.
			// error is a Parse.Error with an error code and message.
			alert(error);
		}
	});
}
currentPage.remove = function() {
	console.log("DetailPage :: delete");
	deleteTask();
};

function deleteTask() {
	formData = {
		taskId: sessionStorage.taskId
	}
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.get(taskId, {
		success: function(task) {
			// The object was retrieved successfully.
			task.destroy({
				success: function(task) {
					// The object was deleted from the Parse Cloud.
					alert("Delete task success");
					$("body").load(path + "pages/ListPage.html", function() {
						$.getScript(path + "js/ListPage.js", function() {
							if (currentPage.init) {
								currentPage.init();
							}
						});
					});
				},
				error: function(task, error) {
					// The delete failed.
					// error is a Parse.Error with an error code and message.
				}
			});
		},
		error: function(object, error) {
			// The object was not retrieved successfully.
			// error is a Parse.Error with an error code and message.
			alert(error);
		}
	});
}

ListPage.js

currentPage = {};
currentPage.init = function() {
	console.log("ListPage :: init");
	listTasks();
};
currentPage.loadPage = function(pageIndex) {
	console.log("ListPage :: loadPage :: pageIndex: " + pageIndex);
	$("body").load(path + "pages/" + pageIndex + ".html");
	$.getScript(path + "js/" + pageIndex + ".js", function() {
		if (currentPage.init) {
			currentPage.init();
		}
	});
};
currentPage.detailPage = function(userId) {
	sessionStorage.setItem("userId", userId);
	$("body").load(path + "pages/DetailPage.html");
	$.getScript(path + "js/DetailPage.js", function() {
		if (currentPage.init) {
			currentPage.init();
		}
	});
};

function listTasks() {
	var Task = Parse.Object.extend("Task");
	var query = new Parse.Query(Task);
	query.equalTo("typeId", "3");
	query.find({
		success: function(results) {
			var index = 0;
			var Arrlen = results.length;
			for (index = 0; index < Arrlen; ++index) {
				var obj = results[index];
				html += '<li class="table-view-cell">';
				html += '<a class="navigate-right" onclick="currentPage.detailPage(' + obj.id + ');" >';
				html += obj.attributes.name;
				html += '</a></li>';
			}
		},
		error: function(object, error) {
			alert(error);
		}
	});
}

main.js

var pagesHistory = [];
var currentPage = {};
var path = "";

function init(){

    $("body").load(path + "pages/ListPage.html", function(){
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });

}

Replace all codes with given codes for each html files.

AddPage.html

<script>
    $.getScript(path + "js/AddPage.js");
</script>
 
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">AddPage</h1>
</header>

<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>

        <li class="table-view-cell"><input id="name" name="name" type="text"></li>

        <li class="table-view-cell table-view-divider">Description:</li>

        <li class="table-view-cell"><input id="description" name="description" type="text"></li>

        <li class="table-view-cell"></li>
    </ul>
   </div>
    <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.add();">ADD TASK</button>
    </div>
</div>

DetailPage.html

<script>
    $.getScript(path + "js/DetailPage.js");
</script>

<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">DetailPage</h1>
</header>

<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>

        <li class="table-view-cell"><input id="name" name="name" type="text"></li>

        <li class="table-view-cell table-view-divider">Description:</li>

        <li class="table-view-cell"><input id="description" name="description" type="text"></li>

    </ul>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.edit();">EDIT TASK</button>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-negative btn-block" onclick="currentPage.remove();">REMOVE TASK</button>
   </div>
</div>

ListPage.html

<script>
    $.getScript(path + "js/ListPage.js");
</script>

<header class="bar bar-nav">
	<button id="LoadAddButton" class="btn pull-right" onclick="currentPage.loadPage('AddPage');">Add</button>
  	<h1 class="title">ListPage</h1>
</header>

<div class="content">
	<ul id="taskList" class="table-view"></ul>
</div>

Build and run your project. I’m using Genymotion. If you don’t have, you can download it here,https://www.genymotion.com/.

 

Result.

You can download the source code here, https://github.com/datomnurdin/com.revivalx.todolist.parse.

Tutorial geolocation cordova plugin and google map API V3 for iOS and android

It is very easy to detect device’s current location (latitude and longitude) with Cordova org.apache.cordova.geolocation plugin. This plugins detect current location based on GPS, IP address, RFID, WiFi and Bluetooth MAC addresses, and GSM/CDMA cell IDs. But there is no guarantee that location will be detected precisely enough.

Create project com.revivalx.cordova.geolocation and install geolocation cordova plugin into your cordova project.

cordova plugin add org.apache.cordova.geolocation

Open up your config.xml file and replace with this code.

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.revivalx.cordova.geolocation" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>GeolocationCordova</name>
    <description>
        This source code provides example about the device's location, such as latitude and longitude.
    </description>
    <author email="nurdinnorazanservices@gmail.com" href="http://revivalx.com">
        Mohammad Nurdin bin Norazan
    </author>
    <content src="index.html" />
    <access origin="*" />
</widget>

After that you need to add iOS and android platform into your cordova project using this command. If you using windows, you can’t create iOS platform because you need iOS SDK installed in your machine.

cordova platform add iOS
cordova platform add android
cordova platform add

cordova platform add

Open up index.html file in www folder. Replace with this code.

<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="msapplication-tap-highlight" content="no" />
        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        <title>Geolocation Cordova Plugin</title>
    </head>
    <body>
        
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
    </body>
</html>

Then open up index.js file in js folder add replace all with this code

var onSuccess = function(position) {
    alert('Latitude: '          + position.coords.latitude          + '\n' +
          'Longitude: '         + position.coords.longitude         + '\n' +
          'Altitude: '          + position.coords.altitude          + '\n' +
          'Accuracy: '          + position.coords.accuracy          + '\n' +
          'Altitude Accuracy: ' + position.coords.altitudeAccuracy  + '\n' +
          'Heading: '           + position.coords.heading           + '\n' +
          'Speed: '             + position.coords.speed             + '\n' +
          'Timestamp: '         + position.timestamp                + '\n');
};

function onError(error) {
    alert('code: '    + error.code    + '\n' +
          'message: ' + error.message + '\n');
}

navigator.geolocation.getCurrentPosition(onSuccess, onError);

Build and run the app. I hope you enjoy this article. You may download the source code here, https://github.com/datomnurdin/com.revivalx.cordova.geolocation .

AngularJs Ionic Mobile App Development Tutorial – Marketing App – Part 1

In this tutorial you will develop a marketing app for iOS and android with these features

  • Login (Facebook Login)
  • Edit profile
  • Create and view all campaign details
  • View reports

What you will be learn from this tutorial are

  • Setup development environment using certain IDE for iOS and android.
  • Preview your iOS and android hybrid app on actual device (smart phone).
  • Develop iOS and android hybrid app using client side language.
  • Create multi page application for iOS and android hybrid app.
  • Connect iOS and android hybrid app with server side language.

Download the required software packages.

Download and install Eclipse Juno SR2 and Xcode 6 (if you’re using Mac for mobile development).

Eclipse Juno SR2 – http://www.eclipse.org/downloads/packages/release/juno/sr2
Xcode 6 – https://developer.apple.com/xcode/downloads/

Setup ADT and Android SDK into your eclipse.

Then you need to setup cordova using NPM (node package manager).

ADT and Android SDK Setup

Don’t forget to install or update your machine with latest JDK 7. Download at http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html.

After you download, make sure you set the correct java path. If not, you can’t start your eclipse. You can download eclipse Juno http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/junosr2.

Then install it. After you install the tool that I tell you, make sure you install ADT (android development tools).

Go to Help and choose Install New Software.

eclipse - Install New Software

eclipse – Install New Software

Click Add button then popup box will appear. Enter ‘ADT’ in name textfield and ‘https://dl-ssl.google.com/android/eclipse/’ in location textfield.

eclipse - Install ADT

eclipse – Install ADT

Click Select All button and click Next.

eclipse - Install ADT

eclipse – Install ADT

Click Next.

eclipse - Install ADT

eclipse – Install ADT

Select I accept the terms of the license of agreement. Click Finish.

eclipse - Install ADT

eclipse – Install ADT

After finished setup ADT in your eclipse, download android SDK (http://developer.android.com/sdk/index.html#Other) and update latest android version or depends on your device for testing. After you install the android SDK, open android SDK , /android-sdk/tools. For this tutorial we will using latest android SDK, Android 5.0 aka Lolipop. Open your terminal/cmd, type android command and enter.

android terminal

android terminal

Select Android 5.0 and click Install 12 packages.

Android SDK Manager

Android SDK Manager

Select all packages, choose Accept License and click Install.

Android SDK Manager

Android SDK Manager

After that, install node.js (http://nodejs.org/) to use npm for package manager. If you not install node.js, you should not be able to invoke node or npm on your command line to install cordova apache. Then install cordova apache using terminal for Mac, command prompt for Windows.

Type this command to install cordova apache.

For Mac

sudo npm install -g cordova ionic

For Windows. If you can’t install, make sure you run the command prompt as administrator.

npm install -g cordova ionic
sudo npm install -g cordova ionic

sudo npm install -g cordova ionic

sudo npm install -g cordova ionic

sudo npm install -g cordova ionic

After you finish install the cordova apache. You can start create your project using cordova command. Open your terminal/command prompt, type these command. You can ignore sudo if you using Windows.

ionic start com.revivalx.cordova.marketing
ionic create project

ionic create project

Open config.xml inside cordova project that you already created just now. Change id and name. Others are optional.

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.revivalx.cordova.marketing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>ToDo</name>
    <description>
        Marketing App.
    </description>
    <author email="mohammadnrdn@gmail.com" href="http://revivalx.com">
        Mohammad Nurdin bin Norazan
    </author>
    <content src="index.html" />
    <access origin="*" />
</widget>

Go back to terminal and add platform for android/iOS. Type these command to add both platforms.

ionic platform add android
ionic platform add android

ionic platform add android

ionic platform add ios
ionic platform add ios

ionic platform add ios

Note, if you got some error message during add andorid platform, you can refer to this link

Common errors during developing hybrid android app– http://blog.revivalx.com/2014/11/02/common-errors-during-developing-android-hybrid-app/

Android part.

Go to eclipse and import android project. Click File and choose Import.

eclipse - import project

eclipse – import project

Choose Existing Android Code into Workspace and click Next.

eclipse - existing android code into workspace

eclipse – existing android code into workspace

Browse your android project and select all. Click Finish.

eclipse – import projects

eclipse – import projects

Make sure you already connect your mobile device (android phone) and enable USB debugging.

Enable USB debugging: http://www.phonearena.com/news/How-to-enable-USB-debugging-on-Android_id53909

Right click android project > Run As > Android Application.

Run As Android Application

Run As Android Application

Select your phone and click Ok.

Android Device Chooser

Android Device Chooser

If successful, your app shown like this.

cordova app preview on android

ionic app preview on android

iOS part.

Open your cordova project for iOS. Go to../com.revivalx.ionic.marketing/platforms/ios/com.revivalx.ionic.marketing.xcodeproj . Select iPhone6 simulator and click Play button.

xcode6

xcode6

If successful, your app shown like this.

ionic app preview on iOS

ionic app preview on iOS

I think thats all for

  • Setup development environment using certain IDE for iOS and android.
  • Preview your iOS and android hybrid app using emulator and actual device (smart phone).

Next tutorial we will develop iOS and android hybrid app using client side language.

Hybrid and Native Mobile App Training this 20 and 21 December

Attention to all!

I’m pleased to announce that I will be organizing Hybrid Mobile App Training this 20 and 21 December. If you’re planning to develop mobile apps, this training is for you. Method that I use for this training is personal coaching/face to face. Max 3/5 persons.

20 December: Hybrid Mobile App Training (Android and iOS)
21 December: Native Mobile App Training (Android)

Fee is RM1000/pax for 1 day training. To register, please whatsapp my number, 0176347239. My call number, 01126252058.

http://www.revivalx.com/my/training/

Hybrid Mobile App Training this 20 and 21 December

Hybrid Mobile App Training this 20 and 21 December

Develop a simple to-do-list mobile app using phonegap/cordova for iOS and android -Part 3

This tutorial is the third part of a three-part series on how to create a simple to-do-list app for beginners.

In the first part of the tutorial series, setup development environment using certain IDE for iOS/android and preview your iOS and android hybrid app using emulator and actual device (smart phone). http://blog.revivalx.com/2014/11/02/develop-a-simple-to-do-list-mobile-app-using-phonegapcordova-for-ios-and-android-part-1/

In this second tutorial, you’ll learn how to develop iOS and android hybrid app using client side language and create multi page application for iOS and android hybrid app. http://blog.revivalx.com/2014/11/03/develop-a-simple-to-do-list-mobile-app-using-phonegapcordova-for-ios-and-android-part-2/

In this third tutorial, you will learn how to create a simple web service for your app. Your web service will enable to create, read, update and data using JSON ( Javascript Object Notation) to your database. We will not using SOAP (Simple Object Access Protocol) for this tutorial because JSON is easy to learn and simple compare to SOAP is too complex for beginner. It basically works on HTTP protocol.

URL Structure

In web service design the URL endpoints should be well formed and should be easily understandable. Every URL for a resource should be uniquely identified.

For example

GET – http://localhost:8888/todolist/todo/index
GET – http://localhost:8888/todolist/todo/display?taskId=1
POST – http://localhost:8888/todolist/todo/create
POST – http://localhost:8888/todolist/todo/update?taskId=1
POST – http://localhost:8888/todolist/todo/delete?taskId=1

Why we using JSON for mobile application? Why not we access directly to our database without using JSON instead PHP or JAVA. It is because hybrid mobile app support client side languages, not servers side languages. Hybrid mobile app consists these 3 languages are HTML5, CSS and Javascript. We can’t simply run PHP or JAVA in mobile app. This video (http://coenraets.org/blog/2013/05/architecting-a-phonegap-application-video-slides/) will answer these questions.

Getting started.

For this tutorial you need to have basic in PHP and Mysql. You need to have eclipse Helios (https://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/heliossr2 ) to complete the project. Compare to previous tutorial we using eclipse Juno. It is because we develop an android app. For eclipse PHP we develop web service using PHP.

First you need to setup a web server in your machine. I’m using MAMP (stands for Mac, Apache, Mysql and Php) for this tutorial. It’s ok if your want to use other than this such as XAMPP or WAMP. No problem with that. But i suggest you using MAMP if you using Mac. There will be a lot of glitches if you using XAMPP or WAMP in your apple machine.

MAMP – http://www.mamp.info/en/downloads/

XAMPP – https://www.apachefriends.org/download.html

WAMP – http://www.wampserver.com/en/

Download MAMP and install to your machine. After finish installed MAMP to your machine, start apache server and mysql server. So far I didn’t get any issues starting my web server compare to XAMPP. If you got problem start up your apache server, make sure you check port 80 because maybe other applications using the same port especially skype. you need to terminate the application before start the apache server. This issue always happened to windows users.

If your apache and mysql server running successful, you will get like this (green light on both server status).

MAMP

MAMP

Then open your chrome browser. Why I’m using chrome rather than other browser because there are a tons of chrome extensions available in chrome marketplace. That’s why i choose to live with it. Type this to open your MAMP start page in your browser.

http://localhost:8888/MAMP/?language=English

Then click phpMyAdmin at top of the bar. You will see this page.

phpmyadmin

phpmyadmin

You need to create a database and a table for this tutorial. Click database tab. Then create ‘todolist‘. Copy this sql script to your sql tab to generate task table.

CREATE TABLE `tasks` (
`taskId` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(250) NOT NULL,
`description` varchar(500) NOT NULL,
`dateCreated` datetime NOT NULL,
`dateUpdated` datetime NOT NULL,
PRIMARY KEY (`taskId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

After executing these queries go through each tables and make sure that everything created correctly. Until now we are done with getting your system ready for development. Run your eclipse Helios to start develop web service. Right click in PHP explore > New > PHP Project.

eclipe helios

eclipe helios

Type todolist-api in project name. At content part, choose create project at existing location (from existing source). Type path name in directory field. /Applications/MAMP/htdocs/todolist-api  . Click Finish.

Right click in your project, select New > PHP File .

PHP File

PHP File

Type db_config.php and click Finish.

You need to create 5 more php files for db_connect.php, create_task.php, get_task_details.php, get_all_tasks.php, update_task.php and delete_task.php. You can check reference that I take from this site for this tutorial.

db_config.php – database configuration / setting.

db_connect.php – database connection.

create_task.php – create task details into database.

get_task_tasks.php – get task details base on task id from database.

get_all_tasks – retrieve all list of tasks.

update_task.php – update task into database base on task id.

delete_task.php – delete task from database base on task id.

Fill up all these PHP files using these code.

db_config.php

<?php
define('DB_USER', "root"); // db user
define('DB_PASSWORD', "root"); // db password (mention your db password here)
define('DB_DATABASE', "todolist"); // database name
define('DB_SERVER', "localhost"); // db server
?>

db_connect.php

<?php
class DB_CONNECT {

    // constructor
    function __construct() {
        // connecting to database
        $this->connect();
    }

    // destructor
    function __destruct() {
        // closing db connection
        $this->close();
    }

    /**
     * Function to connect with database
     */
    function connect() {
        // import database connection variables
        require_once __DIR__ . '/db_config.php';

        // Connecting to mysql database
        $con = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD) or die(mysql_error());

        // Selecing database
        $db = mysql_select_db(DB_DATABASE) or die(mysql_error()) or die(mysql_error());

        // returing connection cursor
        return $con;
    }

    /**
     * Function to close db connection
     */
    function close() {
        // closing db connection
        mysql_close();
    }

}

?>

create_task.php

<?php

/*
 * Following code will create a new task row
 * All task details are read from HTTP Post Request
 */

// array for JSON response
$response = array();

// check for required fields
if (isset($_POST['name']) && isset($_POST['description'])) {

    $name = $_POST['name'];
    $description = $_POST['description'];

    // include db connect class
    require_once __DIR__ . '/db_connect.php';

    // connecting to db
    $db = new DB_CONNECT();

    // mysql inserting a new row
    $result = mysql_query("INSERT INTO tasks(name, description, dateCreated, dateUpdated) VALUES('$name', '$description', NOW(), NOW())");

    // check if row inserted or not
    if ($result) {
        // successfully inserted into database
        $response["success"] = 1;
        $response["message"] = "Task successfully created.";

        // echoing JSON response
        echo json_encode($response);
    } else {
        // failed to insert row
        $response["success"] = 0;
        $response["message"] = "Oops! An error occurred.";

        // echoing JSON response
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";

    // echoing JSON response
    echo json_encode($response);
}
?>

get_task_details.php

<?php

/*
 * Following code will get single task details
 * A task is identified by task id (taskId)
 */

// array for JSON response
$response = array();

// include db connect class
require_once __DIR__ . '/db_connect.php';

// connecting to db
$db = new DB_CONNECT();

// check for post data
if (isset($_GET["taskId"])) {
    $taskId = $_GET['taskId'];

    // get a task from task table
    $result = mysql_query("SELECT *FROM tasks WHERE taskId = $taskId");

    if (!empty($result)) {
        // check for empty result
        if (mysql_num_rows($result) > 0) {

            $result = mysql_fetch_array($result);

            $task = array();
            $task["taskId"] = $result["taskId"];
            $task["name"] = $result["name"];
            $task["description"] = $result["description"];
            $task["dateCreated"] = $result["dateCreated"];
            $task["dateUpdated"] = $result["dateUpdated"];
            // success
            $response["success"] = 1;

            // task node
            $response["task"] = array();

            array_push($response["task"], $task);

            // echoing JSON response
            echo json_encode($response);
        } else {
            // no task found
            $response["success"] = 0;
            $response["message"] = "No task found";

            // echo no tasks JSON
            echo json_encode($response);
        }
    } else {
        // no task found
        $response["success"] = 0;
        $response["message"] = "No task found";

        // echo no tasks JSON
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";

    // echoing JSON response
    echo json_encode($response);
}
?>

get_all_tasks.php

<?php

/*
 * Following code will list all the tasks
 */

// array for JSON response
$response = array();

// include db connect class
require_once __DIR__ . '/db_connect.php';

// connecting to db
$db = new DB_CONNECT();

// get all tasks from task table
$result = mysql_query("SELECT *FROM tasks") or die(mysql_error());

// check for empty result
if (mysql_num_rows($result) > 0) {
    // looping through all results
    // tasks node
    $response["tasks"] = array();

    while ($row = mysql_fetch_array($result)) {
        // temp tasks array
        $tasks = array();
        $task["taskId"] = $row["taskId"];
        $task["name"] = $row["name"];
        $task["description"] = $row["description"];
        $task["dateCreated"] = $row["dateCreated"];
        $task["dateUpdated"] = $row["dateUpdated"];

        // push single task into final response array
        array_push($response["tasks"], $task);
    }
    // success
    $response["success"] = 1;

    // echoing JSON response
    echo json_encode($response);
} else {
    // no tasks found
    $response["success"] = 0;
    $response["message"] = "No tasks found";

    // echo no tasks JSON
    echo json_encode($response);
}
?>

update_task.php

<?php

/*
 * Following code will update a task information
 * A task is identified by task id (taskId)
 */

// array for JSON response
$response = array();

// check for required fields
if (isset($_POST['taskId']) && isset($_POST['name']) && isset($_POST['description'])) {

    $taskId = $_POST['taskId'];
    $name = $_POST['name'];
    $description = $_POST['description'];

    // include db connect class
    require_once __DIR__ . '/db_connect.php';

    // connecting to db
    $db = new DB_CONNECT();

    // mysql update row with matched pid
    $result = mysql_query("UPDATE tasks SET name = '$name', description = '$description', dateUpdated = NOW() WHERE taskId = $taskId");

    // check if row inserted or not
    if ($result) {
        // successfully updated
        $response["success"] = 1;
        $response["message"] = "Task successfully updated.";

        // echoing JSON response
        echo json_encode($response);
    } else {

    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";

    // echoing JSON response
    echo json_encode($response);
}
?>

delete_task.php

<?php

/*
 * Following code will delete a task from table
 * A task is identified by task id (taskId)
 */

// array for JSON response
$response = array();

// check for required fields
if (isset($_POST['taskId'])) {
    $taskId = $_POST['taskId'];

    // include db connect class
    require_once __DIR__ . '/db_connect.php';

    // connecting to db
    $db = new DB_CONNECT();

    // mysql update row with matched taskId
    $result = mysql_query("DELETE FROM tasks WHERE taskId = $taskId");

    // check if row deleted or not
    if (mysql_affected_rows() > 0) {
        // successfully updated
        $response["success"] = 1;
        $response["message"] = "Task successfully deleted";

        // echoing JSON response
        echo json_encode($response);
    } else {
        // no task found
        $response["success"] = 0;
        $response["message"] = "No task found";

        // echo no tasks JSON
        echo json_encode($response);
    }
} else {
    // required field is missing
    $response["success"] = 0;
    $response["message"] = "Required field(s) is missing";

    // echoing JSON response
    echo json_encode($response);
}
?>

After you fill up the files, you need to install Curl in your machine. Curl is a command line tool for transferring data with URL syntax. Install curl via npm. Type this command to install. If you using windows, run this command in your command prompt.

npm install curl
npm install curl

npm install curl

npm install curl

npm install curl

Run this command to test create_task.php in your terminal.

curl POST

curl POST

Success status for create_task.php

{"success":1,"message":"Task successfully created."}

Run it again twice using different data.

Proceed all these curl commands for each URLs

get_task_details.php

curl http://localhost:8888/todolist-api/get_task_details.php?taskId=1

Success status for get_task_details.php

{
	"success": 1,
	"task": [{
		"taskId": "1",
		"name": "Breakfast",
		"description": "Nasi Lemak",
		"dateCreated": "2014-11-07 01:48:32",
		"dateUpdated": "2014-11-07 01:48:32"
	}]
}

get_all_tasks.php

curl http://localhost:8888/todolist-api/get_all_tasks.php

Success status for get_all_tasks.php

{
	"tasks": [{
		"taskId": "1",
		"name": "Breakfast",
		"description": "Nasi Lemak",
		"dateCreated": "2014-11-07 01:48:32",
		"dateUpdated": "2014-11-07 01:48:32"
	}, {
		"taskId": "2",
		"name": "Afternoon",
		"description": "Nasi Kukus",
		"dateCreated": "2014-11-07 01:53:14",
		"dateUpdated": "2014-11-07 01:53:14"
	}, {
		"taskId": "3",
		"name": "Dinner",
		"description": "Nasi Goreng",
		"dateCreated": "2014-11-07 01:53:31",
		"dateUpdated": "2014-11-07 01:53:31"
	}],
	"success": 1
}

update_task.php

curl -X POST -F taskId=1 -F name=Supper -F description=KFC http://localhost:8888/todolist-api/update_task.php

Success status for update_task.php

{"success":1,"message":"Task successfully updated."}

delete_task.php

curl -X POST -F taskId=1 http://localhost:8888/todolist-api/delete_task.php

Success status for delete_task.php

{"success":1,"message":"Task successfully deleted"}

Now we want to integrate PHP with the app. You need to replace all html files and js files so we can invoke PHP from there.

AddPage.js

currentPage = {};
currentPage.init = function() {
    console.log("AddPage :: init");
};
currentPage.back = function() {
    console.log("AddPage :: back");
    $("body").load(path + "pages/ListPage.html", function() {
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};
currentPage.add = function() {
    console.log("AddPage :: add");
    var name = $("#name").val();
    var description = $("#description").val();
    formData = {
        name: $("#name").val(),
        description: $("#description").val()
    }
    if (name == "") {
        alert("Please enter name");
    } else if (description == "") {
        alert("Please enter description");
    } else {
        $.ajax({
            type: "post",
            url: "http://demo.revivalx.com/todolist-api/create_task.php",
            data: formData,
            dataType: "json",
            success: function(data) {
                alert("Add task success");
                $("body").load(path + "pages/ListPage.html", function() {
                    $.getScript(path + "js/ListPage.js", function() {
                        if (currentPage.init) {
                            currentPage.init();
                        }
                    });
                });
            },
            error: function() {
                alert("Add task failure");
            }
        });
    }
};

DetailPage.js

currentPage = {};
currentPage.init = function() {
    console.log("DetailPage :: init");
    detailTask();
};
currentPage.back = function() {
    console.log("DetailPage :: back");
    $("body").load(path + "pages/ListPage.html", function() {
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};
currentPage.edit = function() {
    console.log("DetailPage :: edit");
    var taskId = sessionStorage.taskId;
    var name = $("#name").val();
    var description = $("#description").val();
    formData = {
        taskId: sessionStorage.taskId,
        name: $("#name").val(),
        description: $("#description").val()
    }
    if (name == "") {
        alert("Please enter name");
    } else if (description == "") {
        alert("Please enter description");
    } else {
        $.ajax({
            type: "post",
            url: "http://demo.revivalx.com/todolist-api/update_task.php",
            data: formData,
            dataType: "json",
            success: function(data) {
                alert("Edit task success");
                $("body").load(path + "pages/ListPage.html", function() {
                    $.getScript(path + "js/ListPage.js", function() {
                        if (currentPage.init) {
                            currentPage.init();
                        }
                    });
                });
            },
            error: function() {
                alert("Edit task failure");
            }
        });
    }
};

function detailTask() {
    formData = {
        taskId: sessionStorage.taskId
    }
    $.ajax({
        type: "get",
        url: "http://demo.revivalx.com/todolist-api/get_task_details.php",
        data: formData,
        dataType: "json",
        success: function(data) {
            $('#name').val(data.task[0].name);
            $('#description').val(data.task[0].description);
        },
        error: function() {
            alert("Detail task failure");
        }
    });
}
currentPage.remove = function() {
    console.log("DetailPage :: delete");
    deleteTask();
};

function deleteTask() {
    formData = {
        taskId: sessionStorage.taskId
    }
    $.ajax({
        type: "post",
        url: "http://demo.revivalx.com/todolist-api/delete_task.php",
        data: formData,
        dataType: "json",
        success: function(data) {
            alert("Delete task success");
            $("body").load(path + "pages/ListPage.html", function() {
                $.getScript(path + "js/ListPage.js", function() {
                    if (currentPage.init) {
                        currentPage.init();
                    }
                });
            });
        },
        error: function() {
            alert("Delete task failure");
        }
    });
}

ListPage.js

currentPage = {};
currentPage.init = function() {
    console.log("ListPage :: init");
    listTasks();
};
currentPage.loadPage = function(pageIndex) {
    console.log("ListPage :: loadPage :: pageIndex: " + pageIndex);
    $("body").load(path + "pages/" + pageIndex + ".html");
    $.getScript(path + "js/" + pageIndex + ".js", function() {
        if (currentPage.init) {
            currentPage.init();
        }
    });
};
currentPage.detailPage = function(taskId) {
    sessionStorage.setItem("taskId", taskId);
    $("body").load(path + "pages/DetailPage.html");
    $.getScript(path + "js/DetailPage.js", function() {
        if (currentPage.init) {
            currentPage.init();
        }
    });
};

function listTasks() {
    $.ajax({
        type: "get",
        url: "http://demo.revivalx.com/todolist-api/get_all_tasks.php",
        dataType: "json",
        success: function(data) {
            var ul = $('#taskList');
            var html = '';
            $.each(data.tasks, function(index, item) {
                html += '<li class="table-view-cell">';
                html += '<a class="navigate-right" onclick="currentPage.detailPage(' + item.taskId + ');" >';
                html += item.name;
                html += '</a></li>';
            });
            ul.append(html);
        },
        error: function() {
            alert("List task failure");
        }
    });
}

AddPage.html

<script>
    $.getScript(path + "js/AddPage.js");
</script>
  
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">AddPage</h1>
</header>
<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>
 
        <li class="table-view-cell"><input id="name" name="name" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Description:</li>
 
        <li class="table-view-cell"><input id="description" name="description" type="text"></li>
 
        <li class="table-view-cell"></li>
    </ul>
   </div>
    <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.add();">ADD TASK</button>
    </div>
</div>

DetailPage.html

<script>
    $.getScript(path + "js/DetailPage.js");
</script>
 
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">DetailPage</h1>
</header>
 
<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>
 
        <li class="table-view-cell"><input id="name" name="name" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Description:</li>
 
        <li class="table-view-cell"><input id="description" name="description" type="text"></li>
 
    </ul>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.edit();">EDIT TASK</button>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-negative btn-block" onclick="currentPage.remove();">REMOVE TASK</button>
   </div> 
</div>

ListPage.html

<script>
    $.getScript(path + "js/ListPage.js");
</script>

<header class="bar bar-nav">
	<button id="LoadAddButton" class="btn pull-right" onclick="currentPage.loadPage('AddPage');">Add</button>
  	<h1 class="title">ListPage</h1>
</header>

<div class="content">
	<ul id="taskList" class="table-view"></ul>
</div>

Build and run your app. You can find the source code here: https://github.com/datomnurdin/com.revivalx.cordova.todomobile