SlideShare a Scribd company logo
1 of 106
Download to read offline
The rise of web developers
le 21/10/2016, ionic 2.0-rc1 @loicknuchel
Loïc Knuchel
Geek passionné
Développeur Scala
Organisateur
loicknuchel@gmail.com
@loicknuchel
http://loic.knuchel.org/
L’histoire du smartphone
Juin 2007
Lancement de l’iPhone 1
Septembre 2008
Sortie du HTC G1
avec Android
● Nouvelles possibilités
○ UX
○ Technique
○ Business
● Un écosystème à bâtir
● 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é...)
La WebView
Idée
Coder des applications
entièrement dans la WebView
Idée
Coder des applications
entièrement dans la WebView
Avantages :
● Cross-platform
● Technologies et environnements connus
PhoneGap / Cordova
Mars 2009 :
Lancement de PhoneGap par Nitobi
Octobre 2011 :
Rachat de Nitobi par Adobe
Sé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
Native develoment is ...
way ...
Performance
Code re-write
Complicated
Android Menu (Nav Drawer)
Source: https://developer.android.com/training/implementing-navigation/nav-drawer.html
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch(item.getItemId()) {
case R.id.action_websearch:
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(this, R.string.app_not_available,
Toast.LENGTH_LONG).show();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
Fragment fragment = new PlanetFragment();
Bundle args = new Bundle();
args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame,
fragment).commit();
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
...
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPlanetTitles;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
mPlanetTitles = getResources().getStringArray(R.array.planets_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close
) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
}
...
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
...
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
public static class PlanetFragment extends Fragment {
public static final String ARG_PLANET_NUMBER = "planet_number";
public PlanetFragment() {}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_planet,
container, false);
int i = getArguments().getInt(ARG_PLANET_NUMBER);
String planet =
getResources().getStringArray(R.array.planets_array)[i];
int imageId =
getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
"drawable", getActivity().getPackageName());
((ImageView)
rootView.findViewById(R.id.image)).setImageResource(imageId);
getActivity().setTitle(planet);
return rootView;
}
}
}
onCreate
onDrawerClosed
onDrawerOpened
onPrepareOptionsMenu
onCreateOptionsMenu
onPostCreate
onConfigurationChanged
onCreateView
onOptionsItemSelected
onItemClick
selectItem
MenuInflater
DrawerLayout
ActionBarDrawerToggle
Bundle
AdapterView
ImageView
Fragment
FragmentManager
PlanetFragment
App Store installs are broken !
?
http://bit.ly/voxxrin
App Store installs are broken !
App Store installs are broken !
Ionic c’est quoi ?
+ =
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
Ionic is a complete ecosystem !
One more thing...
Hybrid apps have superpowers...
Hybrid superpowers
●
Hybrid superpowers
Web App :
● Cross-platform
● Searchable
● Accès instantané
● Deep link
100 %
http://bit.ly/voxxrin-bdx-lkn
Hybrid superpowers
Web App :
● Cross-platform
● Searchable
● Accès instantané
● Deep link
Progressive Web App :
● Installation instantanée
● Lancement depuis la Home
● Offline
● Push notifications
Hybrid superpowers
Web App :
● Cross-platform
● Searchable
● Accès instantané
● Deep link
Progressive Web App :
● Installation instantanée
● Lancement depuis la Home
● Offline
● Push notifications
Native App :
● Accès complet au téléphone
Hybrid superpowers
●
App Store deployment is broken !
Google : ~ 2 heures
Apple : ~ 2 jours
Hybrid superpowers
●
Getting started
Install nodejs & npm
$ npm install -g ionic
$ ionic start demoApp --v2
$ 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 run android
src/index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Ionic App</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 rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#4e8ef7">
<link href="build/main.css" rel="stylesheet">
</head>
<body>
<ion-app></ion-app> <!-- Ionic's root component and where the app will load -->
<script src="cordova.js"></script> <!-- cordova.js required for cordova apps -->
<script src="build/polyfills.js"></script> <!-- polyfills generated during the build process -->
<script src="build/main.js"></script> <!-- bundle generated during the build process -->
</body>
</html>
src/app/main.dev.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
src/app/app.module.ts
import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
@NgModule({
declarations: [MyApp, HomePage],
imports: [IonicModule.forRoot(MyApp)],
bootstrap: [IonicApp],
entryComponents: [MyApp, HomePage],
providers: []
})
export class AppModule {}
src/app/app.component.ts
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from 'ionic-native';
import { HomePage } from '../pages/home/home';
@Component({
template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage = HomePage;
constructor(platform: Platform) {
platform.ready().then(() => {
StatusBar.styleDefault();
});
}
}
src/pages/home/home.ts
<ion-header>
<ion-navbar>
<ion-title>Ionic Blank</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
The world is your oyster.
<p>
If you get lost, the <a
href="http://ionicframework.com/docs/v2">docs</
a> will be your guide.
</p>
</ion-content>
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController) {}
}
src/pages/home/home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
template: `
<ion-header>
<ion-navbar>
<ion-title>Ionic Blank</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
The world is your oyster.
<p>
If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will be your guide.
</p>
</ion-content>`
})
export class HomePage {
constructor(public navCtrl: NavController) {}
}
$ ionic start todo-app --v2
Créer une nouvelle page
$ ionic g page todo-list
src/pages/todo-list
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
constructor(public navCtrl: NavController) {}
ionViewDidLoad() {
console.log('Hello TodoList Page');
}
}
<ion-header>
<ion-navbar>
<ion-title>
todo-list
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
</ion-content>
page-todo-list {
}
todo-list.ts todo-list.html todo-list.scss
import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from
'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { TodoList } from
"../pages/todo-list/todo-list";
@NgModule({
declarations: [MyApp, HomePage, TodoList],
imports: [IonicModule.forRoot(MyApp)],
bootstrap: [IonicApp],
entryComponents: [MyApp, HomePage, TodoList],
providers: []
})
export class AppModule {}
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from 'ionic-native';
import { TodoList } from
"../pages/todo-list/todo-list";
@Component({
template: `<ion-nav
[root]="rootPage"></ion-nav>`
})
export class MyApp {
rootPage = TodoList;
constructor(platform: Platform) {
platform.ready().then(() => {
StatusBar.styleDefault();
});
}
}
src/app/app.module.ts src/app/app.component.ts
Ionic2 TODO list
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
export class Todo {
constructor(
public name: string,
public done: boolean = false
) {}
}
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
constructor(public navCtrl: NavController) {}
}
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
</ion-content>
Ionic2 TODO list
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
export class Todo {
constructor(
public name: string,
public done: boolean = false
) {}
}
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
todos: Todo[] = [
new Todo('todo 1'),
new Todo('todo 2')
];
constructor(public navCtrl: NavController) {}
}
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
</ion-content>
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let todo of todos">
{{todo.name}}
</ion-item>
</ion-list>
</ion-content>
Ionic2 TODO list
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let todo of todos">
<ion-label>{{todo.name}}</ion-label>
<ion-checkbox [(ngModel)]="todo.done"></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
Ionic2 TODO list
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<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-list>
</ion-content>
Ionic2 TODO list
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<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>{{todo.name}}</ion-label>
<ion-checkbox [(ngModel)]="todo.done"></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
Ionic2 TODO list
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<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 disabled="true" checked></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
Ionic2 TODO list
<ion-header>
<ion-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 ion-button>
<ion-icon name="send"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
...
</ion-content>
Ionic2 TODO list
import { Component } from
'@angular/core';
import { NavController } from
'ionic-angular';
export class Todo { ... }
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
newTodo: string = '';
todos: Todo[] = [ ... ];
constructor(public navCtrl:
NavController) {}
}
<ion-header>
<ion-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 ion-button (click)="create(newTodo)">
<ion-icon name="send"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
...
</ion-content>
Ionic2 TODO list
import { Component } from
'@angular/core';
import { NavController } from
'ionic-angular';
export class Todo { ... }
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
newTodo: string = '';
todos: Todo[] = [ ... ];
constructor(public navCtrl:
NavController) {}
create(text: string): void {
this.todos.push(new Todo(text));
this.newTodo = '';
}
}
<ion-header>
<ion-navbar>
<ion-title>Todos</ion-title>
</ion-navbar>
<ion-toolbar>
...
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
...
<ion-item
*ngFor="let todo of todos"
[hidden]="!todo.done"
(click)="remove(todo)">
<ion-label
class="done">{{todo.name}}</ion-label>
<ion-checkbox disabled="true"
checked></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
Ionic2 TODO list
import { Component } from '@angular/core';
import { NavController } from
'ionic-angular';
export class Todo { ... }
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
newTodo: string = '';
todos: Todo[] = [ ... ];
constructor(public navCtrl:
NavController) {}
create(text: string): void { ... }
remove(todo: Todo): void {
const i = this.todos.indexOf(todo);
if(i >= 0) { this.todos.splice(i, 1); }
}
}
Créer un composant
$ ionic g component todo-item
src/components/todo-item
import { Component } from '@angular/core';
@Component({
selector: 'todo-item',
templateUrl: 'todo-item.html'
})
export class TodoItem {
text: string;
constructor() {
this.text = 'Hello World';
}
}
{{text}} todo-item {
}
todo-item.ts todo-item.html todo-item.scss
import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { TodoList } from '../pages/todo-list/todo-list';
import { TodoItem } from "../components/todo-item/todo-item";
@NgModule({
declarations: [MyApp, HomePage, TodoList, TodoItem],
imports: [IonicModule.forRoot(MyApp)],
bootstrap: [IonicApp],
entryComponents: [MyApp, HomePage, TodoList],
providers: []
})
export class AppModule {}
src/app/app.module.ts
src/components/todo-item
import { Component, Input } from
'@angular/core';
import {Todo} from
'../../pages/todo-list/todo-list';
@Component({
selector: 'todo-item',
templateUrl: 'todo-item.html'
})
export class TodoItem {
@Input() todo: Todo;
constructor() {}
}
{{text}}
src/components/todo-item
import { Component, Input } from
'@angular/core';
import {Todo} from
'../../pages/todo-list/todo-list';
@Component({
selector: 'todo-item',
templateUrl: 'todo-item.html'
})
export class TodoItem {
@Input() todo: Todo;
constructor() {}
}
<ion-item>
<ion-label>
{{todo.name}}
</ion-label>
<ion-checkbox
[(ngModel)]="todo.done"></ion-checkbox>
</ion-item>
src/components/todo-item
import { Component, Input } from
'@angular/core';
import {Todo} from
'../../pages/todo-list/todo-list';
@Component({
selector: 'todo-item',
templateUrl: 'todo-item.html'
})
export class TodoItem {
@Input() todo: Todo;
constructor() {}
}
<ion-item>
<ion-label [class.done]="todo.done">
{{todo.name}}
</ion-label>
<ion-checkbox
[(ngModel)]="todo.done"
[disabled]="todo.done"
[checked]="todo.done"></ion-checkbox>
</ion-item>
<ion-content>
<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" (click)="remove(todo)">
<ion-label class="done">{{todo.name}}</ion-label>
<ion-checkbox disabled="true" checked></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
todo-list.html
<ion-content>
<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" (click)="remove(todo)">
<ion-label class="done">{{todo.name}}</ion-label>
<ion-checkbox disabled="true" checked></ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
<ion-content>
<ion-list>
<todo-item *ngFor="let todo of todos" [todo]="todo" [hidden]="todo.done"></todo-item>
<todo-item *ngFor="let todo of todos" [todo]="todo" [hidden]="!todo.done" (click)="remove(todo)"></todo-item>
</ion-list>
</ion-content>
todo-list.html
Créer un service
$ ionic g provider todo-service
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class TodoService {
constructor(public http: Http) {
console.log('Hello TodoService Provider');
}
}
src/providers/todo-service.ts
import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { TodoList } from "../pages/todo-list/todo-list";
import { TodoItem } from "../components/todo-item/todo-item";
import { TodoService } from "../providers/todo-service";
@NgModule({
declarations: [MyApp, HomePage, TodoList, TodoItem],
imports: [IonicModule.forRoot(MyApp)],
bootstrap: [IonicApp],
entryComponents: [MyApp, HomePage, TodoList],
providers: [TodoService]
})
export class AppModule {}
src/app/app.module.ts
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import {Todo} from "../pages/todo-list/todo-list";
@Injectable()
export class TodoService {
constructor() {}
private todos: Todo[] = [
new Todo('todo 1'),
new Todo('todo 2')
];
getTodos(): Todo[] {
return this.todos;
}
createTodo(text: string): void {
this.todos.push(new Todo(text));
}
removeTodo(todo: Todo): void {
const i = this.todos.indexOf(todo);
if(i >= 0) { this.todos.splice(i, 1); }
}
}
src/providers/todo-service.ts
import { Component } from '@angular/core';
import { TodoService } from "../../providers/todo-service";
@Component({
selector: 'page-todo-list',
templateUrl: 'todo-list.html'
})
export class TodoList {
newTodo: string = '';
todos: Todo[] = [];
constructor(private todoSrv: TodoService) {
this.todos = todoSrv.getTodos();
}
create(text: string): void {
this.todoSrv.createTodo(text);
this.newTodo = '';
}
remove(todo: Todo): void {
this.todoSrv.removeTodo(todo);
}
}
src/pages/todo-list/todo-list.ts
Ionic2 Menu
$ ionic start my-app sidemenu --v2
<ion-menu [content]="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion-item menuClose *ngFor="let p of pages"
(click)="openPage(p)">
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content></ion-nav>
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = Page1;
pages: {title: string, component: any}[];
constructor(public platform: Platform) {
this.pages = [
{ title: 'Page One', component: Page1 },
{ title: 'Page Two', component: Page2 }
];
}
openPage(page) {
this.nav.setRoot(page.component);
}
}
Ionic2 Sidemenu
<ion-menu [content]="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button menuClose ion-item (click)="openPage1()">
Page One
</button>
<button menuClose ion-item (click)="openPage2()">
Page Two
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content></ion-nav>
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = Page1;
constructor(public platform: Platform) {}
openPage1() { this.nav.setRoot(Page1); }
openPage2() { this.nav.setRoot(Page2); }
}
Ionic2 Sidemenu
<ion-menu [content]="content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button menuClose ion-item (click)="openPage1()">
Page One
</button>
<button menuClose ion-item (click)="openPage2()">
Page Two
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content></ion-nav>
@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;
rootPage: any = Page1;
constructor(public platform: Platform) {}
openPage1() { this.nav.setRoot(Page1); }
openPage2() { this.nav.setRoot(Page2); }
}
Ionic2 Sidemenu
22 lignes
vs
137 lignes !!!
Pour tester ce weekend...
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/
Questions ?
@loicknuchel

