MoinMoin Logo
  • Comments
  • Immutable Page
  • Menu
    • Navigation
    • RecentChanges
    • FindPage
    • Local Site Map
    • Help
    • HelpContents
    • HelpOnMoinWikiSyntax
    • Display
    • Attachments
    • Info
    • Raw Text
    • Print View
    • Edit
    • Load
    • Save
  • Login

Navigation

  • Start
  • Sitemap

Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment

Revision 26 as of 2020-10-30 10:58:59
  • Ionic

Ionic

  • https://ionicframework.com/

Ionic Framework is an open source mobile UI toolkit for building high quality, cross-platform native and web app experiences.

Run chrome

   1 "/C/Program Files (x86)/Google/Chrome/Application/chrome.exe" --disable-web-security --disable-gpu --user-data-dir="c:\TempChrome" --disable-features=SameSiteByDefaultCookies,SameSiteDefaultChecksMethodRigorously
   2 # In Linux
   3 google-chrome  --disable-web-security --disable-gpu --user-data-dir="/tmp" --disable-features=SameSiteByDefaultCookies,SameSiteDefaultChecksMethodRigorously

Example app

  • Requires Android SDK, node 12.16.2 and npm 6.14.5

   1 cd ~
   2 mkdir IonicTest
   3 npm install @ionic/cli
   4 node_modules/.bin/ionic start IonicTest
   5 #framework angular
   6 #starter template tabs
   7 #integrate capacitor N
   8 #create free ionic account N
   9 cd IonicTest
  10 npm i
  11 npm install @ionic/cli
  12 npm install cordova
  13 npm install cordova-res
  14 node_modules/.bin/ionic cordova plugin add cordova-plugin-advanced-http
  15 npm install @ionic-native/http
  16 node_modules/.bin/ionic cordova platform add android
  17 node_modules/.bin/ionic cordova build android
  18 scp ./platforms/android/app/build/outputs/apk/debug/app-debug.apk userx@example.net:/home/userx/www/ionic-test.apk
  19 node_modules/.bin/ionic cordova platform add browser
  20 node_modules/.bin/ionic cordova build browser
  21 node_modules/.bin/ionic serve --cordova --platform=browser
  22 # http://localhost:8100
  23 # no CORS
  24 google-chrome --disable-web-security --disable-gpu --user-data-dir="/tmp"

app.module.ts

   1 import { NgModule } from '@angular/core';
   2 import { BrowserModule } from '@angular/platform-browser';
   3 import { RouteReuseStrategy } from '@angular/router';
   4 import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
   5 import { SplashScreen } from '@ionic-native/splash-screen/ngx';
   6 import { StatusBar } from '@ionic-native/status-bar/ngx';
   7 import { AppRoutingModule } from './app-routing.module';
   8 import { AppComponent } from './app.component';
   9 import { HTTP } from '@ionic-native/http/ngx';
  10 import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx';
  11 import { Device } from '@ionic-native/device/ngx';
  12 import { SQLite } from '@ionic-native/sqlite/ngx';
  13 import { DbService } from './db.service';
  14 import { NotifierService } from './notifier.service';
  15 
  16 @NgModule({
  17   declarations: [AppComponent],
  18   entryComponents: [],
  19   imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  20   providers: [
  21     HTTP,
  22     StatusBar,
  23     SplashScreen,
  24     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
  25     FirebaseMessaging,
  26     Device,
  27     SQLite,
  28     DbService,
  29     NotifierService
  30   ],
  31   bootstrap: [AppComponent]
  32 })
  33 export class AppModule { }

