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

Loïc Knuchel
Loïc KnuchelScala tech lead at Gospeak
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é...)
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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)
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Native develoment is ...
way ...
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
App Store installs are broken !
?
http://bit.ly/voxxrin
App Store installs are broken !
App Store installs are broken !
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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
●
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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) {}
}
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
$ 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); }
}
}
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
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/
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Questions ?
@loicknuchel
1 of 106

Recommended

Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016 by
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016Loïc Knuchel
705 views71 slides
Ionic2 by
Ionic2Ionic2
Ionic2Jiayun Zhou
3K views71 slides
Gdg ionic 2 by
Gdg ionic 2Gdg ionic 2
Gdg ionic 2Shang Yi Lim
370 views17 slides
Ionic bbl le 19 février 2015 by
Ionic bbl le 19 février 2015Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015Loïc Knuchel
5.7K views48 slides
Ionic2 the the journey continues ng-sydney 02-03-16 and ionicaustralia 23-0... by
Ionic2   the the journey continues ng-sydney 02-03-16 and ionicaustralia 23-0...Ionic2   the the journey continues ng-sydney 02-03-16 and ionicaustralia 23-0...
Ionic2 the the journey continues ng-sydney 02-03-16 and ionicaustralia 23-0...Sameera Gayan
557 views18 slides
[Lighting Talk] - Ionic 2 Tour by
[Lighting Talk] - Ionic 2 Tour[Lighting Talk] - Ionic 2 Tour
[Lighting Talk] - Ionic 2 TourCode Experts Learning
466 views13 slides

More Related Content

What's hot

Rapid mobile development with Ionic framework - Voxxdays Ticino 2015 by
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
1.4K views38 slides
Intro to PhoneGap by
Intro to PhoneGapIntro to PhoneGap
Intro to PhoneGapJussi Pohjolainen
1.6K views20 slides
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises by
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesJacob Friesen
2.4K views35 slides
An intro to the JAMStack and Eleventy by
An intro to the JAMStack and EleventyAn intro to the JAMStack and Eleventy
An intro to the JAMStack and EleventyLuciano Mammino
131 views79 slides
EuroPython 2013 - Python3 TurboGears Training by
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears TrainingAlessandro Molina
2.1K views59 slides
Multitasking in iOS 7 by
Multitasking in iOS 7Multitasking in iOS 7
Multitasking in iOS 7Mickaël Rémond
20.4K views23 slides

What's hot(20)

Rapid mobile development with Ionic framework - Voxxdays Ticino 2015 by Alessio Delmonti
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
Alessio Delmonti1.4K views
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises by Jacob Friesen
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Jacob Friesen2.4K views
An intro to the JAMStack and Eleventy by Luciano Mammino
An intro to the JAMStack and EleventyAn intro to the JAMStack and Eleventy
An intro to the JAMStack and Eleventy
Luciano Mammino131 views
EuroPython 2013 - Python3 TurboGears Training by Alessandro Molina
EuroPython 2013 - Python3 TurboGears TrainingEuroPython 2013 - Python3 TurboGears Training
EuroPython 2013 - Python3 TurboGears Training
Alessandro Molina2.1K views
Ionic 2: Mobile apps with the Web by Mike Hartington
Ionic 2: Mobile apps with the WebIonic 2: Mobile apps with the Web
Ionic 2: Mobile apps with the Web
Mike Hartington817 views
Developing Hybrid Applications with IONIC by Fuat Buğra AYDIN
Developing Hybrid Applications with IONICDeveloping Hybrid Applications with IONIC
Developing Hybrid Applications with IONIC
Fuat Buğra AYDIN920 views
iOS Developers Conference-iOS Automation with Cucumber, Appium and Saucelabs by Shashikant Jagtap
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
Shashikant Jagtap2.9K views
Continuous integration by Rémy Virin by CocoaHeads France
Continuous integration by Rémy VirinContinuous integration by Rémy Virin
Continuous integration by Rémy Virin
CocoaHeads France4.1K views
Automatisation in development and testing - within budget by David Lukac
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budget
David Lukac220 views
A Gentle Introduction to Angular Schematics - Angular SF 2019 by Matt Raible
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
Matt Raible458 views
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016) by Kelly Shuster
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 Shuster14.3K views
The Happy Path: Migration Strategies for Node.js by Nicholas Jansma
The Happy Path: Migration Strategies for Node.jsThe Happy Path: Migration Strategies for Node.js
The Happy Path: Migration Strategies for Node.js
Nicholas Jansma6.7K views
Workshop-Build e deploy avançado com Openshift e Kubernetes by juniorjbn
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
juniorjbn375 views
iOS Automation with Cucumber, Appium and Saucelabs by Shashikant Jagtap
iOS Automation with Cucumber, Appium and SaucelabsiOS Automation with Cucumber, Appium and Saucelabs
iOS Automation with Cucumber, Appium and Saucelabs

