ionic2 - the raise of web developer, riviera dev le 17/06/2016
TRANSCRIPT
Loïc KnuchelGeek passionné
Freelance
Développeur web full-stack
Entrepreneur
Cookers / SalooN
@loicknuchel
http://loic.knuchel.org/
● Nouvelle stack technique
● Peu de personnes formées
● Développer plusieurs fois la même chose
● Environnements très spécifiques (offline, puissance, versions, diversité...)
Idée
Coder des applicationsentièrement dans la WebView
Avantages :
● Technologies et environnements connus● Cross-platform
PhoneGap / Cordova
Mars 2009 :Lancement de PhoneGap par Nitobi
Octobre 2011 :Rachat de Nitobi par AdobeSéparation de la technologie (Cordova) et des services commerciaux (PhoneGap)
Oups...● UI moche● UI peu réactive● loin du look & feel natif
Mauvais support des standards du web dans la WebView
Peu d’outils / librairies
Téléphones peu puissants
● App de mauvaise qualité● Bugs
Souvent pour des projets à petit budget...
Aujourd’hui
● Téléphones puissants (et de + en +)
● Très bon support des standards web dans la WebView
● Beaucoup d’outils / librairies
Stack technologique
Natif
Web
Téléphone & APIs natives
Cordova : webview +JavaScript bridges
Angular
Ionic
Application
DX“We want to cater to the 99% who just want to build something functional quickly
and not break the bank to do it.” - Max Lynch
DX#Platform continuity
#CLI
#Backend services
#Push#Deploy
#Package#Auth#Analytics #Ionic View
#Native plugins #Ionic Market
#Ionic Creator
Hybrid superpowers
Web App :
● Cross-platform● Accès instantané● Deep link● Offline
http://bit.ly/voxxrin-bdx-lkn
Hybrid superpowers
Web App :
● Cross-platform● Accès instantané● Deep link● Offline
Progressive Web App :
● Installation instantanée● Lancement depuis la Home● Push notifications
Hybrid superpowers
Web App :
● Cross-platform● Accès instantané● Deep link● Offline
Progressive Web App :
● Installation instantanée● Lancement depuis la Home● Push notifications
Native App :
● Accès complet au téléphone
Nouveautés depuis Ionic 1
● Angular 2 (+ TypeScript)● Navigation push/pop● Nouveaux composants
○ DateTime○ Toast○ Searchbar○ Segment
Getting started
Install nodejs & npm
$ npm install -g ionic@beta
$ ionic start demoApp --v2 --ts
$ cd demoApp && ionic serve
♬ ♫ ♬ ♫ Your Ionic app is ready to go! ♬ ♫ ♬ ♫
Getting started
Install mobile sdk (Android ou iOS)
$ sudo npm install -g cordova
$ ionic platform add android
$ ionic run android
index.html<!DOCTYPE html><html lang="en" dir="ltr"><head> <meta charset="UTF-8"> <title>Ionic</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="format-detection" content="telephone=no"> <meta name="msapplication-tap-highlight" content="no">
<link ios-href="build/css/app.ios.css" rel="stylesheet"> <link md-href="build/css/app.md.css" rel="stylesheet"> <link wp-href="build/css/app.wp.css" rel="stylesheet"></head><body> <!-- this Ionic's root component and where the app will load --> <ion-app></ion-app>
<!-- cordova.js required for cordova apps --> <script src="cordova.js"></script> <!-- Polyfill needed for platforms without Promise and Collection support --> <script src="build/js/es6-shim.min.js"></script> <!-- Zone.js and Reflect-metadata --> <script src="build/js/Reflect.js"></script> <script src="build/js/zone.js"></script> <!-- the bundle which is built from the app's source code --> <script src="build/js/app.bundle.js"></script></body></html>
app.tsimport {App, Platform} from 'ionic-angular';import {StatusBar} from 'ionic-native';import {TabsPage} from './pages/tabs/tabs';
@App({ template: '<ion-nav [root]="rootPage"></ion-nav>', config: {} // http://ionicframework.com/docs/v2/api/config/Config/})export class MyApp { rootPage: any = TabsPage;
constructor(platform: Platform) { platform.ready().then(() => { // Okay, so the platform is ready and our plugins are available. // Here you can do any higher level native things you might need. StatusBar.styleDefault(); }); }}
page1.tsimport {Page} from 'ionic-angular';
@Page({ templateUrl: 'build/pages/page1/page1.html'})export class Page1 { constructor() {
}}
<ion-navbar *navbar> <ion-title>Tab 1</ion-title></ion-navbar>
<ion-content padding class="page1"> <h2>Welcome to Ionic!</h2> <p> This starter project comes with simple tabs-based layout for apps that are going to primarily use a Tabbed UI. </p> <p> Take a look at the <code>app/</code> directory to add or change tabs, update any existing page or create new pages. </p></ion-content>
page1.tsimport {Page} from 'ionic-angular';
@Page({ template: `<ion-navbar *navbar> <ion-title>Tab 1</ion-title></ion-navbar>
<ion-content padding class="page1"> <h2>Welcome to Ionic!</h2> <p> This starter project comes with simple tabs-based layout for apps that are going to primarily use a Tabbed UI. </p></ion-content>`})export class Page1 { constructor() {}}
page1.tsimport {Page} from 'ionic-angular';
@Page({ styles: [`.page1 h2 { color: red;} `], template: `...`})export class Page1 { constructor() {}}
Angular 1 vs Angular 2
● bootstrap manuel
● Filter => Pipe
● Controllers => Components
● Directives => Components
● $scope => Class properties
● Services => Injectables
Template
● Bindings :
● Pipes :
● Propriétés / Input :
● Evénements / Output :
● Double binding :
● Templates :
● Local variables :
● Boucles :
Your favorite hero is: {{favoriteHero}}
<span>{{movie.title | uppercase}}</span>
<a [href]="angularDocsUrl">Angular Docs</a>
<button (click)="toggleMovie()"></button>
<input [(ngModel)]="favoriteMovie" />
<div *ngIf="movies.length === 0">No movies</div>
<video-player #player></video-player><button (click)="player.pause()">Pause</button>
<ul *ngFor="let movie of movies"> <li>{{movie.title}}</li></ul>
todo.page.ts todo.html todo.scssimport {Page} from 'ionic-angular';
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { constructor() { }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-content class="todo-page">
</ion-content>
.todo-page { .done { text-decoration: line-through; }}
import {App, Platform} from 'ionic-angular';import {StatusBar} from 'ionic-native';import {TabsPage} from './pages/tabs/tabs';import {TodoPage} from "./pages/todo/todo.page";
@App({ template: '<ion-nav [root]="rootPage"></ion-nav>', config: {}})export class MyApp { rootPage: any = TodoPage;
constructor(platform: Platform) { platform.ready().then(() => { StatusBar.styleDefault(); }); }}
// http://ionicframework.com/docs/v2/theming/
// App Shared Imports// --------------------------------------------------// These are the imports which make up the design of this app.// By default each design mode includes these shared imports.// App Shared Sass variables belong in app.variables.scss.
@import "../pages/page1/page1";@import "../pages/page2/page2";@import "../pages/page3/page3";@import "../pages/todo/todo";
app.ts theme/app.core.scss
Ionic2 TODO listimport {Page} from 'ionic-angular';
class Todo { constructor( public name: string, public done: boolean = false ) {}}
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { constructor() { }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-content class="todo-page">
</ion-content>
Ionic2 TODO listimport {Page} from 'ionic-angular';
class Todo { constructor( public name: string, public done: boolean = false ) {}}
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { todos: Todo[] = [ new Todo('todo 1'), new Todo('todo 2'), new Todo('todo 3') ];
constructor() { }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-content class="todo-page">
</ion-content>
Ionic2 TODO list<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-content class="todo-page"> <ion-list> <ion-item *ngFor="let todo of todos" [hidden]="todo.done"> <ion-label>{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item> <ion-item *ngFor="let todo of todos" [hidden]="!todo.done"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done" disabled="true"></ion-checkbox> </ion-item> </ion-list></ion-content>
Ionic2 TODO listimport {Page} from 'ionic-angular';
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { newTodo: string = ''; todos: Todo[] = [ new Todo('todo 1'), new Todo('todo 2'), new Todo('todo 3') ];
constructor() { }
create(text: string): void { this.todos.push(new Todo(text)); this.newTodo = ''; }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-toolbar> <ion-input type="text" [(ngModel)]="newTodo" placeholder="Nouvelle tâche"> </ion-input> <ion-buttons end> <button (click)="create(newTodo)"> <ion-icon name="send"></ion-icon> </button> </ion-buttons></ion-toolbar>
<ion-content class="todo-page"> <ion-list> ... </ion-list></ion-content>
Ionic2 TODO listimport {Page} from 'ionic-angular';
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { newTodo: string = ''; todos: Todo[] = [...];
constructor() { }
create(text: string): void { ... }
delete(todo: Todo): void { const i = this.todos.indexOf(todo); if(i >= 0) { this.todos.splice(i, 1); } }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-toolbar> ...</ion-toolbar>
<ion-content class="todo-page"> <ion-list> <ion-item *ngFor="let todo of todos" [hidden]="todo.done"> <ion-label>{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item> <ion-item *ngFor="..." [hidden]="!todo.done" (click)="delete(todo)"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done" disabled="true"></ion-checkbox> </ion-item> </ion-list></ion-content>
Ionic2 TODO listimport {Page} from 'ionic-angular';
@Page({ templateUrl: 'build/pages/todo/todo.html'})export class TodoPage { newTodo: string = ''; todos: Todo[] = [...];
constructor() { }
create(text: string): void { ... }
delete(todo: Todo): void { const i = this.todos.indexOf(todo); if(i >= 0) { this.todos.splice(i, 1); } }}
<ion-navbar *navbar> <ion-title>Todos</ion-title></ion-navbar>
<ion-toolbar> ...</ion-toolbar>
<ion-content class="todo-page"> <ion-list> <ion-item *ngFor="let todo of todos" [hidden]="todo.done"> <ion-label>{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item> <ion-item *ngFor="..." [hidden]="!todo.done" (click)="delete(todo)"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done" disabled="true"></ion-checkbox> </ion-item> </ion-list></ion-content>
Pour tester ce weekend...
http://ionicframework.com/docs/v2/
https://github.com/driftyco/ionic-conference-app
https://github.com/saloonapp/saloon-app
http://mcgivery.com/15-ionic-framework-2-resources/ (60+ maintenant…)
https://angular.io/docs/ts/latest/cookbook/
https://forum.ionicframework.com/
http://loic.knuchel.org/blog/