“I want to build an app!”
HTML5 that acts like native
Web wrapped in native layer
Direct access to native APIs
Familiar web dev environment
A single code base (web platform!)
“It's not 2007 anymore”
Year | Device | Processor | RAM |
---|---|---|---|
2007 | iPhone | 400 MHz | 128 MB |
2010 | iPhone 4 | 1 GHz | 512 MB |
2015 | iPhone 6 | 1.4 GHz dual-core | 1 GB |
(You'll feel right at home)
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.search', {
url: '/search',
views: {
'menuContent': {
templateUrl: 'templates/search.html'
}
},
})
.state('app.browse', {
url: '/browse',
views: {
'menuContent': {
templateUrl: 'templates/browse.html',
controller: 'BrowseCtrl'
}
},
})
$urlRouterProvider.otherwise('/app/browse');
});
State-Based Router with Nested Views
<div class="list card">
<div class="item item-body card-body">
<div class="image-container">
<img src="{{postData.image}}" alt="" />
</div>
<div class="content-container">
<div class="description">{{postData.description}}</div>
<div class="" ng-if="postData.comments.length">
<button class="button button-clear button-positive" ng-click="toggleComments()">
...
</button>
<div class="item item-text-wrap" ng-show="commentsVisible" ng-repeat="comment in postData.comments track by $index">
{{comment}}
</div>
</div>
<div ng-show="commentFieldVisible">
<div class="item item-input-inset" ng-show="commentFieldVisible">
<label class="item-input-wrapper">
<input type="text" placeholder="Add a comment" ng-model="newComment">
</label>
<button class="button button-small button-balanced" ng-click="addComment()">Submit</button>
</div>
</div>
<div class="button-bar">
...
</div>
</div>
</div>
</div>
It's just Angular.js! (No extra learning curve)
.directive('postCard', function() {
return {
restrict: 'E',
templateUrl: 'templates/post-card.html',
scope: {
postData: "=",
},
controller: function($scope, $element) {
// Some controller logic
}
};
});
.controller('BrowseCtrl', function($scope) {
$scope.posts = [
{ image: 'img/arya.jpg', description: "" },
{ image: 'img/jon-snow.jpg', description: "" },
{ image: 'img/tyrion.jpg', description: "" },
{ image: 'img/daenerys.jpg', description: "" },
];
})
...
<ion-content>
<post-card ng-repeat="post in posts" post-data="post"></post-card>
</ion-content>
...
npm install -g ionic cordova
Boilerplate app structure ready for customization
LiveReload both local and native builds
Build and run native apps
js/app.js
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.browse', {
url: '/browse',
views: {
'menuContent': {
templateUrl: 'templates/browse.html',
controller: 'BrowseCtrl'
}
},
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/browse');
})
.controller('AppCtrl', function($scope) {})
.controller('BrowseCtrl', function($scope) {});
/templates/browse.html
<ion-view view-title="Browse">
<ion-content>
<h2>Browse</h2>
</ion-content>
</ion-view>
/templates/menu.html
<ion-side-menus enable-menu-with-back-views="false">
<ion-side-menu-content>
<ion-nav-bar class="bar-positive">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-toggle="left">
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>
<ion-side-menu side="left">
<ion-content>
<ion-list>
<ion-item menu-close href="#/app/browse">
Browse
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
/templates/post-card.html
<div class="list card">
<div class="item item-body card-body">
<div class="image-container">
<img src="{{postData.image}}" alt="" />
</div>
<div class="content-container">
<div class="description">{{postData.description}}</div>
<div class="" ng-if="postData.comments.length">
<button class="button button-clear button-positive" ng-click="toggleComments()">
...
</button>
<div class="item item-text-wrap" ng-show="commentsVisible" ng-repeat="comment in postData.comments track by $index">
{{comment}}
</div>
</div>
<div ng-show="commentFieldVisible">
<div class="item item-input-inset" ng-show="commentFieldVisible">
<label class="item-input-wrapper">
<input type="text" placeholder="Add a comment" ng-model="newComment">
</label>
<button class="button button-small button-balanced" ng-click="addComment()">Submit</button>
</div>
</div>
<div class="button-bar">
...
</div>
</div>
</div>
</div>
/js/app.js
.controller('BrowseCtrl', function($scope) {
$scope.posts = [
{ image: 'img/arya.jpg', description: "..." },
{ image: 'img/jon-snow.jpg', description: "..." },
{ image: 'img/tyrion.jpg', description: "..." },
{ image: 'img/daenerys.jpg', description: "..." },
];
})
/templates/browse.html
<ion-view view-title="Browse">
<ion-content class="animate-fade-slide-in">
<post-card ng-repeat="p in posts" post-data="p"></post-card>
</ion-content>
</ion-view>
/js/app.js
.directive('postCard', function($ionicActionSheet, $ionicPopup, $timeout) {
return {
restrict: 'E',
templateUrl: 'templates/post-card.html',
scope: {
postData: "=",
},
controller: function($scope, $element) {
$scope.commentsVisible = false;
$scope.commentFieldVisible = false;
$scope.postData.comments = $scope.postData.comments || [];
$scope.toggleLike = function() { ...
$scope.addComment = function() { ...
$scope.showOptions = function() { ...
}
};
});
Providers and Service Objects
js/app.js
.factory('Post', function($resource) {
return $resource('http://my-awesome-REST-API.com/post');
})
js/app.js
.controller('BrowseCtrl', function($scope, Post) {
// Get all posts
$scope.posts = Post.query();
})
1. Install ngResource via Bower (optional)
$ bower install ng-resource --save
2. Add dependency to index.html (optional)
<script src="lib/ng-resource/<path to>/ng-resource.js"></script>
3. Include in Angular app dependencies (optional)
angular.module('ionicApp', ['ionic', 'ngResource'])
AdMob | Device | Keychain | Social Sharing |
App Availability | Device Motion | NativeAudio | Spinner |
BackgroundGeolocation | Device Orientation | Media | Splashscreen |
Battery Status | Dialogs | Local Notification | SQLite |
Barcode Scanner | File | Network | Statusbar |
Camera | Flashlight | OAuth | Toast |
Capture | Geolocation | Pin Dialog | Touch ID |
Clipboard | Globalization | Printer | Vibration |
Contacts | GoogleAnalytics | Progress Indicator | Zip |
DatePicker | Keyboard | Push Notifications | More... |
bower install ngCordova --save-dev
lib/ngCordova/dist/ng-cordova.js
angular.module('starter', ['ionic','ngCordova'])
ionic plugin add org.apache.cordova.camera
.controller('AppCtrl', function($scope, $cordovaCamera) {
document.addEventListener("deviceready", function () {
var options = {
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 100,
targetHeight: 100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false,
correctOrientation:true
};
$scope.getPicture = function() {
$cordovaCamera.getPicture(options).then(function(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
}, function(err) {
// error
});
};
}, false);
});
<ion-nav-buttons side="right">
<button class="button button-icon button-clear ion-plus"
menu-toggle="right"
ng-click="getPicture()"></button>
</ion-nav-buttons>
Taking a photo
Getting started guide
ionicframework.com/getting-started
Documentation
ionicframework.com/docs
Visit the Community Forum
forum.ionicframework.com
Contribute on GitHub
github.com/driftyco/ionic
</html>