Viewers also liked

459541 by
459541459541
459541Zulfikar Zulfikar
813 views244 slides
'Tis The Season by
'Tis The Season'Tis The Season
'Tis The SeasonHaynesStreet
356 views7 slides
Pasar grosir di jakarta by
Pasar grosir di jakartaPasar grosir di jakarta
Pasar grosir di jakartahenigusnia
872 views3 slides
2014 스마트한 교실수업 by
2014 스마트한 교실수업2014 스마트한 교실수업
2014 스마트한 교실수업다혜 김
128 views4 slides
Eqpo 10 exposicion by
Eqpo 10 exposicionEqpo 10 exposicion
Eqpo 10 exposicionAlfredo Hernandez
349 views8 slides
Slips & Falls Top the List for Worker’s Comp Claims by
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
144 views13 slides

Viewers also liked(16)

Pasar grosir di jakarta by henigusnia
Pasar grosir di jakartaPasar grosir di jakarta
Pasar grosir di jakarta
henigusnia872 views
2014 스마트한 교실수업 by 다혜 김
2014 스마트한 교실수업2014 스마트한 교실수업
2014 스마트한 교실수업
다혜 김128 views
Slips & Falls Top the List for Worker’s Comp Claims by Cost U Less Direct
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
Cost U Less Direct144 views
Pentecost: What An Amazing Day! by HaynesStreet
Pentecost: What An Amazing Day!Pentecost: What An Amazing Day!
Pentecost: What An Amazing Day!
HaynesStreet528 views
Haydn Barry evaluation questions (incomplete) by haydnbarry
Haydn Barry   evaluation questions (incomplete)Haydn Barry   evaluation questions (incomplete)
Haydn Barry evaluation questions (incomplete)
haydnbarry415 views
Atl 12 fi̇zi̇hi̇n dogasi bi̇lal şahi̇n by Bilal Sahin
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
Bilal Sahin575 views

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

Mini curso Android by
Mini curso AndroidMini curso Android
Mini curso AndroidMario Jorge Pereira
831 views128 slides
Ruby conf2012 by
Ruby conf2012Ruby conf2012
Ruby conf2012Chandan Jog
524 views50 slides
Android Best Practices by
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
7K views58 slides
From Legacy to Hexagonal (An Unexpected Android Journey) by
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
3.8K views87 slides
React Native for multi-platform mobile applications by
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applicationsMatteo Manchi
1.6K views39 slides
Android Intro by
Android IntroAndroid Intro
Android IntroJustin Grammens
2.5K views35 slides

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

