On Github nicobytes / course-ionic2
{
name: 'Nicolas Molina Monroy',
twitter: '@nicobytes',
website: 'https://nicobytes.com',
github: 'https://github.com/nicobytes'
jobs: [
'Hybrid App Developer',
'Front-End Developer'
],
organizer: [
'http://www.meetup.com/es/Hybrid-Apps-Colombia',
'http://www.meetup.com/es/Django-Bogota'
]
}
(You'll feel right at home)
But a lot's changed since its release
Ionic was created 2 years ago....thats ages in web tech
Better/faster devices!
Fewer slow/bad devices!
Widely available web APIs!
Improved browser engines!
Ionic 1 was built with ES5
ES6 brings many new features
NG2 is pushing for ES6
Different look, but all JS Classes
ES6 + ES7 Decorators + Types
Ionic 2 and NG2 built using TS
Code completion in your editor
Why are we still coding for multiple platforms?
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!)
http://techcrunch.com/2012/09/11/mark-zuckerberg-our-biggest-mistake-with-mobile-was-betting-too-much-on-html5/
class Person {
name;
age;
constructor (name, age) {
this.name = name;
this.age = age;
}
getName(){
return this.name;
}
}
export function multiply (x, y) { return x * y }
export var url = 'http://api.domain.com';
import { multiply, url } from "./math"
console.log(multiply(2, 2))
doLogin().then((rta) => {
console.log(rta);
});
doLogin()
.then((rta) => {
console.log(rta);
})
.then((rta) => {
console.log(rta);
})
.then((rta) => {
console.log(rta);
})
.catch((error) => {
console.log(error);
})
for (let i = 0; i < a.length; i++) {
let x = a[i];
}
(function() {
'use strict';
//Code
})();
doLogin((response) => {
console.log(response);
});
//
doLogin(function(response){
console.log(response);
});
class Person {
private name: string;
private age: number;
private single: boolean;
constructor (name, age) {
this.name = name;
this.age = age;
this.sigle = false;
}
getName():string{
return this.name;
}
}
npm install -g ionic@beta cordova
ionic info
ionic start appBlank blank --v2 --ts
ionic start appSide sidemenu --v2 --ts
ionic start appTabs tabs --v2 --ts
ionic platform add android
ionic platform add ios
ionic serve --lab
<input [value]="twitter">
<button (click)="doChange()">
<p> Hola {{twitter}} </p>
<input [value]="twitter" (input)="twitter = $event.target.value">
<input [(ngModel)]="twitter">
<p #myVar></p>
<button (click)="myVar.innerHTML = 'test.'">
ionic start myAwesomeApp --v2 --ts
cd myAwesomeApp
ionic info
ionic serve
ionic build android
ionic build ios
ionic build android --release
ionic build ios --release
ionic emulate android
ionic emulate ios
ionic platform add android
ionic platform add ios
ionic platform add wp
ionic run android
ionic run ios
ionic state save
ionic state restore
ionic resources
ionic plugin add cordova-plugin-XXXXXX
//Examples
ionic plugin add cordova-plugin-camera
ionic plugin add cordova-plugin-googlemaps
ionic plugin add phonegap-plugin-push
npm install moment --save
npm install -g typings
//Now
npm install underscore --save
typings install underscore --ambient --save
@Decorator({
//meta data
})
export class MyClass {
//Your class
}
ionic g --list
ionic g page heroes
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
templateUrl: 'build/pages/heroes/heroes.html',
})
export class HeroesPage {
constructor(private nav: NavController) {
}
}
ionic g component my-hero
import { Component, Input } from '@angular/core';
@Component({
selector: 'my-hero',
templateUrl: 'build/components/my-hero/my-hero.html'
})
export class MyHero {
text: string;
@Input() hero: any;
constructor() {
this.text = 'Hello World';
}
}
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {MyHero} from '../../components/my-hero/my-hero';
@Component({
templateUrl: 'build/pages/heroes/heroes.html',
directives: [MyHero]
})
export class HeroesPage {
<my-hero *ngFor="let hero of heroes" [hero]="hero"></my-hero>
import { Component, Input, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'my-hero',
templateUrl: 'build/components/my-hero/my-hero.html',
encapsulation: ViewEncapsulation.Native
})
ionic g directive my-highlight
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[my-highlight]' // Attribute selector
})
export class MyHighlight {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
<h1 my-highlight>Hola</h1>
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {MyHero} from '../../components/my-hero/my-hero';
import {MyHighlight} from '../../components/my-highlight/my-highlight';
@Component({
templateUrl: 'build/pages/heroes/heroes.html',
directives: [MyHero, MyHighlight]
})
export class HeroesPage {
ionic g pipe reserve
import { Injectable, Pipe } from '@angular/core';
@Pipe({
name: 'reserve'
})
@Injectable()
export class Reserve {
transform(value: string, args: any[]) {
return value.split('').reverse().join('');
}
}
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {MyHero} from '../../components/my-hero/my-hero';
import {MyHighlight} from '../../components/my-highlight/my-highlight';
import {Reserve} from '../../pipes/reserve';
@Component({
templateUrl: 'build/pages/heroes/heroes.html',
directives: [MyHero, MyHighlight],
pipes: [Reserve]
})
export class HeroesPage {
<h1>{{ 'Hola' | reserve }}</h1>
ionic g provider heroes
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class Heroes {
data: any;
constructor(private http: Http) {
this.data = null;
}
load() {
//Code
}
}
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import {MyHero} from '../../components/my-hero/my-hero';
import {MyHighlight} from '../../components/my-highlight/my-highlight';
import {Reserve} from '../../pipes/reserve';
import {HeroesService} from '../../providers/heroes/heroes';
@Component({
templateUrl: 'build/pages/heroes/heroes.html',
directives: [MyHero, MyHighlight],
pipes: [Reserve],
providers: [ HeroesService ]
})
export class HeroesPage {
export class HeroesPage {
heroes: any[];
constructor(
private nav: NavController,
private heroesService: HeroesService
) {
this.heroesService.load();
this.heroes = [
{
name: 'as'
},
{
name: 'as'
}
];
}
}
import {Component} from '@angular/core';
import {Platform, ionicBootstrap} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {TabsPage} from './pages/tabs/tabs';
import {HeroesService} from './providers/heroes/heroes';
@Component({
template: '<ion-nav [root]="rootPage"></ion-nav>'
})
export class MyApp {
private rootPage: any;
constructor(
private platform: Platform,
private heroesService: HeroesService
) {
this.heroesService.load;
}
}
ionicBootstrap(MyApp, [HeroesService]);
// 1.
import { NavController } from 'ionic-angular';
// 2.
constructor(
private nav: NavController,
private heroesService: HeroesService
) {
// 3.
this.nav.push( HeroPage );
// 1.
import { NavController } from 'ionic-angular';
// 2.
constructor(
private nav: NavController,
private heroesService: HeroesService
) {
// 3.
this.nav.pop();
this.nav.setRoot( page );
this.nav.push(somethingPage, {
example1: data1,
example2: data2
});
import {Component} from '@angular/core';
import {NavController, NavParams} from 'ionic-angular';
@Component({
templateUrl: 'build/pages/second/second.html'
})
export class somethingPage {
constructor(nav: NavController, navParams: NavParams){
this.navParams.get('example1');
}
}
<ion-menu [content]="content">
<ion-content>
<ion-list>
<button menuClose ion-item (click)="openTabsPage()">Tabs</button>
<button menuClose ion-item (click)="openHeroesPage()">Heroes</button>
<button menuClose ion-item (click)="close()" >Cerrar </button >
</ion-list>
</ion-content>
</ion-menu>
<ion-nav id="nav" #content [root]="rootPage"></ion-nav>
export class MenuPage {
private rootPage: any;
constructor(private nav: NavController) {
this.rootPage = TabsPage;
}
openHeroesPage(){
this.rootPage = HeroesPage;
}
close(){
this.nav.setRoot( LoginPage );
}
}
<button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
$colors: (
primary: #387ef5,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
favorite: #69BB7B
);
$colors: (
// ...
twitter: #55acee
)
<button twitter>Twitter</button>
$colors: (
// ...
twitter:(
base: #55acee,
contrast: #ffffff
)
)
.home {
p{
background: color($colors, twitter, base);
}
}
$my-padding: 10px;
.home {
p{
background: color($colors, twitter, base);
padding: $my-padding;
}
}
.md button {
background: red;
}
.ios button {
background: blue;
}
.wp button {
background: green;
}
<button [class.myclass]="true">Twitter</button>
<button [attr.no-lines]="true">Twitter</button>
// App iOS Variables
// --------------------------------------------------
// iOS only Sass variables can go here
$button-ios-border-radius: 20px;
@import "../pages/home/home";
@import "../component/my-avatar/my-avatar";
@import "../pages/home/ios/home";
button[primary]{
background: black;
}
<link href="build/font-awesome/css/font-awesome.min.css" rel="stylesheet" >
<form (ngSubmit)="saveData()">
<ion-input type="text" required name="username" [(ngModel)]="model.username"></ion-input>
<ion-input type="text" required name="name" [(ngModel)]="model.name"></ion-input>
<button primary block type="submit">Save</button>
</form>
this.username = new Control(
'Default value',
Validators.required
/*Async*/
);
<input type="text"
ngControl="username"
[(ngModel)]="model.username"
name="username" />
myForm: ControlGroup;
//
constructor(
private formBuilder: FormBuilder
) {
this.username = new Control('', Validators.required);
this.name = new Control('', Validators.required);
this.myForm = this.formBuilder.group({
username: this.username,
name: this.name,
})
<form (ngSubmit)="saveData()" [ngFormModel]="myForm" novalidate>
<ion-input type="text"
name="username"
[(ngModel)]="model.username"
ngControl="username"></ion-input>
<ion-input type="text"
name="name"
[(ngModel)]="model.name" ngControl="name"></ion-input>
<button primary block type="submit">Save</button>
</form>
<div *ngIf="username.dirty && !username.valid">
<p *ngIf="username.errors.required">
Este campo es requerido
</p>
</div>
Validators.compose([
Validators.required,
Validators.minLength(4),
Validators.maxLength(8),
Validators.pattern('[a-zA-Z ]*')
])
this.username = new Control(
'',
Validators.compose([
Validators.required,
Validators.minLength(4),
Validators.maxLength(8),
Validators.pattern('[a-zA-Z ]*')
])
);
this.myForm = this.formBuilder.group({
username: ['', Validators.compose([....])],
name: ['', Validators.compose([....])],
})
<div *ngIf="myForm.controls.username.dirty && !myForm.controls.username.valid">
<p *ngIf="myForm.controls.username.errors.required">
Este campo es requerido
</p>
</div>
<button primary block type="submit" [disabled]="!myForm.valid" >Save</button>
//Or
(ngSubmit)="myForm.valid && saveData()"
import {Control} from '@angular/common';
export class AgeValidator{
static isOld(control: Control){
let value = control.value;
if(value > 18){
return {
'isOld': true
}
}
return null;
}
}
import { AgeValidator } from '../../validators/age';
//Control
age: ['', AgeValidator.isReal]
import { AgeValidator } from '../../validators/age';
//Control
age: ['', AgeValidator.isReal]
return new Promise(resolve => {
this.http.get('https://randomuser.me/api/?results=25')
.map(res => res.json())
.subscribe(data => {
this.data = data.results;
resolve(this.data);
});
});
getAllTodos() {
return new Promise((resolve, reject) => {
this.http.get(`${this.path}/todos?_expand=user`)
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, error =>{
reject(error);
})
});
}
getTodo(id: number){
return new Promise((resolve, reject) => {
this.http.get(`${this.path}/todos/${id}`)
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, error =>{
reject(error);
})
});
}
createTodo(data: any){
return new Promise((resolve, reject) => {
this.http.post(`${this.path}/todos`, data)
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, error =>{
reject(error);
})
});
}
editTodo(data: any){
return new Promise((resolve, reject) => {
this.http.post(`${this.path}/todos`, data)
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, error =>{
reject(error);
})
});
}
deleteTodo(data: any){
return new Promise((resolve, reject) => {
this.http.post(`${this.path}/todos`, data)
.map(res => res.json())
.subscribe(data => {
resolve(data);
}, error =>{
reject(error);
})
});
}
var headers = new Headers();
headers.append('Authorization', 'Basic ----------');
this.http.post('http://api.domain.com/users', data, {
headers: headers
})
"proxies": [
{
"path": "/v1",
"proxyUrl": "https://api.instagram.com/v1"
}
]
import { Storage, LocalStorage } from 'ionic-angular';
@Injectable()
export class TodosService {
todos: Storage;
constructor() {
this.todos = new Storage(LocalStorage);
}
saveTodos( todos ){
this.todos.set('todos', JSON.stringify(todos));
}
getAllTodos() {
return this.todos.get('todos');
}
}
import { Storage, SqlStorage } from 'ionic-angular';
@Injectable()
export class TodosService {
todos: Storage;
constructor() {
this.todos = new Storage( SqlStorage, {name: 'dbname'} );
}
createTable(){
let sql = "CREATE TABLE IF NOT EXISTS todos(id INTEGER PRIMARY KEY AUTOINCREMENT,title VARCHAR(32), done INTEGER)";
this.todos.query( sql )
.then(data => {
console.log( data );
})
.catch(error => {
console.log( error );
})
}
createTodo(data: any){
let sql = `INSERT INTO todos(title, done) values("${data.title}","${data.done}")`;
this.todos.query( sql )
.then(data => {
console.log( data );
})
.catch(error => {
console.log( error );
})
}
getAllTodos():Promise<any>{
let sql = `SELECT * from todos`;
return this.todos.query( sql )
.then(response => {
let data = [];
for (let index = 0; index < response.res.rows.length; index++) {
data.push({
id: response.res.rows[index].id,
title: response.res.rows[index].title,
completed: response.res.rows[index].done == "true" ? true : false
});
}
return Promise.resolve( data );
})
.catch(error => {
return Promise.reject(error)
})
}
npm install angularfire2 --save
npm install firebase --save
npm install typings -g
typings install --save firebase
typings/index.d.ts
/// <reference path="../node_modules/angularfire2/firebase3.d.ts" />
import {FIREBASE_PROVIDERS, defaultFirebase} from 'angularfire2';
ionicBootstrap(MyApp, [
FIREBASE_PROVIDERS,
defaultFirebase({
apiKey: "------------",
authDomain: "------------",
databaseURL: "------------",
storageBucket: "------------",
}),
]);
{
"rules": {
".read": true,
".write": true
}
}
import { Injectable } from '@angular/core';
import { FirebaseListObservable, AngularFire } from 'angularfire2';
@Injectable()
export class TodosService {
todos: FirebaseListObservable<any>
constructor(
private af: AngularFire
) {
this.todos = this.af.database.list('/todos');
}
getAllTasks(){
return this.todos;
}
getAllTodos(){
return this.todos;
}
createTodo(todo: any){
return this.todos.push( todo );
}
updateTodo(task: any){
return this.todos.update( task.$key, {
title: task.title,
completed: task.completed
});
}
updateTodo(task: any){
return this.todos.update( task.$key, {
title: task.title,
completed: task.completed
});
}
removeTodo(task: any){
return this.todos.remove( task.$key );
}
android
ionic plugin add xxxx-xxx--xxxx --save
adb devices
adb start-server
adb kill-server
ionic run android
ionic run ios
ionicBootstrap(MyApp, [ Providers ], {
prodMode: true
});
ionic resources
<?xml version='1.0' encoding='utf-8'?>
<widget id="io.ionic.starter" version="0.0.1" xmlns="http://www.w3.org/ns/
widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>V2 Test</name>
<description>An Ionic Framework and Cordova project.</description>
<author email="hi@ionicframework" href="http://ionicframework.com/">Ionic
Framework Team</author>
keytool -genkey -v -keystore my-release-key.keystore -alias upload -keyalg RSA -keysize 2048 -validity 10000
Ionic build android --release
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore platforms/android/build/outputs/apk/android-release-unsigned.apk upload
zipalign -v 4 platforms/android/build/outputs/apk/android-release-unsigned.apk upload.apk
openssl genrsa -out mykey.key 2048
openssl req -new -key mykey.key -out myCSR.certSigningRequest -subj "/emailAddress=you@yourdomain.com, CN=Your Name, C=AU"
Open Keychain Access
Open .cer > Export .p12
openssl x509 -in ios_development.cer -inform DER -out app_pem_file.pem -outform PEM
openssl pkcs12 -export -inkey mykey.key -in app_pem_file.pem -out app_p12.p12
ionic build ios