app.component.ts

   1 import { Component } from '@angular/core';
   2 import { Device } from '@ionic-native/device/ngx';
   3 import { Platform } from '@ionic/angular';
   4 import { SplashScreen } from '@ionic-native/splash-screen/ngx';
   5 import { StatusBar } from '@ionic-native/status-bar/ngx';
   6 import { FirebaseMessaging } from '@ionic-native/firebase-messaging/ngx';
   7 import { HTTP } from '@ionic-native/http/ngx';
   8 import { DbService } from './db.service';
   9 import { NotifierService } from './notifier.service';
  10 
  11 @Component({
  12   selector: 'app-root',
  13   templateUrl: 'app.component.html',
  14   styleUrls: ['app.component.scss']
  15 })
  16 export class AppComponent {
  17 
  18   constructor(
  19     private platform: Platform,
  20     private splashScreen: SplashScreen,
  21     private statusBar: StatusBar,
  22     private firebaseMessaging: FirebaseMessaging,
  23     private http: HTTP,
  24     private device: Device,
  25     private dbservice: DbService,
  26     private notifier: NotifierService
  27   ) {
  28     this.initializeApp();
  29   }
  30 
  31   initializeApp() {
  32     this.platform.ready().then(() => {
  33       this.statusBar.styleDefault();
  34       this.splashScreen.hide();
  35       this.handleNotifications();
  36     });
  37   }
  38 
  39   private fcmGetToken() {
  40     this.firebaseMessaging.getToken().then((token: any) => {
  41       let url: string = "https://example.org/logit.php";
  42       let body: any = { "devUUID": this.device.uuid };
  43       console.log("Body:" + JSON.stringify(body));
  44       this.http.post(url, body, {}).then(data => {
  45         console.log(data.status);
  46         console.log(data.data); // data received by server
  47         console.log(data.headers);
  48         // subscribe to topic with token name
  49         this.firebaseMessaging.subscribe(this.device.uuid);
  50       })
  51         .catch(error => {
  52           alert("Error " + JSON.stringify(error.error));
  53         });
  54     });
  55   }
  56 
  57   private handleNotifications() {
  58     this.firebaseMessaging.requestPermission().then(() => {
  59       this.fcmGetToken();
  60 
  61       this.firebaseMessaging.onTokenRefresh().subscribe(() => {
  62         this.fcmGetToken();
  63       });
  64 
  65       this.firebaseMessaging.onMessage().subscribe((payload: any) => {
  66         this.dbservice.insertPush("fg msg " + payload.body);
  67         this.notifier.notify(NotifierService.GOT_PUSH);
  68       });
  69 
  70       this.firebaseMessaging.onBackgroundMessage().subscribe((payload: any) => {
  71         this.dbservice.insertPush("back msg " + payload.body);
  72         this.notifier.notify(NotifierService.GOT_PUSH);
  73       });
  74     });
  75   }
  76 }

tab1.page.ts

   1 import { Component } from '@angular/core';
   2 import { HTTP } from '@ionic-native/http/ngx';
   3 
   4 @Component({
   5   selector: 'app-tab1',
   6   templateUrl: 'tab1.page.html',
   7   styleUrls: ['tab1.page.scss']
   8 })
   9 export class Tab1Page {
  10   public res;
  11 
  12   constructor(private http: HTTP) {}
  13 
  14   public ionViewDidEnter(){
  15     console.log("Stuff");
  16     this.http.get("https://labs.bitarus.allowed.org/xapps/rest/version/", {}, {})
  17     .then(data => {
  18       console.log(data.status);
  19       console.log(data.data); // data received by server
  20       this.res=data.data;
  21       console.log(data.headers);
  22     })
  23     .catch(error => {
  24       console.log(error.status);
  25       console.log(error.error); // error message as string
  26       console.log(error.headers);
  27     });
  28   }
  29 }

tab1.page.html

   1 <ion-header [translucent]="true">
   2   <ion-toolbar>
   3     <ion-title>
   4       Tab 111 {{res}}
   5     </ion-title>
   6   </ion-toolbar>
   7 </ion-header>
   8 
   9 <ion-content [fullscreen]="true">
  10   <ion-header collapse="condense">
  11     <ion-toolbar>
  12       <ion-title size="large">Tab 111</ion-title>
  13     </ion-toolbar>
  14   </ion-header>
  15 
  16   <app-explore-container name="Tab 111 page {{res}}"></app-explore-container>
  17 </ion-content>

tab2.page.html

   1 <ion-header [translucent]="true">
   2   <ion-toolbar>
   3     <ion-title>
   4       Sum
   5     </ion-title>
   6   </ion-toolbar>
   7 </ion-header>
   8 <ion-content [fullscreen]="true">
   9   <ion-header collapse="condense">
  10     <ion-toolbar>
  11       <ion-title size="large">Sum</ion-title>
  12     </ion-toolbar>
  13   </ion-header>
  14   <ion-item>
  15     <ion-label>Value 1</ion-label>
  16     <ion-input [(ngModel)]="in1"></ion-input>
  17   </ion-item>
  18   <ion-item>
  19      <ion-label>Value 2</ion-label>
  20      <ion-input [(ngModel)]="in2"></ion-input>
  21   </ion-item>
  22   <ion-button color="primary" (click)="sumValuesButtonClicked()">Sum values</ion-button>
  23 </ion-content>