More Related Content

What's hot

Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
Rapid mobile development with Ionic framework - Voxxdays Ticino 2015Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
Rapid mobile development with Ionic framework - Voxxdays Ticino 2015Alessio Delmonti
 
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesJacob Friesen
 
An intro to the JAMStack and Eleventy
An intro to the JAMStack and EleventyAn intro to the JAMStack and Eleventy
An intro to the JAMStack and EleventyLuciano Mammino
 
EuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingAlessandro Molina
 
Ionic 2: Mobile apps with the Web
Ionic 2: Mobile apps with the WebIonic 2: Mobile apps with the Web
Ionic 2: Mobile apps with the WebMike Hartington
 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPodsCocoaHeads France
 
Developing Hybrid Applications with IONIC
Developing Hybrid Applications with IONICDeveloping Hybrid Applications with IONIC
Developing Hybrid Applications with IONICFuat Buğra AYDIN
 
iOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs
iOS Developers Conference-iOS Automation with Cucumber, Appium and SaucelabsiOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs
iOS Developers Conference-iOS Automation with Cucumber, Appium and SaucelabsShashikant Jagtap
 
Continuous integration by Rémy Virin
Continuous integration by Rémy VirinContinuous integration by Rémy Virin
Continuous integration by Rémy VirinCocoaHeads France
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budgetDavid Lukac
 
