Creating an Ionic App
In the previous chapters, we have learned how to import the Ionic framework into our project.
Next, we will introduce how to create an Ionic app.
Creating an Ionic app uses HTML, CSS, and JavaScript. So, we can create a www
directory and an index.html
file within it, with the following code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Todo</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- File included in apps created with Cordova/PhoneGap, provided by Cordova/PhoneGap (shows 404 during development) -->
<script src="cordova.js"></script>
</head>
<body>
</body>
</html>
In the above code, we have included the Ionic CSS file, Ionic JS file, and the Ionic AngularJS extension ionic.bundle.js
.
The ionic.bundle.js
file already includes the Ionic core JS, AngularJS, and Ionic's AngularJS extensions. If you need to include other Angular modules, you can call them from the lib/js/angular
directory.
The cordova.js
file is generated when using Cordova/PhoneGap to create an app and does not need to be manually included. You can find this file in your Cordova/PhoneGap project, so it is normal to show a 404 during development.
Creating the App
Next, we will implement an app that includes a title, sidebar, list, etc., as shown in the design below:
Creating the Sidebar
The sidebar is created using the ion-side-menus
controller.
Edit the previously created index.html
file and modify the content inside the <body>
tag as follows:
<body>
<ion-side-menus>
<ion-side-menu-content>
</ion-side-menu-content>
<ion-side-menu side="left">
</ion-side-menu>
</ion-side-menus>
</body>
Controller explanation:
- ion-side-menus: A container with side menus that can be expanded by clicking a button or swiping the screen.
- ion-side-menu-content: A container for the main content that can be expanded by swiping the screen.
- ion-side-menu: A container for the sidebar.
Initializing the App
Next, we create a new AngularJS module and initialize it. The code is located in www/js/app.js
:
angular.module('todo', ['ionic'])
<body ng-app="todo">
Include the app.js
file above the <script src="cordova.js"></script>
in the index.html
file:
<script src="js/app.js"></script>
Modify the content of the body
tag in the index.html
file as follows:
<body ng-app="todo">
<ion-side-menus>
<!-- Center content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<h1 class="title">Todo</h1>
</ion-header-bar>
<ion-content>
</ion-content>
</ion-side-menu-content>
<!-- Left menu -->
<ion-side-menu side="left">
<ion-header-bar class="bar-dark">
<h1 class="title">Projects</h1>
</ion-header-bar>
<ion-content>
</ion-content>
</ion-side-menu>
</ion-side-menus>
</body>
</ion-header-bar>
</ion-side-menu>
</ion-side-menus>
</body>
Following the steps above, we have completed the basic setup of an Ionic app.
Creating a List
First, create a controller TodoCtrl:
<body ng-app="todo" ng-controller="TodoCtrl">
In the app.js file, define the list data using the controller:
angular.module('todo', ['ionic'])
.controller('TodoCtrl', function($scope) {
$scope.tasks = [
{ title: 'tutorialpro.org' },
{ title: 'www.tutorialpro.org' },
{ title: 'tutorialpro.org' },
{ title: 'www.tutorialpro.org' }
];
});
In the index.html page, use Angular ng-repeat to iterate over the data for the list:
<!-- Center content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<h1 class="title">Todo</h1>
</ion-header-bar>
<ion-content>
<!-- List -->
<ion-list>
<ion-item ng-repeat="task in tasks">
{{task.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu-content>
The modified code within the body tag of index.html is as follows:
<body ng-app="todo" ng-controller="TodoCtrl">
<ion-side-menus>
<!-- Center content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<h1 class="title">Todo</h1>
</ion-header-bar>
<ion-content>
<!-- List -->
<ion-list>
<ion-item ng-repeat="task in tasks">
{{task.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu-content>
<!-- Left menu -->
<ion-side-menu side="left">
<ion-header-bar class="bar-dark">
<h1 class="title">Projects</h1>
</ion-header-bar>
</ion-side-menu>
</ion-side-menus>
<script src="http://www.tutorialpro.org/static/ionic/js/app.js"></script>
<script src="cordova.js"></script>
</body>
Creating an Add Page
Modify index.html by adding the following code after </ion-side-menus>:
<script id="new-task.html" type="text/ng-template">
<div class="modal">
<!-- Modal header bar -->
<ion-header-bar class="bar-secondary">
<h1 class="title">New Task</h1>
<button class="button button-clear button-positive" ng-click="closeNewTask()">Cancel</button>
</ion-header-bar>
<!-- Modal content area -->
<ion-content>
<form ng-submit="createTask(task)">
<div class="list">
<label class="item item-input">
<input type="text" placeholder="What do you need to do?" ng-model="task.title">
</label>
</div>
<div class="padding">
<button type="submit" class="button button-block button-positive">Create Task</button>
</div>
</form>
</ion-content>
</div>
</script>
In the above code, we define a new template page using <script id="new-task.html" type="text/ng-template">.
The form submission triggers the createTask(task) function.
ng-model="task.title" assigns the form input data to the title property of the task object.
Modify the content within <ion-side-menu-content> as follows:
<!-- Center content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<h1 class="title">Todo</h1>
<!-- New button -->
<button class="button button-icon" ng-click="newTask()">
<i class="icon ion-compose"></i>
</button>
</ion-header-bar>
<ion-content>
<!-- List -->
<ion-list>
<ion-item ng-repeat="task in tasks">
{{task.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu-content>
In the app.js file, the controller code is as follows:
angular.module('todo', ['ionic'])
.controller('TodoCtrl', function($scope, $ionicModal) {
$scope.tasks = [
{ title: 'tutorialpro.org' },
{ title: 'www.tutorialpro.org' },
{ title: 'tutorialpro.org' },
{ title: 'www.tutorialpro.org' }
];
// Create and load the modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope,
animation: 'slide-in-up'
});
// Call on form submission
$scope.createTask = function(task) {
$scope.tasks.push({
title: task.title
});
$scope.taskModal.hide();
task.title = "";
};
// Open the new modal
$scope.newTask = function() {
$scope.taskModal.show();
};
// Close the new modal
$scope.closeNewTask = function() {
$scope.taskModal.hide();
};
});
Creating a Sidebar
With the above steps, we have implemented the new task feature. Now, we will add a sidebar functionality to the app.
<!-- Main Content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<button class="button button-icon" ng-click="toggleProjects()">
<i class="icon ion-navicon"></i>
</button>
<h1 class="title">{{activeProject.title}}</h1>
<!-- Add Button -->
<button class="button button-icon" ng-click="newTask()">
<i class="icon ion-compose"></i>
</button>
</ion-header-bar>
<ion-content scroll="false">
<ion-list>
<ion-item ng-repeat="task in activeProject.tasks">
{{task.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu-content>
Add Sidebar:
<!-- Left Sidebar -->
<ion-side-menu side="left">
<ion-header-bar class="bar-dark">
<h1 class="title">Projects</h1>
<button class="button button-icon ion-plus" ng-click="newProject()">
</button>
</ion-header-bar>
<ion-content scroll="false">
<ion-list>
<ion-item ng-repeat="project in projects" ng-click="selectProject(project, $index)" ng-class="{active: activeProject == project}">
{{project.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
The ng-class
directive in <ion-item>
sets the active menu style.
Here we create a new JS file app2.js
(to avoid confusion with the previous one), with the following code:
angular.module('todo', ['ionic'])
/**
* The Projects factory handles saving and loading projects
* from local storage, and also lets us save and load the
* last active project index.
*/
.factory('Projects', function() {
return {
all: function() {
var projectString = window.localStorage['projects'];
if(projectString) {
return angular.fromJson(projectString);
}
return [];
},
save: function(projects) {
window.localStorage['projects'] = angular.toJson(projects);
},
newProject: function(projectTitle) {
// Add a new project
return {
title: projectTitle,
tasks: []
};
},
getLastActiveIndex: function() {
return parseInt(window.localStorage['lastActiveProject']) || 0;
},
setLastActiveIndex: function(index) {
window.localStorage['lastActiveProject'] = index;
}
}
})
.controller('TodoCtrl', function($scope, $timeout, $ionicModal, Projects, $ionicSideMenuDelegate) {
// A utility function for creating a new project
// with the given projectTitle
var createProject = function(projectTitle) {
var newProject = Projects.newProject(projectTitle);
$scope.projects.push(newProject);
Projects.save($scope.projects);
$scope.selectProject(newProject, $scope.projects.length-1);
}
// Load or initialize projects
$scope.projects = Projects.all();
// Grab the last active, or the first project
$scope.activeProject = $scope.projects[Projects.getLastActiveIndex()];
// Called to create a new project
$scope.newProject = function() {
var projectTitle = prompt('Project name');
if(projectTitle) {
createProject(projectTitle);
}
};
// Called to select the given project
$scope.selectProject = function(project, index) {
$scope.activeProject = project;
Projects.setLastActiveIndex(index);
$ionicSideMenuDelegate.toggleLeft(false);
};
// Create our modal
$ionicModal.fromTemplateUrl('new-task.html', function(modal) {
$scope.taskModal = modal;
}, {
scope: $scope
});
$scope.createTask = function(task) {
if(!$scope.activeProject || !task) {
return;
}
$scope.activeProject.tasks.push({
title: task.title
});
$scope.taskModal.hide();
// Inefficient, but save all the projects
Projects.save($scope.projects);
task.title = "";
};
$scope.newTask = function() {
$scope.taskModal.show();
};
$scope.closeNewTask = function() {
$scope.taskModal.hide();
}
$scope.toggleProjects = function() {
$ionicSideMenuDelegate.toggleLeft();
};
// Try to create the first project, make sure to defer
// this by using $timeout so everything is initialized
// properly
$timeout(function() {
if($scope.projects.length == 0) {
while(true) {
var projectTitle = prompt('Your first project title:');
if(projectTitle) {
createProject(projectTitle);
break;
}
}
}
});
});
<ion-side-menus>
<!-- Center Content -->
<ion-side-menu-content>
<ion-header-bar class="bar-dark">
<button class="button button-icon" ng-click="toggleProjects()">
<i class="icon ion-navicon"></i>
</button>
<h1 class="title">{{activeProject.title}}</h1>
<!-- New Button -->
<button class="button button-icon" ng-click="newTask()">
<i class="icon ion-compose"></i>
</button>
</ion-header-bar>
<ion-content scroll="false">
<ion-list>
<ion-item ng-repeat="task in activeProject.tasks">
{{task.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu-content>
<!-- Left Sidebar -->
<ion-side-menu side="left">
<ion-header-bar class="bar-dark">
<h1 class="title">Projects</h1>
<button class="button button-icon ion-plus" ng-click="newProject()">
</button>
</ion-header-bar>
<ion-content scroll="false">
<ion-list>
<ion-item ng-repeat="project in projects" ng-click="selectProject(project, $index)" ng-class="{active: activeProject == project}">
{{project.title}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>