tab2.page.ts

   1 import { Component } from '@angular/core';
   2 import { AlertController } from '@ionic/angular';
   3 
   4 @Component({
   5   selector: 'app-tab2',
   6   templateUrl: 'tab2.page.html',
   7   styleUrls: ['tab2.page.scss']
   8 })
   9 export class Tab2Page {
  10   in1:string;
  11   in2:string;
  12 
  13   constructor(public alertController: AlertController) {}
  14 
  15   sumValuesButtonClicked(){
  16     let res:Number;
  17     res = parseInt(this.in1) + parseInt(this.in2);
  18     this.presentResult(res).then(()=>{
  19       console.log("Done");
  20     });
  21   }
  22 
  23   async presentResult(res:Number) {
  24     const alert = await this.alertController.create({
  25       header: 'Sum',
  26       subHeader: 'Result',
  27       message: res.toString(),
  28       buttons: ['OK'],
  29     });
  30 
  31     await alert.present();
  32     let result = await alert.onDidDismiss();
  33     console.log(result); 
  34   }
  35 }

tab3.page.html

   1 <ion-header [translucent]="true">
   2   <ion-toolbar>
   3     <ion-title>
   4       Push notifications list
   5     </ion-title>
   6   </ion-toolbar>
   7 </ion-header>
   8 
   9 <ion-content [fullscreen]="true">
  10   <ion-header collapse="condense">
  11     <ion-toolbar>
  12       <ion-title size="large">Push notifications list</ion-title>
  13     </ion-toolbar>
  14   </ion-header>
  15   <ul>
  16     <li *ngFor="let pushNotification of items">
  17       {{pushNotification}}
  18     </li>
  19   </ul>
  20 </ion-content>

notifier.service.ts

   1 import { Injectable } from '@angular/core';
   2 
   3 @Injectable({
   4   providedIn: 'root'
   5 })
   6 export class NotifierService {
   7   static readonly GOT_PUSH: 'GotPush';
   8 
   9   private actions: string[];
  10   private callbacks: Function[];
  11 
  12   constructor() {
  13     this.actions = [];
  14     this.callbacks = [];
  15   }
  16 
  17   /**
  18    * Subscribe a callback to an action
  19    * @param action 
  20    * @param callback 
  21    */
  22   public subscribe(action: string, callback: Function) {
  23     this.actions.push(action);
  24     this.callbacks.push(callback);
  25   }
  26 
  27   public notify(action: string) {
  28     let idx: number;
  29     idx = -1;
  30     for (idx = 0; idx < this.actions.length; idx++) {
  31       if (this.actions[idx] == action) {
  32         break;
  33       }
  34     }
  35 
  36     if (idx != -1) {
  37       this.callbacks[idx]();
  38     }
  39   }
  40 }

tab3.page.ts

   1 import { ChangeDetectorRef, Component } from '@angular/core';
   2 import { DbService } from '../db.service';
   3 import { NotifierService } from '../notifier.service';
   4 
   5 @Component({
   6   selector: 'app-tab3',
   7   templateUrl: 'tab3.page.html',
   8   styleUrls: ['tab3.page.scss']
   9 })
  10 export class Tab3Page {
  11   public items: string[];
  12 
  13   constructor(private dbService: DbService, private notifier: NotifierService, private changeDetectionRef: ChangeDetectorRef
  14   ) {
  15     this.updateData();
  16     this.notifier.subscribe(NotifierService.GOT_PUSH, this.gotPush.bind(this));
  17     //setInterval(this.refresh.bind(this), 5000);
  18   }
  19 
  20   // private refresh() {
  21   //   // triggers change detection when called by setInterval
  22   // }
  23 
  24   public gotPush() {
  25     try {
  26       this.updateData();
  27     } catch (e) {
  28       alert("Caught error in gotPush");
  29     }
  30   }
  31 
  32   public updateData() {
  33 
  34     this.dbService.getNotifications().then((data: string[]) => {
  35       this.items = data;
  36       this.changeDetectionRef.detectChanges();
  37     });
  38   }
  39 
  40   public ionViewDidEnter() {
  41     this.updateData();
  42   }
  43 }