A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019Matt Raible
 
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Kelly Shuster
 
The Happy Path: Migration Strategies for Node.js
The Happy Path: Migration Strategies for Node.jsThe Happy Path: Migration Strategies for Node.js
The Happy Path: Migration Strategies for Node.jsNicholas Jansma
 
Workshop-Build e deploy avançado com Openshift e Kubernetes
Workshop-Build e deploy avançado com Openshift e KubernetesWorkshop-Build e deploy avançado com Openshift e Kubernetes
Workshop-Build e deploy avançado com Openshift e Kubernetesjuniorjbn
 
iOS Automation with Cucumber, Appium and Saucelabs
iOS Automation with Cucumber, Appium and SaucelabsiOS Automation with Cucumber, Appium and Saucelabs
iOS Automation with Cucumber, Appium and SaucelabsShashikant Jagtap
 
Framework dynamic par Simone Sivetta
Framework dynamic par Simone SivettaFramework dynamic par Simone Sivetta
Framework dynamic par Simone SivettaCocoaHeads France
 

What's hot (20)

Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
Rapid mobile development with Ionic framework - Voxxdays Ticino 2015Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
Rapid mobile development with Ionic framework - Voxxdays Ticino 2015
 
Intro to PhoneGap
Intro to PhoneGapIntro to PhoneGap
Intro to PhoneGap
 
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
 