React Native for multi-platform mobile applications by Matteo Manchi
React Native for multi-platform mobile applicationsReact Native for multi-platform mobile applications
React Native for multi-platform mobile applications
Matteo Manchi1.6K views
PhoneGap, Backbone & Javascript by natematias
PhoneGap, Backbone & JavascriptPhoneGap, Backbone & Javascript
PhoneGap, Backbone & Javascript
natematias803 views
[Ultracode Munich #4] Short introduction to the new Android build system incl... by BeMyApp
[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...
BeMyApp2K views
Intro to Flutter by Eason Pai
Intro to FlutterIntro to Flutter
Intro to Flutter
Eason Pai2.2K views
Native Android Development Practices by Roy Clarkson
Native Android Development PracticesNative Android Development Practices
Native Android Development Practices
Roy Clarkson1.5K views
NativeScript and Angular by Jen Looper
NativeScript and AngularNativeScript and Angular
NativeScript and Angular
Jen Looper3 views
Architecting Single Activity Applications (With or Without Fragments) by Gabor Varadi
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 Varadi1.8K views
2018 (codeone) Graal VM and MicroProfile a polyglot microservices solution [d... by César Hernández
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ández204 views
Android Workshop by Junda Ong
Android WorkshopAndroid Workshop
Android Workshop
Junda Ong1.5K views
Ignite your app development with Angular, NativeScript and Firebase by Jen Looper
Ignite your app development with Angular, NativeScript and FirebaseIgnite your app development with Angular, NativeScript and Firebase
Ignite your app development with Angular, NativeScript and Firebase
Jen Looper5 views

More from Loïc Knuchel

Scala bad practices, scala.io 2019 by
Scala bad practices, scala.io 2019Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Loïc Knuchel
803 views22 slides
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe... by
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
1.7K views43 slides
Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016 by
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
962 views63 slides
FP is coming... le 19/05/2016 by
FP is coming... le 19/05/2016FP is coming... le 19/05/2016
FP is coming... le 19/05/2016Loïc Knuchel
681 views98 slides
Programmation fonctionnelle en JavaScript by
Programmation fonctionnelle en JavaScriptProgrammation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptLoïc Knuchel
1.2K views88 slides
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015 by
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
2.8K views50 slides

More from Loïc Knuchel(12)

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

Recently uploaded

Unlocking the Power of AI in Product Management - A Comprehensive Guide for P... by
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...NimaTorabi2
16 views17 slides
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action by
Gen Apps on Google Cloud PaLM2 and Codey APIs in ActionGen Apps on Google Cloud PaLM2 and Codey APIs in Action
Gen Apps on Google Cloud PaLM2 and Codey APIs in ActionMárton Kodok
16 views55 slides
How Workforce Management Software Empowers SMEs | TraQSuite by
How Workforce Management Software Empowers SMEs | TraQSuiteHow Workforce Management Software Empowers SMEs | TraQSuite
How Workforce Management Software Empowers SMEs | TraQSuiteTraQSuite
6 views3 slides
Agile 101 by
Agile 101Agile 101
Agile 101John Valentino
10 views20 slides
What is API by
What is APIWhat is API
What is APIartembondar5
12 views15 slides
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation by
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook AutomationDRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook AutomationHCLSoftware
6 views8 slides

Recently uploaded(20)

Unlocking the Power of AI in Product Management - A Comprehensive Guide for P... by NimaTorabi2
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...
Unlocking the Power of AI in Product Management - A Comprehensive Guide for P...
NimaTorabi216 views
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action by Márton Kodok
Gen Apps on Google Cloud PaLM2 and Codey APIs in ActionGen Apps on Google Cloud PaLM2 and Codey APIs in Action
Gen Apps on Google Cloud PaLM2 and Codey APIs in Action
Márton Kodok16 views
How Workforce Management Software Empowers SMEs | TraQSuite by TraQSuite
How Workforce Management Software Empowers SMEs | TraQSuiteHow Workforce Management Software Empowers SMEs | TraQSuite
How Workforce Management Software Empowers SMEs | TraQSuite
TraQSuite6 views
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation by HCLSoftware
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook AutomationDRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation
DRYiCE™ iAutomate: AI-enhanced Intelligent Runbook Automation
HCLSoftware6 views
Dev-HRE-Ops - Addressing the _Last Mile DevOps Challenge_ in Highly Regulated... by TomHalpin9
Dev-HRE-Ops - Addressing the _Last Mile DevOps Challenge_ in Highly Regulated...Dev-HRE-Ops - Addressing the _Last Mile DevOps Challenge_ in Highly Regulated...
Dev-HRE-Ops - Addressing the _Last Mile DevOps Challenge_ in Highly Regulated...
TomHalpin96 views
Top-5-production-devconMunich-2023-v2.pptx by Tier1 app
Top-5-production-devconMunich-2023-v2.pptxTop-5-production-devconMunich-2023-v2.pptx
Top-5-production-devconMunich-2023-v2.pptx
Tier1 app6 views
Airline Booking Software by SharmiMehta
Airline Booking SoftwareAirline Booking Software
Airline Booking Software
SharmiMehta9 views
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with... by sparkfabrik
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
sparkfabrik8 views
Electronic AWB - Electronic Air Waybill by Freightoscope
Electronic AWB - Electronic Air Waybill Electronic AWB - Electronic Air Waybill
Electronic AWB - Electronic Air Waybill
Freightoscope 5 views
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx by animuscrm
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx
2023-November-Schneider Electric-Meetup-BCN Admin Group.pptx
animuscrm15 views
ADDO_2022_CICID_Tom_Halpin.pdf by TomHalpin9
ADDO_2022_CICID_Tom_Halpin.pdfADDO_2022_CICID_Tom_Halpin.pdf
ADDO_2022_CICID_Tom_Halpin.pdf
TomHalpin95 views
tecnologia18.docx by nosi6702
tecnologia18.docxtecnologia18.docx
tecnologia18.docx
nosi67025 views
Quality Engineer: A Day in the Life by John Valentino
Quality Engineer: A Day in the LifeQuality Engineer: A Day in the Life
Quality Engineer: A Day in the Life
John Valentino7 views

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é...)
  • 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)
  • 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
  • 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; } } }
  • 30. App Store installs are broken ! ? http://bit.ly/voxxrin
  • 31. App Store installs are broken !
  • 32. App Store installs are broken !
  • 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
  • 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) {} }
  • 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); } } }
  • 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
  • 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
  • 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/