db.service.ts

  • ionic generate service db

   1 import { Injectable } from '@angular/core';
   2 import { SQLite, SQLiteObject } from '@ionic-native/sqlite/ngx';
   3 
   4 @Injectable({
   5   providedIn: 'root'
   6 })
   7 export class DbService {
   8 
   9   constructor(private sqlite: SQLite) {
  10   }
  11 
  12   private getDb(): Promise<SQLiteObject> {
  13     let async: Promise<SQLiteObject> = new Promise<SQLiteObject>((resolve, reject) => {
  14       let promise = this.sqlite.create({
  15         name: 'data.db',
  16         location: 'default'
  17       });
  18 
  19       promise.then((db: SQLiteObject) => {
  20         db.executeSql('CREATE TABLE IF NOT EXISTS PushNotificationsTable (push text)', [])
  21           .then(() => {
  22             resolve(db);
  23           })
  24           .catch((e) => { reject('Table not created ' + JSON.stringify(e)); });
  25       });
  26 
  27       promise.catch(e => reject("Create db error " + JSON.stringify(e)));
  28     });
  29 
  30     return async;
  31   }
  32 
  33   public insertPush(body: string) {
  34     this.getDb().then((db: SQLiteObject) => {
  35       if (db != null) {
  36         db.executeSql('INSERT INTO PushNotificationsTable VALUES (?)', [body])
  37           .then(() => {
  38           })
  39           .catch(e => alert("Insert error " + JSON.stringify(e)));
  40       } else {
  41         alert('insertPush: this.db is null');
  42       }
  43     });
  44   }
  45 
  46   public getNotifications(): Promise<string[]> {
  47     let asyncTask: Promise<string[]> = new Promise<string[]>((resolve, reject) => {
  48 
  49       this.getDb().then((db: SQLiteObject) => {
  50         if (db != null) {
  51           db.executeSql('SELECT * FROM PushNotificationsTable', []).then((data) => {
  52             let items: string[];
  53             items = [];
  54             for (let i = 0; i < data.rows.length; i++) {
  55               let item = data.rows.item(i);
  56               items.push(item.push);
  57             }
  58             resolve(items);
  59           }).catch((e) => {
  60             reject(e);
  61           });
  62         } else {
  63           alert('getNotifications: this.db is null');
  64           reject('getNotifications: this.db is null');
  65         }
  66       });
  67     });
  68 
  69     return asyncTask;
  70   }
  71 }