An intro to the JAMStack and Eleventy
An intro to the JAMStack and EleventyAn intro to the JAMStack and Eleventy
An intro to the JAMStack and Eleventy
 
EuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears Training
 
Multitasking in iOS 7
Multitasking in iOS 7Multitasking in iOS 7
Multitasking in iOS 7
 
Ionic 2: Mobile apps with the Web
Ionic 2: Mobile apps with the WebIonic 2: Mobile apps with the Web
Ionic 2: Mobile apps with the Web
 
Build a lego app with CocoaPods
Build a lego app with CocoaPodsBuild a lego app with CocoaPods
Build a lego app with CocoaPods
 
Developing Hybrid Applications with IONIC
Developing Hybrid Applications with IONICDeveloping Hybrid Applications with IONIC
Developing Hybrid Applications with IONIC
 
iOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs
iOS Developers Conference-iOS Automation with Cucumber, Appium and SaucelabsiOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs
iOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs
 
Continuous integration by Rémy Virin
Continuous integration by Rémy VirinContinuous integration by Rémy Virin
Continuous integration by Rémy Virin
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budget
 
A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019
 
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
 
Intro to ionic 2
Intro to ionic 2Intro to ionic 2
Intro to ionic 2
 
What's new in ios 7.0
What's new in ios 7.0What's new in ios 7.0
What's new in ios 7.0
 
The Happy Path: Migration Strategies for Node.js
The Happy Path: Migration Strategies for Node.jsThe Happy Path: Migration Strategies for Node.js
The Happy Path: Migration Strategies for Node.js
 
Workshop-Build e deploy avançado com Openshift e Kubernetes
Workshop-Build e deploy avançado com Openshift e KubernetesWorkshop-Build e deploy avançado com Openshift e Kubernetes
Workshop-Build e deploy avançado com Openshift e Kubernetes
 
iOS Automation with Cucumber, Appium and Saucelabs
iOS Automation with Cucumber, Appium and SaucelabsiOS Automation with Cucumber, Appium and Saucelabs
iOS Automation with Cucumber, Appium and Saucelabs
 
Framework dynamic par Simone Sivetta
Framework dynamic par Simone SivettaFramework dynamic par Simone Sivetta
Framework dynamic par Simone Sivetta
 

Viewers also liked

Pasar grosir di jakarta
Pasar grosir di jakartaPasar grosir di jakarta
Pasar grosir di jakartahenigusnia
 
2014 스마트한 교실수업
2014 스마트한 교실수업2014 스마트한 교실수업
2014 스마트한 교실수업다혜 김
 
Slips & Falls Top the List for Worker’s Comp Claims
Slips & Falls Top the List for Worker’s Comp ClaimsSlips & Falls Top the List for Worker’s Comp Claims
Slips & Falls Top the List for Worker’s Comp ClaimsCost U Less Direct
 
Pentecost: What An Amazing Day!
Pentecost: What An Amazing Day!Pentecost: What An Amazing Day!
Pentecost: What An Amazing Day!HaynesStreet
 
Haydn Barry evaluation questions (incomplete)
Haydn Barry   evaluation questions (incomplete)Haydn Barry   evaluation questions (incomplete)
Haydn Barry evaluation questions (incomplete)haydnbarry
 
A2 media evaluation questions
A2 media evaluation questionsA2 media evaluation questions
A2 media evaluation questionsmylesrichardson
 
Atl 12 fi̇zi̇hi̇n dogasi bi̇lal şahi̇n
Atl 12 fi̇zi̇hi̇n dogasi   bi̇lal şahi̇nAtl 12 fi̇zi̇hi̇n dogasi   bi̇lal şahi̇n
Atl 12 fi̇zi̇hi̇n dogasi bi̇lal şahi̇nBilal Sahin
 

Viewers also liked (16)

459541
459541459541
459541
 
'Tis The Season
'Tis The Season'Tis The Season
'Tis The Season
 
Pasar grosir di jakarta
Pasar grosir di jakartaPasar grosir di jakarta
Pasar grosir di jakarta
 
2014 스마트한 교실수업
2014 스마트한 교실수업2014 스마트한 교실수업
2014 스마트한 교실수업
 
Eqpo 10 exposicion
Eqpo 10 exposicionEqpo 10 exposicion
Eqpo 10 exposicion
 
Slips & Falls Top the List for Worker’s Comp Claims
Slips & Falls Top the List for Worker’s Comp ClaimsSlips & Falls Top the List for Worker’s Comp Claims
Slips & Falls Top the List for Worker’s Comp Claims
 
Pentecost: What An Amazing Day!
Pentecost: What An Amazing Day!Pentecost: What An Amazing Day!
Pentecost: What An Amazing Day!
 
La conjunción equipo 2
La conjunción equipo 2La conjunción equipo 2
La conjunción equipo 2
 
Haydn Barry evaluation questions (incomplete)
Haydn Barry   evaluation questions (incomplete)Haydn Barry   evaluation questions (incomplete)
Haydn Barry evaluation questions (incomplete)
 
A2 media evaluation questions
A2 media evaluation questionsA2 media evaluation questions
A2 media evaluation questions
 
Media evaluation
Media evaluationMedia evaluation
Media evaluation
 
Its all about tyler
Its all about tylerIts all about tyler
Its all about tyler
 
Whypowerpointrulesthebusinessworld 130821132711-phpapp02 (1)
Whypowerpointrulesthebusinessworld 130821132711-phpapp02 (1)Whypowerpointrulesthebusinessworld 130821132711-phpapp02 (1)
Whypowerpointrulesthebusinessworld 130821132711-phpapp02 (1)
 
Love
LoveLove
Love
 
