In my previous article we built an Ionic framework app that pulls weather data from Forecast.io for a given latitude and longitude. In this tutorial, we’re going to extend the app to use Parse as a remote backend.
If you’re not familiar with Parse, it’s a web-based platform that provides backend services. It allows developers to focus on the application development without having to worry about server setup and maintenance.
Since parse provides SDKs for Android, iOS and JavaScript, it’s a natural choice for hybrid app developers looking for an easy-to-use remote backend.
Parse setup
Before we can begin using Parse, we have to sign up for a free developer account. Signing up is quick and easy. Just go here.
Once you signup, create an application by pressing the ‘create new app’ button

Once your app is created, Parse.com displays a window listing API keys that are specific to you application.

Cick the button labelled databrowser
. You should now see the dashboard for your app.

From the dashboard you can manage your app settings, configure push notification, view analytics, create cloud code and create your data classes from the data browser. In this tutorial, we’ll just be looking at the databrowser section. We’ll explore analytics, push notifications and cloud code in future articles.
Click the new class button to, well, create a new class.

The default option for class type will be custom. Enter City
for class name and press enter. You should now see a newly created class in the dashboard with the following default columns
- objectId
- createdAt
- updatedAt
- ACL
objectId
is a unique alphanumeric ID generated by parse. We will be covering ACL’s in future articles.
To add columns specific to the class City
, click the button labelled + Col
. Add the following columns.
- name – string
- latitude – integer
- longitude – integer
Next, click the button labelled + Row
to add blank rows.
Lastly, add the following data to pre-populate the class.
- Miami, 25.7877,80.2241
- New York City, 40.7127 , 74.0059
- London, 51.5072, 1.1275
- Los Angeles, 34.0500, 118.2500
- Dallas, 32.7758, 96.7967
- Frankfurt, 50.1117, 8.6858
- New Delhi, 28.6100, 77.2300
Great, we have so far created an account on parse.com, got our API keys and created a class to store location details.
Before we begin coding the app we have to download the Parse JavaScript SDK here.
About the app
Our app shows the weather data for a given latitude and longitude, with the help of Forecast.io.
If you’re just joining us, please refer to Part 1 of this tutorial for the preliminary coding and set up required.
Now, we’re going to modify the application to use data from Parse.com instead of working with static data. You can begin by either making a copy of the code from Part 1 and make changes as specified, or download the complete source code for this version at the end of this tutorial. We’ll be working with a copy of the existing code making changes as we go along.
To complete the app we need to:
- Add parse-1.2.17.js to index.html
- Modify LocationsCtrl in controllers.js to fetch data from Parse.
- Initialize the Parse SDK in app.js
- Modify the view file tab-cities.html to pass the currently selected items index to LocationsCtrl.changeCity.
If you downloaded the code for the previous article, you’ll want to look for the ionic-weather-app
folder. If you downloaded code into a different folder, substitute the folder name accordingly.
Go to the command prompt, navigate to the parent folder containing the code for part one of this tutorial, and type the following commands.
$cp -R ionic-weather-app ionic-weather-app2
$cd ionic-weather-app2/www
Now, copy parse-1.2.17.js to the folder js/lib/ionic/js/
.
Next, open index.html
, which is found in the www
folder and find the line containing the following.
<script src="lib/ionic/js/angular/angular-resource.js"></script>
Add the following after below the line.
<script src="lib/ionic/js/parse-1.2.17.js"></script>
Save index.html
, open www/js/controllers.js
and replace its contents with the code below.
angular.module('starter.controllers', ['ionic'])
.constant('FORECASTIO_KEY', 'add-your-forecastio-key-here')
.controller('HomeCtrl', function($scope,$state,Weather,DataStore) {
//read default settings into scope
console.log('inside home');
$scope.city = DataStore.city;
var latitude = DataStore.latitude;
var longitude = DataStore.longitude;
//call getCurrentWeather method in factory ‘Weather’
Weather.getCurrentWeather(latitude,longitude).then(function(resp) {
$scope.current = resp.data;
console.log('GOT CURRENT', $scope.current);
}, function(error) {
alert('Unable to get current conditions');
console.error(error);
});
})
.controller('LocationsCtrl', function($scope,$rootScope, $state,DataStore) {
$scope.cities = [];
var data = window.localStorage.getItem('cities');
if (data != null ) {
$scope.cities = null;
$scope.cities = JSON.parse(data);
console.log('using local storage');
}
else {
var cityObj = Parse.Object.extend("City");
var query = new Parse.Query(cityObj);
//query.descending("createdAt"); //specify sorting
//query.limit(20); //specify limit -- fetch only 20 objects
query.find({
success:function(results) {
$scope.$apply(function() {
var index =0;
var Arrlen=results.length ;
for (index = 0; index < Arrlen; ++index) {
var obj = results[index];
$scope.cities.push({
id : obj.id,
name: obj.attributes.name,
lat: obj.attributes.latitude,
lgn: obj.attributes.longitude
});
}
window.localStorage.setItem('cities', JSON.stringify($scope.cities));
});
},
error:function(error) {
console.log("Error retrieving cities!");
}
}); //end query.find
}
$scope.changeCity = function(cityId) {
//get lat and longitude for seleted location
var data = JSON.parse(window.localStorage.getItem('cities'));
var lat = data[cityId].lat; //latitude
var lgn = data[cityId].lgn; //longitude
var city = data[cityId].name; //city name
DataStore.setCity(city);
DataStore.setLatitude(lat);
DataStore.setLongitude(lgn);
$state.go('tab.home');
}
})
.controller('SettingsCtrl', function($scope) {
//manages app settings
});
Here’s what occurs in LocationsCtrl upon initialization.
- Locate an item called
cities
from local storage. - If it’s found, we populate $scope.cities with data from local storage.
- Otherwise, we make a call to Parse for it to fetch objects of type ‘City’ and, upon successful retrieval, we parse (pun fully intended) the data into an array, add it to $scope.cities and store the data in local storage for subsequent use.
The reason we do the above is to ensure that we reduce the number of server calls and work with a local copy of data to improve performance.
The next thing to notice is that the method changeCity
is also modified to use the data from local storage to lookup the selected city’s latitude and longitude.
Save controllers.js
, open www/templates/tab-cities.html
and replace its content the code below.
<ion-view title="Cities">
<ion-content class="has-header">
<h1>Select city</h1>
<ion-list>
<ion-item ng-repeat="city in cities">
<span href="#" ng-click="changeCity('{{$index}}')">
{{city.name}}
</span>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
In the above code, $index
is the iterator offset provided by ng-repeat
. It’s a handy way to access elements in a collection by index.
Lastly open www/js/app.js
and replace its content the code below.
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
.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.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
//initialize parse
Parse.Initialize("add-your-parse-application-Id","add-you-parse-javascript-key");
});
})
.config(function($stateProvider, $urlRouterProvider) {
$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.home', {
url: '/home',
views: {
'tab-home': {
templateUrl: 'templates/tab-home.html',
controller: 'HomeCtrl'
}
}
})
.state('tab.changecity', {
url: '/city',
views: {
'tab-cities': {
templateUrl: 'templates/tab-cities.html',
controller: 'LocationsCtrl'
}
}
})
.state('tab.settings', {
url: '/settings',
views: {
'tab-settings': {
templateUrl: 'templates/tab-settings.html',
controller: 'SettingsCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/home');
});
That’s it. Save the file, then build and run the app from the command line.
$ionic build ios
$ionic run ios
ionic run ios
installs the build on an iOS device. If you don’t have a device handy, you can run the app in an emulator with the following command.
$ionic emulate ios
You can also view the app in a browser. If you don’t have a web server installed, you can use Python’s SimpleHTTPServer. From the terminal, navigate to the www
folder and run the following command.
$python -m SimpleHTTPServer 3000
Now, open your favorite browser and vist http://localhost:3000
. If this doesn’t work, make sure SimpleHTTPServer is installed and that the path is correct.
If all is well, you should see the app run in the browser.
Conclusion
In this article, we’ve seen how easy it is to integrate Parse as a remote backend with Ionic apps. In future tutorials, we’ll see how to add push notifications to an Ionic app.
If you’re unfamiliar with AngularJS, I recommended referring to the AngularJS docs for a better understanding of it. In the mean time, you can donwload this article’s source code on GitHub
Till next time, happy coding!
Author: Sriram Kota