Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building an Ionic hybrid mobile app with TypeScript

Presentation based on experiences of building a hybrid mobile app using the Ionic framework, Cordova, AngularJS and TypeScript.

  • Login to see the comments

Building an Ionic hybrid mobile app with TypeScript

  1. 1. Building a cross-platform Hybrid Ionic App with TypeScript Lessons learned in building a real-world hybrid application using the Ionic framework and TypeScript Oleksandr Zinchenko [Macaw], Serge van den Oever [Macaw]
  2. 2. Versions used This document is produced when using the following versions: • Cordova version 4.1.2 (cordova --version) • Ionic version 1.2.8 (ionic --version) • Ionic framework version 1.0.0-beta.11 (ionic lib)
  3. 3. Contents 1. Introduction 2. Minimal Ionic project structure 3. Create a project 4. Project modifications: initial structure 5. Project modifications: npm packages 6. Project modifications: shellinit 7. Project modifications: hooks 8. Project modifications: TypeScript interfaces 9. Project modifications: TypeScript compiler 10.Working with Typescript template 12.Controller template 13.Service template 14.Directive template 15.Restore existing project from source control 16.Running app 17.Debugging 18.Development tools 19.Accessing the file system 20.Development strategy 21.Best coding practices 22.Debug/release code compilation 23.Preparing for the store: Android 24.Preparing for the store: iOS 25.Update the app without store approval 26.Optimization tips 27.Ionic/Angular issues (1) 28.Ionic/Angular issues (2) 29.References
  4. 4. Introduction TypeScript. TypeScript is a strict superset of JavaScript, and adds optional static typing and class-based object-oriented programming to the language. It is designed for development of large applications and transcompiles to JavaScript. Additional features include: 1) Type annotations and compile-time type checking 2) Interfaces 3) Classes 4) Modules 5) Abbreviated "arrow" syntax for anonymous functions Cordova. Apache Cordova is a set of device APIs that allow to access native device function from JavaScript. Combined with a UI framework this allows to create cross-platform app using just HTML, CSS and JavaScript. Cordova command-line interface (cli) includes: 1) create template Cordova project 2) build app for target platform using the same source code 3) run app in an emulator or device Angular. AngularJS lets you write client-side single-page web applications using JavaScript. Its goal is to simplify both development and testing of an app by providing a framework for client-side model-view-controller (MVC) architecture. Most important concepts in AngularJS: 1) Services 2) Controllers 3) Directives Ionic. Ionic is an open source front-end SDK (CSS framework and a Javascript UI library) for developing hybrid mobile apps with HTML5. Ionic Javascript UI library is built on top of angular and cordova. The Ionic framework introduces its own command-line interface (cli) on top of the Cordova cli. Ionic cli extends Cordova cli with: 1) livereload - reload app immediately after code changes 2) packaging for store deployment – certificates 3) build in the cloud - build for iOS on Windows 4) Gulp build system and the Bower package manager The purpose of the current presentation is to show the complete developing cycle of a cross-platform hybrid app using Cordova, Angular, Ionic and TypeScript.
  5. 5. Minimal Ionic project structure The following folders and files would be created in new project: hooks - used to “hook in” actions during the different stages of the Ionic (or actually Cordova) build process node_modules - project specific node.js modules plugins - Cordova plugins are located here scss - the sass files are managed here, builds to css (we move this folder into www to enable css debugging based on generated map files in the sass compilation) www - the actual folder where the source code for our app lives. The www folder contains all files that are packaged into the native host application. All other folders and files are there to support the build process of the native application, or contains sources compiled into the www folder (like the scss folder, which we move into www). Ionic uses two package management systems: • npm - for node packages, useful for installing packages to extends the build process • packages required are managed through package.json • packages are installed in the folder node_modules • Bower - managing client-side libraries • .bowerrc contains the Bower configuration: { "directory": “www/lib" } all client-side library packages are installed in www/lib • packages required are managed through bower.json gulpfile.js is the “makefile” for the Gulp build system config.xml is the Cordova configuration file that is used in building the hybrid app
  6. 6. Create a project 1. Use either Windows, OSX or Linux (We only tested on Windows and OSX) 2. Make sure that node.js is installed (see 3. install the node package cordova and ionic globally using the node.js package manager: >npm install cordova -g (or update if already installed) >npm install ionic -g (or update if already installed) 4. Create ionic project: >ionic start myapp blank --appname "My App" –id com.mycompany.myapp --sass 5. where: myapp is the folder created in the current folder for your project blank is the template used for the project --appname specifies the name of the app --id specifies the package name (internal name) --sass specifies to use SASS for CSS precompiling 6. Add target platform (do: > ionic platform list for available platforms on your OS): >ionic platform add <PLATFORM>
  7. 7. Project modifications: initial structure 1. Move the folder scss into the folder www. All sources that are compiled should we in the www folder, so source maps can point to the original source files while debugging. 2. Change gulpfile.js so the sass folder points to the www/scss folder: var paths = {sass: ['./www/scss/**/*.scss']}; 3. Change gulpfile.js so the 'sass' task also points to the www/scss folder: gulp.src('./www/scss/') 4. Add the folders used by the package managers www/lib, node_modules, plugins, platforms to the .gitignore file (Gist). All external packages, plugins and platforms should not be managed in source control. 5. When working on Windows and using Visual Studio, it is important to mark the node_modules folder as hidden to avoid issues in Visual Studio which can’t handle deep folder structures correctly. 6. When working in Visual Studio it is recommended that each project member create his own solution file to be able to use different path to the project. *.suo files should be excluded from source control.
  8. 8. Project modifications: npm packages We also install the Cordova and Ionic packages locally inside the project folder so we can ensure specific versions of Ionic and Cordova for the project. > npm install cordova --save-dev > npm install ionic --save-dev Use the --save-dev option to register the packages as dependency, so they can be pulled in later using npm install. The information about packages would be written into package.json file (initially this file created by ionic start command). Initially the above commands install the latest versions of Cordova and Ionic. When done with development lock-down the used versions using the command: > npm shrinkwrap
  9. 9. Project modifications: shellinit 1) The project specific node packages and their commands are installed in the folder node_modules/.bin. Add this folder to the PATH (at the beginning) to ensure the usage of the project specific versions of the packages. On OSX/Linux add in the file ~/.bash-profile: export PATH=./node_modules/.bin:$PATH On Windows add file shellinit.bat (Gist) with the following lines: @rem Add the node_modules.bin folder (found with 'npm bin') to the path @cd %~dp0 @for /f %%i in ('npm bin') do set PATH=%%i;%PATH% On Windows execute the script shellinit.bat before executing command-line commands. 2) In addition you can add the following lines to be sure that all dependent packages will be always installed by their respective package manager and are up to date: @rem make sure everything is installed call npm install call bower install call tsd update call tsd rebundle call cordova restore plugins --experimental
  10. 10. Project modifications: hooks When working with a Cordova hybrid app, you might need a way to extend your build process. Cordova Hooks serves that purpose and can execute scripts before or after certain points of the build process. The obvious example of hook usage is copying app icons and splash screens to the appropriate platform folder during build (see more info here). An example of hook script for copying resources that executes after Cordova’s ‘prepare’ command is hooksafter_prepare030_resource_files.js (Gist): #!/usr/bin/env node var fs = require('fs'); var path = require('path'); var rootdir = process.argv[2]; filestocopy.forEach(function(obj) { Object.keys(obj).forEach(function(key) { var val = obj[key]; var srcfile = path.join(rootdir, key); var destfile = path.join(rootdir, val); console.log("copying "+srcfile+" to "+destfile); var destdir = path.dirname(destfile); if (fs.existsSync(srcfile) && fs.existsSync(destdir)) { fs.createReadStream(srcfile) .pipe(fs.createWriteStream(destfile)); } }); }); var filestocopy = [{ "config/ios/splashscreens/Default-568h@2x~iphone.png": "platforms/ios/MyApp/Resources/splash/Default-568h@2x~iphone.png" }, { "config/ios/splashscreens/Default-Landscape@2x~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Landscape@2x~ipad.png" }, { "config/ios/splashscreens/Default-Landscape~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Landscape~ipad.png" }, { "config/ios/splashscreens/Default-Portrait@2x~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Portrait@2x~ipad.png" }, { "config/ios/splashscreens/Default-Portrait~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Portrait~ipad.png" }, { "config/ios/splashscreens/Default@2x~iphone.png": "platforms/ios/MyApp/Resources/splash/Default@2x~iphone.png" }, { "config/ios/splashscreens/Default~iphone.png": "platforms/ios/MyApp/Resources/splash/Default~iphone.png" }];
  11. 11. Project modifications: TypeScript interfaces A large set of type definitions for common JavaScript libraries is managed by the DefinitlyTyped interfaces library. In order to be able to install definitely typed interfaces (definitions) you can use the TypeScript Definition Manager (tsd): 1. Install tsd locally (0.6.0-beta.4 or greater): >npm install tsd@next --save-dev At the time of writing tsd@next was a beta version. Later you should be able to install it using: >npm install tsd -–save-dev 2. Install all needed type definitions. For example all cordova plugins definitions: >cd www >tsd install cordova/* --save –overwrite --save –overwrite flags will save a list of installed definitions in tsd.json. 3. Add the tsd.json file to source control. Exclude the typings folder (wwwtypings) from source control. It is possible to update or restore all definitions files configured in tsd.json by: > tsd reinstall > tsd rebundle - create the tsd.d.ts file included by _reference.ts
  12. 12. Project modifications: TypeScript compiler 1. In order to be able to compile TypeScript into JavaScript we need to install the gulp-tsc npm module: > npm install gulp-tsc —save-dev 2. In the default Ionic gulpfile.js add the following bold lines to support TypeScript compilation (Gist): var typescript = require('gulp-tsc'); var paths = { sass: ['./www/scss/**/*.scss'], typescript: ['./www/scripts/**/*.ts'] }; gulp.task('default', ['sass', 'compile']); function compileTypeScript(done) { gulp.src(paths.typescript) .pipe(typescript({ sourcemap: true, out: 'tslib.js', sourceRoot: '../scripts' })) .pipe(gulp.dest('./www/js/')) .on('end', done); } gulp.task('compile', compileTypeScript); gulp.task('watch', function() { compileTypeScript();, ['sass']);, ['compile']); }); 3. The above additions compile all TypeScript files in the www/scripts folder to a single file www/js/tslib.js. Include this resulting JavaScript file in index.html: <script src="js/tslib.js"></script>
  13. 13. Working with Typescript 1. Each TypeScript file should begin with the line: /// <reference path='../_reference.ts'/> Using this reference all TypeScript files ‘know’ about each other, and editors like Visual Studio can provide intellisense. 2. Create a _reference.ts file in the www/scripts. This file should contain references to all theTypeScript files in the project: typings, services, controllers, directives, interfaces and of course the main entrypoint of the app, app.ts: /// <reference path='../typings/tsd.d.ts' /> /// <reference path="controllers/MyController.ts" /> /// <reference path="services/MyService.ts" /> /// <reference path="directives/MyDirective.ts" /> /// <reference path="interfaces/MyInterface.ts" /> /// <reference path="app.ts" /> Note that the file ../typings/tsd.d.ts is generated and maintained by the tsd tool.
  14. 14. app.ts template app.ts is the entry point of the app (Gist). 1. Add reference to _reference.ts: /// <reference path="_reference.ts"/> 2. We declare an interface for the global rootScope object $rootScope: interface IAppRootScopeService extends ng.IRootScopeService { online: boolean; lastScrollTimestamp: number; isScrolling: () => boolean; onScroll: () => void; } 3. Directives are registered using angular.module() calls: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); 4. Services should be registered using myApp.service() calls: myApp.service("serviceName", myNameSpace.MyServiceClassName); 5. Controllers should be registered in the UI-routing structure (Learn more here: myApp.config(($stateProvider, $urlRouterProvider) => { $stateProvider.state("view", { url: "/view", templateUrl: "views/view.html", controller: "ViewController" }); }); 6. Actual code entry point of the app is function ( $rootScope: ft.IAppRootScopeService ) { // myApp entry point } );
  15. 15. Controller template 1) Add reference in _reference.ts 2) Bind in app.ts to angular UI-router state: .state(‘home', { templateUrl: "views/home.html", controller: “MyController” }); /// <reference path='../_reference.ts'/> interface IMyControllerScope extends ng.IScope { vm: IMyController; // now our view model (vm) in the scope is typed } interface IMyController { myString: string; myFunction: (arg) => boolean; } class MyController implements IMyController { myString: string = ‘initial value’; // $inject annotation. It provides $injector with information about dependencies to be injected into constructor // it is better to have it close to the constructor, because the parameters must match in count and type. // See public static $inject = [ "$scope", "$rootScope“ ]; constructor( private $scope: IMyControllerScope, private $rootScope: IAppRootScopeService ) { var currentClass: MyController = this; $scope.vm = this; $scope.$on("$destroy", () => { // Clean up detached Dom elements // Clean up attached listeners }); currentClass.myString = 'assigning variables here'; } myFunction(arg): boolean { // arg processing here return true; } } Gist of the template
  16. 16. Service template /// <reference path='../_reference.ts'/> module myNameSpace { "use strict"; export class MyServiceClassName { public static $inject = [ "$log" ]; public pubVar: string; private privVar: string; constructor( private $log: ng.ILogService ) { privVar = ‘5’; } someFunction(element): number { return parseInt(privVar, 10); } } } Register a service: 1) Add reference in _reference.ts 2) Register in app.ts: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); myApp.service(“serviceName", myNameSpace.MyServiceClassName); Gist of the template Note that we’re creating a service inside myNameSpace name space. This kind of structure is useful for big proje cts. As an example you can redefine some interface inside a certain namespace and it will not affect the code out side this name space.
  17. 17. Directive template /// <reference path='../../typings/angularjs/angular.d.ts' /> interface IMyDirectiveScope extends ng.IScope { bookmarker: string; } angular.module('directive.bindonce', []) .directive('bindOnce', function () { return { restrict: 'A', scope: true, link: ($scope: IMyDirectiveScope): void => { setTimeout(() => { $scope.$destroy(); }, 0); } } }); Register a directive: 1) Add reference in _reference.ts 2) Register in app.ts file: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); Nota bene: Always use functions for your directive definitions. See: te-angularjs-code-using-typescript/ Gist of the bind-once directive
  18. 18. Restore existing project from source control 1. Update/install node.js ( 2. Pull existing project 3. >cd root_directory_of_the_project 4. >shellinit.bat - This script configures settings for command-line development with local node_modules and automatically runs: npm install – reads package.json file and installs listed packages and dependencies bower install – reads bower.json file and installs listed JavaScript libraries tsd update – reads tsd.json and installs TypeScript interfaces tsd rebundle – create tsd.d.ts file which is included to the project for references to TypeScript interfaces cordova restore plugins --experimental – reads the Cordova config.xml and installs listed plugins 5. When working on Windows AND using Visual Studio, it is important to mark the node_modules folder as hidden to avoid issues in Visual Studio which can’t handle deep folder structures correctly. 6. >ionic platform add <PLATFORM> - Adds target platform and copies installed plugins.
  19. 19. Running app To run the app on Android device: 1) enable usb debugging on your device (see tutorial) 2) install OEM USB Drivers (see docs) 3) >gulp – to build the project 4) >ionic run android – to run app from device’s file system >ionic run android ––livereload – to run app in remote server and access it from your device. Changing any of the source files will result in an immediate compilation and reload of the app. This option is extremely useful during development and debugging. To run the app on Genymotion Android emulator: 1) disable hyper-v (see tutorial) 2) install genymotion Android emulator ( 3) >ionic run android or >ionic run android –livereload (note that for Genymotion you should use >ionic run instead of ionic emulate) To run the app on IOS device //to do To run the app on IOS emulator //to do To run the app in PC browser (without Cordova support): >ionic serve – same as run --livereload but this time without Cordova and in the desktop browser.
  20. 20. Debugging 1) Android chrome debugging (Android version 4.4+) The app uses a web browser component running the Cordova api to communicate with native features of the device or emulator. The app can be debugged using the Chrome browser. The Chrome browser allows to connect remotely (url: chrome://inspect/#devices) to the app running on an android device or emulator using usb debugging. Note that this approach is not possible if you have an Android version less than 4.4. 2) IOS safari debugging //to do
  21. 21. Development tools Windows: 1) Visual Studio as an editor 2) Genymotion android emulator 3) ConEmu - Windows terminal supporting multiple tabs 4) TotalCommander with ADB plugin to get access to the file system of the device or emulator OSX: WebStorm iFunBox
  22. 22. Accessing the file system Files on a device could be accessed for read and write using org.apache.cordova.file plugin. As of v1.2.0, URLs to important file-system directories are provided as constants which make it extremely convenient, because file system on different platforms vary significantly. As an example the path to the application directory in the code looks like var path = cordova.file.applicationDirectory for both Android and iOS, but the actual value of path variable would be different. It is important to know that: 1) >ionic serve – doesn’t use Cordova at all and runs in desktop browser only. This command creates a small webserver which runs the app. To read files you can use $http requests. 2) >ionic run <PLATFORM> >ionic emulate <PLATFORM> - these runs will actually install the app on the device (or emulator) and you will have full access to the file system and app files via the cordova.file plugin. 3) >ionic run <PLATFORM> --livereload >ionic emulate <PLATFORM> --livereload these commands create a remote livereload webserver and access it from the browser component in the app. You do have access to device’s file system with the cordova.file plugin here, but you can not access the HTML, JavaScript and CSS files embedded in the app.
  23. 23. Development strategy 1) Start with browser based (w/o Cordova) development using Chrome, simulate device functionality where possible • Fast development cycle (>ionic serve) • Full Chrome debugging power • Possible to release app preview as an url accessible on dropbox or other location 2) To develop interactions with a device we should use livereload approach using a real device or an emulator (>ionic run <PLATFORM> --livereload) 3) Develop for Android, test on iOS • From Android 4.4 full remote debugging and profiling through Chrome inspect • iOS debugging is “suboptimal” 4) Test for the correct css layout on different devices for every platform. 5) Test JavaScript functionallity of the app in different platforms. The behaviour might be different (As an example: not all Cordova plugins are cross-platform).
  24. 24. Best coding practices 1. Don’t use ‘this’ pointer directly in a code as it is misleading and most likely will produce scope-related errors(in case of nested functions). Instead you should assign value of ‘this’ pointer to a definitly typed variable: var currentClass: ClassName = this; 2. Use types for all variables and functions as it helps to find type missmach. 3. Read best coding practices for TypeScript. 4. Read angularJS ‘style guide’ which contain the best coding practices for angular.
  25. 25. Debug/release code compilation In order to place the app into the web store it is recommended to: 1.minify HTML, CSS and JavaScript code 2.uglify JavaScript code 3.remove all comments from HTML, CSS and JavaScript Install ready to use gulp modules that could perform these tasks: 1.>npm install gulp-ng-annotate -–save-dev used to remove angularJS injections and comments and minifies JavaScript 2.>npm install gulp-uglify –save-dev 3.>npm install gulp-sync –save-dev helper module that is used to make sync calls of the tasks in Gulp 4.>npm install gulp-minify-html –save-dev 5.>npm install gulp-rename –save-dev used to change file name It is convinient to add these tasks to project gulpfile.js (see full gulpfile.js at Gist): var ngAnnotate = require('gulp-ng-annotate'); var uglify = require("gulp-uglify"); var gulpsync = require('gulp-sync')(gulp); var minifyHTML = require('gulp-minify-html'); var rename = require("gulp-rename"); gulp.task('compile', compileTypeScript); gulp.task('default', ['debug']); gulp.task('release', gulpsync.sync(['minifyHtml', 'sass', 'compile', 'minifyJs'])); gulp.task('debug', ['sass', 'compile']); gulp.task('minifyJs', function (done) { gulp.src('./www/js/tslib.js') .pipe(ngAnnotate({remove: true, add: true, single_quotes: true})) .pipe(uglify()) .pipe(gulp.dest('./www/js')) .on('end', done); }); gulp.task('minifyHtml', function (done) { gulp.src('./www/index.html') .pipe(minifyHTML({ empty: true })) .pipe(rename(function (path) { path.basename += "-min"; })) .pipe(gulp.dest('./www')); gulp.src('./www/views/*') .pipe(minifyHTML({ empty: true })) .pipe(gulp.dest('./www/views/min')) .on('end', done); }); Now it’s much easier to compile debug/release versions of your code: >gulp debug >gulp release
  26. 26. Preparing for the store: Android Before publishing it is necessary to: 1. increase android-versionCode in project/config.xml file 2. Build: >cordova build –release 3. sign the App with jarsigner (a part of Java SE Development Kit) 4. allign the App with zipalign (a part of Android SDK) It is convinient to write nodejs script ‘build.js’ that will handle all mentioned tasks: function shellExec(cmd, callback){ console.log(cmd + ' executing...'); exec(cmd, function(err, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (err !== null) { console.error('fatal Error: ' + err); process.exit(1); } else { typeof callback === 'function' && callback(); } }); } shellExec('cordova build --release android', function () { shellExec('jarsigner -verbose -sigalg SHA1withRSA - digestalg SHA1 –keystore <PATH_TO_KEYSTORE> <PATH_TO_release-unsigned.apk> -storepass <PASSWORD> elsevierMyApp', function() { shellExec('zipalign -v 4 <PATH_TO_release- unsigned.apk> <OUTPUT_APK_PATH>'); }); }); usage: >gulp build
  27. 27. Preparing for the store: iOS //to do
  28. 28. Update the app without store approval Why it’s important to avoid web store approval? 1) First of all it’s important because people which were not directly involved with developing could update a content. 2) Second reason is that verifying a new release could take enormous amount of time for some platforms (up to 10 days for iOS). The idea is to build a hybrid app that will be a wrapper (bootstrapper app) for an actual App (embedded app). Bootstrapper app should be configured (name, icons, splash) as it is embedded app and during the run it should redirect to the actual embedded app. Luckily it is easy to do using javaScript window.location command. Bootstrapper app contains: 1) bootstrapper files 2) platform specific file with archived Cordova and plugins 3) embedded app archived into file 4) archive containing additional app content During each start bootstrapper compares version file version.json in the app folder with version file on a remote server. If updates found bootstrapper detects it and installs new version of the embedded app or installs new content. Source code for the bootstrapper you could find at Git, flow diagram you can fins in the blogpost . (Note that this version still uses old cordova.file plugin conventions for device file system)
  29. 29. Optimization tips 1. Only release versions of the app should be published 2. Exclude console output in release version of the app 3. AngularJS ng-repeat might significantly slow down a hybrid app. Critical case is when each ng- repeat item contain other angular bindin(s) 4. Minimize amount of angular bindings in HTML code 5. Allways manually unregister Jquery listeners at onDestroy event as angular don’t do it automatically 6. Allways manually clean all detached DOM elements at onDestroy event as angular don’t do it automatically 7. Use bind-once bindings if you don’t expect binded value to be changed (see directive template) 8. Starting from angularJS v1.3.5 It is possible to turn off angular debug data (see docs)
  30. 30. Ionic/Angular issues (1) • Ionic scroll (overflow-scroll=“false”) gives problem with $ionicScrollDelegate.scrollTo() function. We solve it by using native scrolling (overflow-scroll=“true”) • Tap during scroll issue. Touching of a list item during scroll process results in firing touch event of another item. This bug could be solved by using scroll detection $ionicScrollDelegate.on- scroll or by creating a directive in case of overflow-scroll=“false”: angular.module('directive.scrolldetector', []) .directive('scrollDetector', function ($window) { return { restrict: 'A', link: function (scope, element, attrs) { function handler(e) { scope.$evalAsync(function () { scope.$eval((<any>attrs).scrollDetector); }); } scope.$on('$destroy', () => { element[0].removeEventListener("scroll", handler); }); element[0].addEventListener("scroll", handler); } } }); Next create function that we can call to check if scrolling is active: $rootScope.onScroll = () => { $rootScope.lastScrollTimestamp = (new Date()).getTime(); } $rootScope.isScrolling = () => { //to be sure that at least 300 ms we have no scrolling if ($rootScope.lastScrollTimestamp + 300 > (new Date()).getTime()) { return true; } else { return false; }} usage: in html: <ion-content overflow-scroll="true" scroll-detector="onScroll()"> in script: onTap = (e) => { if (typeof $rootScope.isScrolling == 'function' && !$rootScope.isScrolling()) { //tap event here }}
  31. 31. Ionic/Angular issues (2) • Angular digest loop and $ionicLoading sync issue. Let’s imagine that you want to use $ionicLoading mesage right before script start heavy calculation. You will probably write the following: ${ template: ‘wait…’, noBackdrop: true }); //script for heavy calc which will result in heavy calc first and only then you will see your message. Next you will probably add timeout wrapper to push your heave calc script call to digest loop right after $ call: ${ template: ‘wait…’, noBackdrop: true }); $timeout(()={ //script for heavy calc }); which results with the same problem. We don’t know the clean way to solve the issue and as a workaround we use this: ${ template: ‘wait…’, noBackdrop: true }); $timeout(()={ //script for heavy calc }, 300);
  32. 32. References 1. 2. 3. router 4. 5. 6. 7. 8. 9. 10. droid_adb.html
  33. 33. The end.