Atl 12 fi̇zi̇hi̇n dogasi bi̇lal şahi̇n
Atl 12 fi̇zi̇hi̇n dogasi   bi̇lal şahi̇nAtl 12 fi̇zi̇hi̇n dogasi   bi̇lal şahi̇n
Atl 12 fi̇zi̇hi̇n dogasi bi̇lal şahi̇n
 
Give Thanks
Give ThanksGive Thanks
Give Thanks
 

Similar to Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016

Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)Jose Manuel Pereira Garcia
 
React Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsMatteo Manchi
 
PhoneGap, Backbone & Javascript
PhoneGap, Backbone & JavascriptPhoneGap, Backbone & Javascript
PhoneGap, Backbone & Javascriptnatematias
 
[Ultracode Munich #4] Short introduction to the new Android build system incl...
[Ultracode Munich #4] Short introduction to the new Android build system incl...[Ultracode Munich #4] Short introduction to the new Android build system incl...
[Ultracode Munich #4] Short introduction to the new Android build system incl...BeMyApp
 
Five android architecture
Five android architectureFive android architecture
Five android architectureTomislav Homan
 
How To Integrate Native Android App With React Native.
How To Integrate Native Android App With React Native.How To Integrate Native Android App With React Native.
How To Integrate Native Android App With React Native.Techugo
 
Intro to Flutter
Intro to FlutterIntro to Flutter
Intro to FlutterEason Pai
 
Native Android Development Practices
Native Android Development PracticesNative Android Development Practices
Native Android Development PracticesRoy Clarkson
 
NativeScript and Angular
NativeScript and AngularNativeScript and Angular
NativeScript and AngularJen Looper
 
Architecting Single Activity Applications (With or Without Fragments)
Architecting Single Activity Applications (With or Without Fragments)Architecting Single Activity Applications (With or Without Fragments)
Architecting Single Activity Applications (With or Without Fragments)Gabor Varadi
 
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...César Hernández
 
Android Workshop
Android WorkshopAndroid Workshop
Android WorkshopJunda Ong
 

Similar to Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016 (20)

Mini curso Android
Mini curso AndroidMini curso Android
Mini curso Android
 
Ruby conf2012
Ruby conf2012Ruby conf2012
Ruby conf2012
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
React Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applications
 
Android Intro
Android IntroAndroid Intro
Android Intro
 
Android
AndroidAndroid
Android
 
IoT-javascript-2019-fosdem
IoT-javascript-2019-fosdemIoT-javascript-2019-fosdem
IoT-javascript-2019-fosdem
 
PhoneGap, Backbone & Javascript
PhoneGap, Backbone & JavascriptPhoneGap, Backbone & Javascript
PhoneGap, Backbone & Javascript
 
[Ultracode Munich #4] Short introduction to the new Android build system incl...
[Ultracode Munich #4] Short introduction to the new Android build system incl...[Ultracode Munich #4] Short introduction to the new Android build system incl...
[Ultracode Munich #4] Short introduction to the new Android build system incl...
 
Five android architecture
Five android architectureFive android architecture
Five android architecture
 
How To Integrate Native Android App With React Native.
How To Integrate Native Android App With React Native.How To Integrate Native Android App With React Native.
How To Integrate Native Android App With React Native.
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
React nativebeginner1
React nativebeginner1React nativebeginner1
React nativebeginner1
 
Intro to Flutter
Intro to FlutterIntro to Flutter
Intro to Flutter
 
Native Android Development Practices
Native Android Development PracticesNative Android Development Practices
Native Android Development Practices
 
NativeScript and Angular
NativeScript and AngularNativeScript and Angular
NativeScript and Angular
 
Architecting Single Activity Applications (With or Without Fragments)
Architecting Single Activity Applications (With or Without Fragments)Architecting Single Activity Applications (With or Without Fragments)
Architecting Single Activity Applications (With or Without Fragments)
 
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d...
 
Android Workshop
Android WorkshopAndroid Workshop
Android Workshop
 

More from Loïc Knuchel

Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Loïc Knuchel
 
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Loïc Knuchel
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Loïc Knuchel
 
FP is coming... le 19/05/2016
FP is coming... le 19/05/2016FP is coming... le 19/05/2016
FP is coming... le 19/05/2016Loïc Knuchel
 
Programmation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptProgrammation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptLoïc Knuchel
 
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Loïc Knuchel
 
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Loïc Knuchel
 
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Loïc Knuchel
 
Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Loïc Knuchel
 
Devoxx 2015, ionic chat
Devoxx 2015, ionic chatDevoxx 2015, ionic chat
Devoxx 2015, ionic chatLoïc Knuchel
 
Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Loïc Knuchel
 
Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Loïc Knuchel
 

More from Loïc Knuchel (12)

Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019
 
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
 
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016
 
FP is coming... le 19/05/2016
FP is coming... le 19/05/2016FP is coming... le 19/05/2016
FP is coming... le 19/05/2016
 
Programmation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptProgrammation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScript
 
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
 
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
 
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
 
Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015
 
Devoxx 2015, ionic chat
Devoxx 2015, ionic chatDevoxx 2015, ionic chat
Devoxx 2015, ionic chat
 
Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015
 
Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014
 

Recently uploaded

Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 

Recently uploaded (20)

Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 

Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016

  • 1. The rise of web developers le 21/10/2016, ionic 2.0-rc1 @loicknuchel
  • 2. Loïc Knuchel Geek passionné Développeur Scala Organisateur loicknuchel@gmail.com @loicknuchel http://loic.knuchel.org/
  • 4. Juin 2007 Lancement de l’iPhone 1
  • 5. Septembre 2008 Sortie du HTC G1 avec Android
  • 6. ● Nouvelles possibilités ○ UX ○ Technique ○ Business ● Un écosystème à bâtir
  • 7. ● 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é...)
  • 8.
  • 11. Idée Coder des applications entièrement dans la WebView Avantages : ● Cross-platform ● Technologies et environnements connus
  • 12. PhoneGap / Cordova Mars 2009 : Lancement de PhoneGap par Nitobi Octobre 2011 : Rachat de Nitobi par Adobe Séparation de la technologie (Cordova) et des services commerciaux (PhoneGap)
  • 13.
  • 14. 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...
  • 15. Aujourd’hui ● Téléphones puissants (et de + en +) ● Très bon support des standards web dans la WebView ● Beaucoup d’outils / librairies
  • 16.
  • 17.
  • 18.
  • 21.
  • 25. Android Menu (Nav Drawer) Source: https://developer.android.com/training/implementing-navigation/nav-drawer.html
  • 26. ... @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } switch(item.getItemId()) { case R.id.action_websearch: Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); intent.putExtra(SearchManager.QUERY, getActionBar().getTitle()); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show(); } return true; default: return super.onOptionsItemSelected(item); } } private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } private void selectItem(int position) { Fragment fragment = new PlanetFragment(); Bundle args = new Bundle(); args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position); fragment.setArguments(args); FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit(); mDrawerList.setItemChecked(position, true); setTitle(mPlanetTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } ... public class MainActivity extends Activity { private DrawerLayout mDrawerLayout; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private CharSequence mDrawerTitle; private CharSequence mTitle; private String[] mPlanetTitles; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = mDrawerTitle = getTitle(); mPlanetTitles = getResources().getStringArray(R.array.planets_array); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mPlanetTitles)); mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle( this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close ) { public void onDrawerClosed(View view) { getActionBar().setTitle(mTitle); invalidateOptionsMenu(); } public void onDrawerOpened(View drawerView) { getActionBar().setTitle(mDrawerTitle); invalidateOptionsMenu(); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); if (savedInstanceState == null) { selectItem(0); } } ...
  • 27. <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" /> <ListView android:id="@+id/left_drawer" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#111"/> </android.support.v4.widget.DrawerLayout> ... @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); menu.findItem(R.id.action_websearch).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu); } @Override public void setTitle(CharSequence title) { mTitle = title; getActionBar().setTitle(mTitle); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } public static class PlanetFragment extends Fragment { public static final String ARG_PLANET_NUMBER = "planet_number"; public PlanetFragment() {} @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_planet, container, false); int i = getArguments().getInt(ARG_PLANET_NUMBER); String planet = getResources().getStringArray(R.array.planets_array)[i]; int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()), "drawable", getActivity().getPackageName()); ((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId); getActivity().setTitle(planet); return rootView; } } }
  • 29.
  • 30. App Store installs are broken ! ? http://bit.ly/voxxrin
  • 31. App Store installs are broken !
  • 32. App Store installs are broken !
  • 33.
  • 34.
  • 35.
  • 37. Stack technologique Natif Web Téléphone & APIs natives Cordova : webview + JavaScript bridges Angular Ionic Application
  • 38. 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
  • 39. DX #Platform continuity #CLI #Backend services #Push #Deploy #Package #Auth #Analytics #Ionic View #Native plugins #Ionic Market #Ionic Creator
  • 40. Ionic is a complete ecosystem !
  • 42. Hybrid apps have superpowers...
  • 44. Hybrid superpowers Web App : ● Cross-platform ● Searchable ● Accès instantané ● Deep link 100 % http://bit.ly/voxxrin-bdx-lkn
  • 45. Hybrid superpowers Web App : ● Cross-platform ● Searchable ● Accès instantané ● Deep link Progressive Web App : ● Installation instantanée ● Lancement depuis la Home ● Offline ● Push notifications
  • 46. Hybrid superpowers Web App : ● Cross-platform ● Searchable ● Accès instantané ● Deep link Progressive Web App : ● Installation instantanée ● Lancement depuis la Home ● Offline ● Push notifications Native App : ● Accès complet au téléphone
  • 48. App Store deployment is broken ! Google : ~ 2 heures Apple : ~ 2 jours
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60. Getting started Install nodejs & npm $ npm install -g ionic $ ionic start demoApp --v2 $ cd demoApp && ionic serve ♬ ♫ ♬ ♫ Your Ionic app is ready to go! ♬ ♫ ♬ ♫
  • 61. Getting started Install mobile sdk (Android ou iOS) $ sudo npm install -g cordova $ ionic run android
  • 62. src/index.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="UTF-8"> <title>Ionic App</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 rel="icon" type="image/x-icon" href="assets/icon/favicon.ico"> <link rel="manifest" href="manifest.json"> <meta name="theme-color" content="#4e8ef7"> <link href="build/main.css" rel="stylesheet"> </head> <body> <ion-app></ion-app> <!-- Ionic's root component and where the app will load --> <script src="cordova.js"></script> <!-- cordova.js required for cordova apps --> <script src="build/polyfills.js"></script> <!-- polyfills generated during the build process --> <script src="build/main.js"></script> <!-- bundle generated during the build process --> </body> </html>
  • 63. src/app/main.dev.ts import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
  • 64. src/app/app.module.ts import { NgModule } from '@angular/core'; import { IonicApp, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; @NgModule({ declarations: [MyApp, HomePage], imports: [IonicModule.forRoot(MyApp)], bootstrap: [IonicApp], entryComponents: [MyApp, HomePage], providers: [] }) export class AppModule {}
  • 65. src/app/app.component.ts import { Component } from '@angular/core'; import { Platform } from 'ionic-angular'; import { StatusBar } from 'ionic-native'; import { HomePage } from '../pages/home/home'; @Component({ template: `<ion-nav [root]="rootPage"></ion-nav>` }) export class MyApp { rootPage = HomePage; constructor(platform: Platform) { platform.ready().then(() => { StatusBar.styleDefault(); }); } }
  • 66. src/pages/home/home.ts <ion-header> <ion-navbar> <ion-title>Ionic Blank</ion-title> </ion-navbar> </ion-header> <ion-content padding> The world is your oyster. <p> If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</ a> will be your guide. </p> </ion-content> import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { constructor(public navCtrl: NavController) {} }
  • 67. src/pages/home/home.ts import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; @Component({ template: ` <ion-header> <ion-navbar> <ion-title>Ionic Blank</ion-title> </ion-navbar> </ion-header> <ion-content padding> The world is your oyster. <p> If you get lost, the <a href="http://ionicframework.com/docs/v2">docs</a> will be your guide. </p> </ion-content>` }) export class HomePage { constructor(public navCtrl: NavController) {} }
  • 68.
  • 69. $ ionic start todo-app --v2
  • 70. Créer une nouvelle page $ ionic g page todo-list
  • 71. src/pages/todo-list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { constructor(public navCtrl: NavController) {} ionViewDidLoad() { console.log('Hello TodoList Page'); } } <ion-header> <ion-navbar> <ion-title> todo-list </ion-title> </ion-navbar> </ion-header> <ion-content padding> </ion-content> page-todo-list { } todo-list.ts todo-list.html todo-list.scss
  • 72. import { NgModule } from '@angular/core'; import { IonicApp, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { TodoList } from "../pages/todo-list/todo-list"; @NgModule({ declarations: [MyApp, HomePage, TodoList], imports: [IonicModule.forRoot(MyApp)], bootstrap: [IonicApp], entryComponents: [MyApp, HomePage, TodoList], providers: [] }) export class AppModule {} import { Component } from '@angular/core'; import { Platform } from 'ionic-angular'; import { StatusBar } from 'ionic-native'; import { TodoList } from "../pages/todo-list/todo-list"; @Component({ template: `<ion-nav [root]="rootPage"></ion-nav>` }) export class MyApp { rootPage = TodoList; constructor(platform: Platform) { platform.ready().then(() => { StatusBar.styleDefault(); }); } } src/app/app.module.ts src/app/app.component.ts
  • 73. Ionic2 TODO list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; export class Todo { constructor( public name: string, public done: boolean = false ) {} } @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { constructor(public navCtrl: NavController) {} } <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> </ion-content>
  • 74. Ionic2 TODO list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; export class Todo { constructor( public name: string, public done: boolean = false ) {} } @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { todos: Todo[] = [ new Todo('todo 1'), new Todo('todo 2') ]; constructor(public navCtrl: NavController) {} } <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> </ion-content>
  • 76. <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> <ion-list> <ion-item *ngFor="let todo of todos"> <ion-label>{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item> </ion-list> </ion-content> Ionic2 TODO list
  • 77. <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> <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-list> </ion-content> Ionic2 TODO list
  • 78. <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> <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>{{todo.name}}</ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item> </ion-list> </ion-content> Ionic2 TODO list
  • 79. <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> </ion-header> <ion-content> <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 disabled="true" checked></ion-checkbox> </ion-item> </ion-list> </ion-content> Ionic2 TODO list
  • 80. <ion-header> <ion-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 ion-button> <ion-icon name="send"></ion-icon> </button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> ... </ion-content> Ionic2 TODO list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; export class Todo { ... } @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { newTodo: string = ''; todos: Todo[] = [ ... ]; constructor(public navCtrl: NavController) {} }
  • 81. <ion-header> <ion-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 ion-button (click)="create(newTodo)"> <ion-icon name="send"></ion-icon> </button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> ... </ion-content> Ionic2 TODO list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; export class Todo { ... } @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { newTodo: string = ''; todos: Todo[] = [ ... ]; constructor(public navCtrl: NavController) {} create(text: string): void { this.todos.push(new Todo(text)); this.newTodo = ''; } }
  • 82. <ion-header> <ion-navbar> <ion-title>Todos</ion-title> </ion-navbar> <ion-toolbar> ... </ion-toolbar> </ion-header> <ion-content> <ion-list> ... <ion-item *ngFor="let todo of todos" [hidden]="!todo.done" (click)="remove(todo)"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox disabled="true" checked></ion-checkbox> </ion-item> </ion-list> </ion-content> Ionic2 TODO list import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; export class Todo { ... } @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { newTodo: string = ''; todos: Todo[] = [ ... ]; constructor(public navCtrl: NavController) {} create(text: string): void { ... } remove(todo: Todo): void { const i = this.todos.indexOf(todo); if(i >= 0) { this.todos.splice(i, 1); } } }
  • 83.
  • 84. Créer un composant $ ionic g component todo-item
  • 85. src/components/todo-item import { Component } from '@angular/core'; @Component({ selector: 'todo-item', templateUrl: 'todo-item.html' }) export class TodoItem { text: string; constructor() { this.text = 'Hello World'; } } {{text}} todo-item { } todo-item.ts todo-item.html todo-item.scss
  • 86. import { NgModule } from '@angular/core'; import { IonicApp, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { TodoList } from '../pages/todo-list/todo-list'; import { TodoItem } from "../components/todo-item/todo-item"; @NgModule({ declarations: [MyApp, HomePage, TodoList, TodoItem], imports: [IonicModule.forRoot(MyApp)], bootstrap: [IonicApp], entryComponents: [MyApp, HomePage, TodoList], providers: [] }) export class AppModule {} src/app/app.module.ts
  • 87. src/components/todo-item import { Component, Input } from '@angular/core'; import {Todo} from '../../pages/todo-list/todo-list'; @Component({ selector: 'todo-item', templateUrl: 'todo-item.html' }) export class TodoItem { @Input() todo: Todo; constructor() {} } {{text}}
  • 88. src/components/todo-item import { Component, Input } from '@angular/core'; import {Todo} from '../../pages/todo-list/todo-list'; @Component({ selector: 'todo-item', templateUrl: 'todo-item.html' }) export class TodoItem { @Input() todo: Todo; constructor() {} } <ion-item> <ion-label> {{todo.name}} </ion-label> <ion-checkbox [(ngModel)]="todo.done"></ion-checkbox> </ion-item>
  • 89. src/components/todo-item import { Component, Input } from '@angular/core'; import {Todo} from '../../pages/todo-list/todo-list'; @Component({ selector: 'todo-item', templateUrl: 'todo-item.html' }) export class TodoItem { @Input() todo: Todo; constructor() {} } <ion-item> <ion-label [class.done]="todo.done"> {{todo.name}} </ion-label> <ion-checkbox [(ngModel)]="todo.done" [disabled]="todo.done" [checked]="todo.done"></ion-checkbox> </ion-item>
  • 90. <ion-content> <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" (click)="remove(todo)"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox disabled="true" checked></ion-checkbox> </ion-item> </ion-list> </ion-content> todo-list.html
  • 91. <ion-content> <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" (click)="remove(todo)"> <ion-label class="done">{{todo.name}}</ion-label> <ion-checkbox disabled="true" checked></ion-checkbox> </ion-item> </ion-list> </ion-content> <ion-content> <ion-list> <todo-item *ngFor="let todo of todos" [todo]="todo" [hidden]="todo.done"></todo-item> <todo-item *ngFor="let todo of todos" [todo]="todo" [hidden]="!todo.done" (click)="remove(todo)"></todo-item> </ion-list> </ion-content> todo-list.html
  • 92.
  • 93. Créer un service $ ionic g provider todo-service
  • 94. import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class TodoService { constructor(public http: Http) { console.log('Hello TodoService Provider'); } } src/providers/todo-service.ts
  • 95. import { NgModule } from '@angular/core'; import { IonicApp, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { TodoList } from "../pages/todo-list/todo-list"; import { TodoItem } from "../components/todo-item/todo-item"; import { TodoService } from "../providers/todo-service"; @NgModule({ declarations: [MyApp, HomePage, TodoList, TodoItem], imports: [IonicModule.forRoot(MyApp)], bootstrap: [IonicApp], entryComponents: [MyApp, HomePage, TodoList], providers: [TodoService] }) export class AppModule {} src/app/app.module.ts
  • 96. import { Injectable } from '@angular/core'; import 'rxjs/add/operator/map'; import {Todo} from "../pages/todo-list/todo-list"; @Injectable() export class TodoService { constructor() {} private todos: Todo[] = [ new Todo('todo 1'), new Todo('todo 2') ]; getTodos(): Todo[] { return this.todos; } createTodo(text: string): void { this.todos.push(new Todo(text)); } removeTodo(todo: Todo): void { const i = this.todos.indexOf(todo); if(i >= 0) { this.todos.splice(i, 1); } } } src/providers/todo-service.ts
  • 97. import { Component } from '@angular/core'; import { TodoService } from "../../providers/todo-service"; @Component({ selector: 'page-todo-list', templateUrl: 'todo-list.html' }) export class TodoList { newTodo: string = ''; todos: Todo[] = []; constructor(private todoSrv: TodoService) { this.todos = todoSrv.getTodos(); } create(text: string): void { this.todoSrv.createTodo(text); this.newTodo = ''; } remove(todo: Todo): void { this.todoSrv.removeTodo(todo); } } src/pages/todo-list/todo-list.ts
  • 98.
  • 99. Ionic2 Menu $ ionic start my-app sidemenu --v2
  • 100. <ion-menu [content]="content"> <ion-header> <ion-toolbar> <ion-title>Menu</ion-title> </ion-toolbar> </ion-header> <ion-content> <ion-list> <button ion-item menuClose *ngFor="let p of pages" (click)="openPage(p)"> {{p.title}} </button> </ion-list> </ion-content> </ion-menu> <ion-nav [root]="rootPage" #content></ion-nav> @Component({ templateUrl: 'app.html' }) export class MyApp { @ViewChild(Nav) nav: Nav; rootPage: any = Page1; pages: {title: string, component: any}[]; constructor(public platform: Platform) { this.pages = [ { title: 'Page One', component: Page1 }, { title: 'Page Two', component: Page2 } ]; } openPage(page) { this.nav.setRoot(page.component); } } Ionic2 Sidemenu
  • 101. <ion-menu [content]="content"> <ion-header> <ion-toolbar> <ion-title>Menu</ion-title> </ion-toolbar> </ion-header> <ion-content> <ion-list> <button menuClose ion-item (click)="openPage1()"> Page One </button> <button menuClose ion-item (click)="openPage2()"> Page Two </button> </ion-list> </ion-content> </ion-menu> <ion-nav [root]="rootPage" #content></ion-nav> @Component({ templateUrl: 'app.html' }) export class MyApp { @ViewChild(Nav) nav: Nav; rootPage: any = Page1; constructor(public platform: Platform) {} openPage1() { this.nav.setRoot(Page1); } openPage2() { this.nav.setRoot(Page2); } } Ionic2 Sidemenu
  • 102. <ion-menu [content]="content"> <ion-header> <ion-toolbar> <ion-title>Menu</ion-title> </ion-toolbar> </ion-header> <ion-content> <ion-list> <button menuClose ion-item (click)="openPage1()"> Page One </button> <button menuClose ion-item (click)="openPage2()"> Page Two </button> </ion-list> </ion-content> </ion-menu> <ion-nav [root]="rootPage" #content></ion-nav> @Component({ templateUrl: 'app.html' }) export class MyApp { @ViewChild(Nav) nav: Nav; rootPage: any = Page1; constructor(public platform: Platform) {} openPage1() { this.nav.setRoot(Page1); } openPage2() { this.nav.setRoot(Page2); } } Ionic2 Sidemenu 22 lignes vs 137 lignes !!!
  • 103. Pour tester ce weekend...
  • 104. 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/
  • 105.