EchoPlugin

  • www/EchoPlugin.js

   1 window.echo = function(str, callback) {
   2     cordova.exec(callback, function(err) {
   3         callback('Nothing to echo.');
   4     }, "Echo", "echo", [str]);
   5 };
  • echo-plugin/plugin.xml

   1 <?xml version="1.0" encoding="UTF-8"?>
   2 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
   3     id="org.allowed.bitarus.EchoPlugin"
   4     version="1.0.0">
   5     <name>echo-plugin</name>
   6     <description>echo plugin</description>
   7     <license>null</license>
   8 
   9     <js-module src="www/EchoPlugin.js" name="EchoPlugin">
  10         <clobbers target="EchoPlugin" />
  11     </js-module>
  12 
  13     <platform name="android">
  14         <config-file target="res/xml/config.xml" parent="/*">
  15             <feature name="EchoPlugin" >
  16                 <param name="android-package" value="org.allowed.bitarus.EchoPlugin"/>
  17             </feature>
  18         </config-file>
  19         <config-file target="AndroidManifest.xml" parent="/*">
  20             <uses-permission android:name="android.permission.INTERNET" />
  21         </config-file>
  22         <source-file src="src/main/java/org/allowed/bitarus/EchoPlugin.java" target-dir="src/org/allowed/bitarus" />
  23     </platform>
  24 </plugin>
  • echo-plugin/package.json

   1 {
   2   "name": "org.allowed.bitarus.echoplugin",
   3   "version": "1.0.0",
   4   "description": "Echo plugin",
   5   "cordova": {
   6     "id": "org.allowed.bitarus.echoplugin",
   7     "platforms": [
   8       "android"
   9     ]
  10   },
  11   "keywords": [
  12     "ecosystem:cordova",
  13     "cordova-android"
  14   ],
  15   "author": "Vitor",
  16   "license": "null"
  17 }
  • echo-plugin/src/main/java/org/allowed/bitarus/EchoPlugin.java

   1 package org.allowed.bitarus;
   2 
   3 import org.apache.cordova.CordovaPlugin;
   4 import org.apache.cordova.CallbackContext;
   5 import org.json.JSONArray;
   6 import org.json.JSONException;
   7 import org.json.JSONObject;
   8 import org.apache.cordova.CordovaWebView;
   9 import org.apache.cordova.CordovaInterface;
  10 
  11 public class EchoPlugin extends CordovaPlugin {
  12     @Override
  13     public void initialize(CordovaInterface cordova, CordovaWebView webView) {
  14         super.initialize(cordova, webView);
  15     }
  16 
  17     @Override
  18     public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {        
  19         if (action.equals("echo")) {
  20             String message = "Echo " + args.getString(0) + " !!!";
  21             this.echo(message, callbackContext);
  22             return true;
  23         }
  24 
  25         if (action.equals("getintentdata")) {            
  26             this.getintentdata(callbackContext);
  27             return true;
  28         }
  29 
  30 
  31         return false;
  32     }
  33 
  34     private void echo(String message, CallbackContext callbackContext) {
  35         if (message != null && message.length() > 0) {
  36             callbackContext.success(message);
  37         } else {
  38             callbackContext.error("Expected one non-empty string argument.");
  39         }
  40     }
  41 
  42     private void getintentdata(CallbackContext callbackContext) {
  43         String data = this.cordova.getActivity().getIntent().getDataString() ;      
  44         String action = this.cordova.getActivity().getIntent().getAction();
  45         String result = String.format( "{\"data\":\"%s\" , \"action\":\"%s\"}",data,action );
  46         callbackContext.success(result);
  47     }    
  48 }
  • tab1.page.ts

   1 import { Component } from '@angular/core';
   2 import { HTTP } from '@ionic-native/http/ngx';
   3 import { Platform } from '@ionic/angular';
   4 
   5 declare let cordova: any;
   6 
   7 @Component({
   8   selector: 'app-tab1',
   9   templateUrl: 'tab1.page.html',
  10   styleUrls: ['tab1.page.scss']
  11 })
  12 export class Tab1Page {
  13   public res;
  14   public echo: string;
  15 
  16   constructor(private http: HTTP, private platform: Platform) {
  17 
  18     this.platform.ready().then(() => {
  19       this.init();
  20     }
  21     );
  22 
  23   }
  24 
  25   public init() {
  26     this.getEcho();
  27   }
  28 
  29   getEcho() {
  30     if (this.platform.is('cordova')) {
  31       try {
  32         cordova.exec(
  33           (success) => {
  34             this.echo = success;
  35           },
  36           (error) => { },
  37           //feature name in  /home/vitor/MyIonicProject/echo-plugin/plugin.xml
  38           //feature name in /home/vitor/MyIonicProject/platforms/android/app/src/main/res/xml/config.xml
  39           "EchoPlugin", // class Service name
  40           "echo", // action
  41           ["argxyz"] // arguments
  42         );
  43       } catch (e) {
  44         this.echo = "Got error in get echo " + JSON.stringify(e) + e.message;
  45       }
  46     }
  47   }
  48 
  49   public ionViewDidEnter() {
  50     console.log("Stuff");
  51     this.http.get("https://labs.bitarus.allowed.org/cebapps/r/core/version/", {}, {})
  52       .then(data => {
  53         console.log(data.status);
  54         console.log(data.data); // data received by server
  55         this.res = data.data;
  56         console.log(data.headers);
  57       })
  58       .catch(error => {
  59         console.log(error.status);
  60         console.log(error.error); // error message as string
  61         console.log(error.headers);
  62       });
  63   }
  64 }
  • tab1.page.html

   1 <ion-header [translucent]="true">
   2   <ion-toolbar>
   3     <ion-title>
   4       Tab 111 {{res}}
   5     </ion-title>
   6   </ion-toolbar>
   7 </ion-header>
   8 <ion-content [fullscreen]="true">
   9   <ion-header collapse="condense">
  10     <ion-toolbar>
  11       <ion-title size="large">Tab 111</ion-title>
  12     </ion-toolbar>
  13   </ion-header>
  14   <app-explore-container name="Tab 111 page {{res}} {{echo}}"></app-explore-container>
  15 </ion-content>

SQLite

  • npm install @ionic-native/sqlite
  • node_modules/.bin/ionic cordova plugin add cordova-sqlite-storage
  • https://github.com/storesafe/cordova-sqlite-storage

// app.module.ts
import { SQLite } from '@ionic-native/sqlite/ngx';
providers SQLite

// app.component.ts 
import { SQLite } from '@ionic-native/sqlite/ngx';
constructor private sqlite:SQLite

Create service

  • node_modules/.bin/ionic generate service notifier
  • Add in providers in app.module.ts
  • Inject in constructor of classes that might use the dependency/bean/service

Angular change detection

  • https://www.mokkapps.de/blog/the-last-guide-for-angular-change-detection-you-will-ever-need/

In short, the framework will trigger a change detection if one of the following events occurs:

    any browser event (click, keyup, etc.)
    setInterval() and setTimeout()
    HTTP requests via XMLHttpRequest
  • https://angular.io/api/core/ChangeDetectorRef

constructor(private ref: ChangeDetectorRef) {
//...
this.ref.detectChanges();
  • MoinMoin Powered
  • Python Powered
  • GPL licensed
  • Valid HTML 4.01