Ionic2, Webpack and ECMAScript6 boilerplate

Today we had the chance to discover a Ionic2 presentation by @adamdbradley at AngularConnect London!

This presentation announces the alpha release of Ionic2 and shares the documentation on how to start building your own app with Ionic2.

As I got pretty excited I also created a boilerplate based on the cutePuppyPics starter kit by ionic team. My version is enhanced in many ways:

  1. removes gulp dependency (only webpack is needed and because you’re worth it 😉
  2. removes ionic-cli dependency (only cordova and webpack-dev-server are needed)
  3. removes dist files (only the sources are committed)

Running this boilerplate is as easy as running these two commands:

# Install dependencies
npm install

# Run the dev server
npm run devserver

Now open your browser on http://localhost:8080/ and enjoy Ionic2 🙂

Demo (3mb, can be pretty slow to load..)

Source available on Github : https://github.com/shprink/ionic2-webpack-ES6-boilerplate

Native transitions for Ionic Framework made easier

I have heard about the Telerik’s native transition plugin for Cordova recently. To me this is not only a game changer in the hybrid industry, but in the entire mobile application industry.

Indeed with this improvement it will be really hard to tell what’s an hybrid application and what’s not. With the help of Ionic Framework, AngularJS and Cordova, hybrid applications are now sexiest than before, cheaper to produce and quicker to release. I started developing hybrid applications two years ago and the improvement made by Ionic, AngularJS, Cordova, Crosswalk are tremendous!

To help the Ionic community to use native transitions I created ionic-native-transitions a plugin available on github and npm where transitions are automatically added to your ionic application.

Just turn the plugin ON and enjoy native transitions 😉

native-transitions

Create a Mobile Application Using WordPress, Ionic, and AngularJS

Introduction

This tutorial is a post that I did for tutsplus.com. It will explain you step by step how to create a modern, hybrid, mobile application (iOS and Android) of your WordPress website using the latest technologies. We’ll be using Ionic Framework, ECMAScript 6, npm, webpack, and Apache Cordova.

http://code.tutsplus.com/tutorials/create-a-mobile-application-using-wordpress-ionic-and-angularjs–cms-24170

Ultimate AngularJS and Ionic performance cheat sheet

As a lot of persons have asked me about how to improve AngularJS and/or Ionic performance. To avoid repeating myself on forums or on Slack I decided to create this ultimate cheat sheet list!

AngularJS

$watch

If you ever need to use $watch to listen to scope changes, you better use the right one. Indeed watched properties are examined on every call to $digest(), and therefore influence your application performance. There are three different ways to $watch scope properties:

$watch(watchExpression, listener, [objectEquality]);

Registers a listener callback to be executed whenever the watchExpression changes.

This is the basic $watch, it can be used like this:

$scope.$watch('watchExpression', function(newVal, oldVal){
    if(newVal){
        // watchExpression has changed.
    }
});

If watchExpression is an object that contains objects you can use objectEquality as true to deep watch watchExpression. While this is a super feature to have, it has a huge impact on your application performance:

$scope.$watch('watchExpression', function(newVal, oldVal){
    if(newVal){
        // watchExpression has changed.
    }
}, true);

My advice is to avoid using objectEquality when possible.

$watchGroup(watchExpressions, listener);

A variant of $watch() where it watches an array of watchExpressions. If any one expression in the collection changes the listener is executed.

Introduced in AngularJS 1.3, $watchGroup allows to watch several expressions at once.

$scope.$watchGroup([
    'watchExpression',
    'watchExpression2',
    'watchExpression3'
], function(newVals, oldVals) {
    if (newVals[0]) {
        // watchExpression has changed.
    }
    if (newVals[1]) {
        // watchExpression2 has changed.
    }
    if (newVals[2]) {
        // watchExpression3 has changed.
    }
});

While $watchGroup might not improve your application performance compare to $watch, it has the advantage to be more synthetic when watching several scope expressions.

$watchCollection(obj, listener);

Shallow watches the properties of an object and fires whenever any of the properties change (for arrays, this implies watching the array items; for object maps, this implies watching the properties). If a change is detected, the listener callback is fired.

$watchCollection can be considered in between the $watch and the $watch with objectEquality (deep watch). It also works comparing object references but with the advantage to also shallow watches the properties of your object.

For instance adding an element to an array that you watch will not trigger the normal $watch but trigger the $watch with objectEquality and the $watchCollection.

I recommend using the $watchCollection over the $watch with objectEquality when necessary. It is less expensive and therefore better for performance.

To go further on $watch and $watchCollection differences I recommend this article by Ben Nadel: http://www.bennadel.com/blog/2566-scope-watch-vs-watchcollection-in-angularjs.htm


One-time binding

An expression that starts with :: is considered a one-time expression. One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value.

One-time binding :: was also introduced in Angular 1.3. It has a real impact on your application performance.

Basically using One-time binding :: on expression will remove it from the $watchers list when populated. It means that the expression will not be able to update even if the data changes.

For instance displaying the user first name on an application is unlikely to be updates, therefore is a good candidate for One-time binding :::

{{::user.first_name}}

My advice is to go through all your applications views and think about what could or could not be updated and use One-time binding :: accordingly. It will be a huge relief for the digest cycle!


Track by

track by is used to avoid useless DOM manipulation when using ng-repeat. Indeed if the digest cycle finds that at least one element of your collection has changed, ng-repeat will re-render all elements. DOM manipulation always has effects on the application performance, the less you have the better. To avoid re-rendering the complete collection and only change the elements that need to be changed use track by with a unique identifier.

Change your code from that:

ng-repeat="user in users"

to:

ng-repeat="user in users track by user.id" (if users have a unique id) or ng-repeat="user in users track by $index" if they don’t. $index is added by ng-repeat to each elements of your collection.


Logs

When using AngularJS do not use console.log, having them on a production application can slow down performances (see this jsperf). Some tools such as gulp-strip-debug automatically removes them from your code but my advice is not use console.log at all. AngularJS has a built in service that just does that: $log. It can be switched off using the $logProvider provider:

angular.module('yourModule').config(function($logProvider) {
    if (/* test if in production */) {
        $logProvider.debugEnabled(false);
    }
});

The $log service has several log levels .info .debug and .error.


Debug

AngularJS by default adds scope references to the DOM for tools such as angularjs-batarang to work. This has an impact on your application performance.

It can be disabled using the $compileProvider provider:

angular.module('yourModule').config(function($compileProvider) {
    if (/* test if in production */) {
        $compileProvider.debugInfoEnabled(false);
    }
});

Loops

Depending on the browser you use, JavaScript performance can be different. I set up 9 loop tests that go through an array of one hundred elements:

var arr = new Array(100);

# while loop
var i = 0;
while (i < arr.length) {
  arr[i];
  i++;
};

# cached while loop
var i = 0,
  len = arr.length;
while (i < len) {
  arr[i];
  i++;
};

# Reverse while loop
var i = arr.length;
while (i--) {
  arr[i];
};

# for loop
for (var i = 0; i < arr.length; ++i) {
  arr[i];
};

# cached for loop
var i = 0,
  len = arr.length
for (; i < len; ++i) {
  arr[i];
};

# Reverse for loop
for (var i = arr.length; i--;) {
  arr[i];
};

# Angular foreach
angular.forEach(arr, function(value, i) {
  arr[i];
});

# Native foreach
arr.forEach(function(value, i) {
  arr[i];
});

# Lodash foreach
_.forEach(arr, function(value, i) {
  arr[i];
});

At the end we can compare the results. What is the most performant way to iterate on an Array? Well apparently the “cached for loop” tend to be the best alternative across browsers. Native and Angular foreach are just 13 times less efficient than the cached loop…

The “cached for loop” does not re-evaluate the arr.length at every iteration, that’s why is it faster than the normal “for loop”.

It is also interesting to notice that lodash performance is four times better than angular foreach. If you do not like to use native for loops I recommend using lodash (I love this lib).


Animations

According to Ben Nadel’s blog post: Enable Animations Explicitly For A Performance Boost In AngularJS it is possible to force ngAnimate to only target elements that have a specific class name instead of checking all elements seeking for elements that could animate.

angular.module('yourModule').config(function($animateProvider) {
    $animateProvider.classNameFilter( /banimatedb/ );
});

I personally have not tested this approach but according to Ben Nadel’s numbers it could make a significant performance enhancement.


Ionic

Native scrolling

Native scrolling was released in May 2015 with Ionic 1.0. Before that Ionic relied on the JavaScript scrolling which was created to have proper events for features such as “Pull To Refresh”, Infinite Scrolling, List Reordering, or Collection Repeat. Browsers evolved to handle native scrolling events but mostly on Android, iOS in Cordova still doesn’t have completely native scroll events.

Native scrolling can be enabled using overflow-scroll=”true” on your ion-content or using the $ionicConfigProvider provider:

angular.module('yourModule').config(function($ionicConfigProvider) {
    $ionicConfigProvider.scrolling.jsScrolling(false);
});

My advice is to always enable it, once you have tested it you cannot live without it!

More information


Collection repeat

The collection-repeat directive is a directive that allows you to render lists with thousands of items and experience little to no performance penalty. It renders into the DOM only as many items as are currently visible.

Collection repeat is good for performance, but not on every cases. Indeed Collection repeat must $watch every item and item properties of your collection (you cannot use the One-time binding or track by with it). Depending on the data you want to display the number of $watchers can slow down your application.

<ion-content>
  <ion-item collection-repeat="item in items">
    {{item}}
  </ion-item>
</ion-content>

Another downside is that you cannot use native scrolling with a collection repeat.

More information


Infinite Scroll

The<ion-infinite-scroll> directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page. It has the advantage to only load the right amount of data that the user needs.

<ion-content ng-controller="MyController">
  <ion-list>
  ....
  ....
  </ion-list>

  <ion-infinite-scroll
    on-infinite="loadMore()"
    distance="1%">
  </ion-infinite-scroll>
</ion-content>

From my experience in a lot of cases using the infinite scroll combined with the One-time binding, track by and the Native scrolling is way better in terms of performance than a collection repeat.

More information


View cache

The view cache is one of Ionic’s killer feature. If enabled it keeps views in the DOM cache with their scope, current state, and scroll position. When navigating you never lose your input or scroll position so you can go back in history without the fear of losing data.

What about performance then? Well when a page is cached its scope is disconnected from the $watch cycle and reconnected when used again. It means that the number of $watchers are the same as if you do not use the view cache. However keeping views in the DOM and saving theirs states in memory have an impact on the application performance. My advice is to use this feature (it is a MUST have) but to cache only a reasonable amount of pages using the $ionicConfigProvider provider:

angular.module('yourModule').config(function($ionicConfigProvider) {
    $ionicConfigProvider.views.maxCache(5);
});

By default, Ionic will cache a maximum of 10 views, and not only can this be configured, but you can also explicitly state which views should and should not be cached using the <ion-view cache-view="false"> directive or the UI router $stateProvider provider.

$stateProvider.state('myState', {
   cache: false,
   url : '/myUrl',
   templateUrl : 'my-template.html'
});

More information


Events

When using AngularJS it is considered a good practice to load your data using the $viewContentLoaded event in controllers. When using Ionic SDK, this event is not usable, instead we have access to more specific events. The Ionic view cache comes with 8 new events, for instance “$ionicView.loaded” is triggered once per view being created and added to the DOM while the “$ionicView.enter” event will fire, whether it was the first load or a cached view.

Using the right event to load your data can improve the usability of the application. Indeed the less HTTP requests you send the better for the usability.

Here is the complete list of events that you can use with Ionic:

$scope.$on('$ionicView.loaded', function(){});
$scope.$on('$ionicView.enter', function(){});
$scope.$on('$ionicView.leave', function(){});
$scope.$on('$ionicView.beforeEnter', function(){});
$scope.$on('$ionicView.beforeLeave', function(){});
$scope.$on('$ionicView.afterEnter', function(){});
$scope.$on('$ionicView.afterLeave', function(){});
$scope.$on('$ionicView.unloaded', function(){});

More information


Native transitions

It is now possible to use native transitions within Ionic applications. I created ionic-native-transitions, a plugin that helps you configuring Telerik’s native transition Cordova plugin.

More information


Cordova

Crosswalk

I highly recommend using Crosswalk. Basically it embedded the latest chromium into the app (adding around 20Mb per apk: ARM and X86) so you have the same experience on every android version/device.

Installing it is as easy as that:

cordova plugin add cordova-plugin-crosswalk-webview@1.2.0

Try it out, for me Crosswalk has been a game changer in the hybrid industry, it makes applications smoother.


That’s all I could come up with on top of my head, if I missed things please let me know by commenting.

Modular AngularJS and Ionic architecture: a first step towards AngularJS 2

This post describes the architecture that you can use RIGHT NOW on your AngularJS 1.x or Ionic applications and that will be compatible with AngularJS 2. When the time comes and according to this article: Angular 1 and 2 running together, you will be able to migrate easily your application, module by module.

Forget what you know

A large majority of the Ionic, AngularJS 1.x projects are using Bower, Gulp and a folder-by-type architecture. If you want to build large scale applications with several developers, you will definitely have problems if you follow that kind of architecture.

AngularJS is often used to create prototypes and MVP really quickly so why bother? Well, we all know what happen to prototypes and MVPs that somehow work… they go directly into production. If you have reached that point, it is not too late to restructure your code and think about it before your application turns into FrankenstApp!


Bower

Here are few reasons not to use Bower:

  1. It does not support CommonJS out of the box.
  2. Using npm and Bower at the same time is a non sense (they both fulfill the same need).
  3. npm has become the most popular package manager for JavaScript.
  4. Requires closures to avoid scope leaking.

If you want to know more reasons I recommend you to read this article: Why my team uses npm instead of bower

What is CommonJS?

The CommonJS group defined a module format to solve JavaScript scope issues by making sure each module is executed in its own namespace.

CommonJS handle modules outside the browser and works great with ECMAScript 5 or 6.

// Import with ECMAScript 5
var angular = require('angular');

// Export with ECMAScript 5
module.exports = function(){}

// Import with ECMAScript 6
import angular from 'angular';

// Export with ECMAScript 6
export default function(){}

Gulp

Few reasons not to use Gulp:

  1. Compiling, concatenating and minifying your application require to install a lot of dependencies (gulp-concat, gulp-minify-css, express, livereload etc.).
  2. Basic needs (web server, livereload, concat etc) require to create many scripts that YOU will need to maintain yourself.

In 2015 it should not be that complicated to fulfill your application’s basic needs. The solution is to use Webpack.


Folder-by-type structure

The folder-by-type structure is basically grouping JavaScript files by types (controllers, configs, views, directives etc.) as followed:

app/
    app.js
    controllers/
        aaa.js
        bbb.js
        ccc.js
    directives/
        ddd.directive.js
        eee.directive.js
        fff.directive.js
    services/
        xxx.js
        yyy.js
        zzz.js
    views/
        aaa.html
        bbb.html
        ccc.html
        ddd.directive.html
        eee.directive.html
        fff.directive.html

This folder architecture is a terrible idea for large scale applications. I have experienced it before and it is not a good memory, especially if you are several developers to work at the same time. Here are some reasons not to use it:

  1. The number of files in your folders can become really large.
  2. Finding all the files you need to modify for a specific feature can be tricky.
  3. Working on a feature will lead to open many folders.

If you do not trust me, at least trust John Papa’s styleguide 🙂

A better solution is to Create components/modules with a Folders-by-Feature structure.


Use Webpack

Webpack is a module bundler, it takes modules with dependencies and generates static assets.

Webpack and Webpack-dev-server easily replace Gulp for basic application needs (web server, livereload, concatenation, minification, compliling JS or Sass etc.). Instead of having to maintain several Gulp scripts, what you only need is a configuration file webpack.config.js… that’s ALL!

For instance having an autoprefixed CSS injected into your application from several Sass files is as simple as that with Webpack:

{
    test: /.scss$/,
    loader: "style!css!autoprefixer!sass"
}

No need to show you the equivalent using Gulp or Grunt, I think you got my point! If you want to go further with Webpack you can read this article I created some time ago: Introduction to Webpack with practical examples


Create components/modules

The solution to large scale applications is to create loosely coupled modules. I have been doing AngularJS applications for a long time now and after a lot of experimenting I have settled to the following architecture:

  • Every file that can be edited, live in the src/ or /lib folder.
  • Every AngularJS module needs a proper folder.
  • Every module file *.module.js must define a unique namespace (and must be the only place where this namespace appears).
  • Every module file *.module.js must declare all its dependencies (even if dependencies are already injected in the app).
  • Every module file *.module.js must declare all its configs, controllers, services, filters etc.
  • Every config, controller, service, filter etc. must export a function or a Class.
  • If a module needs some specific style, the .scss file must live within the module as well.

All of this is very powerful, it assures you to have modules that can be shared by several applications without getting any error (except for missing dependencies).

Here an example of a home module structure:

lib/
    index.js
    home/
        home.module.js
        home.config.js
        home.service.js
        home.controller.js
        home.html
        home.scss

Now here is the home.module.js file using ECMAScript 6:

import modConfig from './home.config';
import modController from './home.controller';

let mod = angular.module('prototype.home', [
    'ionic',
    'ui.router'
]);

mod.config(modConfig);
mod.controller('HomeController', modController);

export default mod = mod.name

Use Folders-by-Feature structure

Reasons to use Folders-by-Feature structure:

  1. The number of files in your folders are limited to few.
  2. Finding all the files you need to modify for a specific feature is easy (they are in the same folder!).
  3. You can work independently on a feature.
  4. Knowing what the module represents is easy (the folder name is sufficient).
lib/
    index.js
    home/
        home.module.js
        home.config.js
        home.service.js
        home.controller.js
        home.html
        home.scss
    parameters/
        parameters.module.js
        parameters.config.js
        parameters.service.js
        parameters.controller.js
        parameters.html
        parameters.scss

Recommended boilerplates

If you are ready to start making some changes in your application with the architecture I suggested in this post you can clone those repositories, they are a good start:

  1. [Angular Material]: shprink/angular1.4-ES6-material-webpack-boilerplate. A simple AngularJS 1.4 boilerplate using ES6, material design and Webpack.
  2. [Ionic]: shprink/ios-android-wordpress-ionic-webpack-ES6. Repo created for the TutsPlus article: Creating iOS/Android mobile applications for WordPress using Ionic SDK, Webpack, ES6 and WP-API.

iOS / Android push notifications 100% free and self hosted for WordPress using Cordova and Ionic

Push notification is always a pain when it comes to find the perfect free service, there are several possibilities like pushwoosh, pushapps, pushover etc.

If you are hosting your WordPress website there is no need to subscribe any of those services. With your server you have already what it takes to send push notifications to your subscriber.

No third party service involved, just your WordPress server and your application.

It all start with installing Push Notifications for WordPress (Lite) plugin to your WordPress.

Send push notifications to iOS, Android, and Fire OS devices when you publish a new post. Straight from your WordPress site, in real-time.

Installation

  1. Search and install “Push Notifications for WordPress (Lite)” from the Plugins WordPress page
  2. Activate “Push Notifications for WordPress (Lite)” through the ‘Plugins’ menu in WordPress
  3. Configure the plugin by going to the Push Notifications menu that appears in your admin menu

Android

If you have not already done so, you’ll need to set up a Google API project, to generate your senderID. Follow these steps to do so.

Get the SenderID

Signing into https://developers.google.com/mobile/add and follow the steps to get Cloud messaging senderID and apiKey.

Tip: The senderID is a 12 digit number

Configure the WordPress plugin

Go to Push Notifications > Settings and check the following checkboxes:

  • Basic Options > Send push notifications when a new post is published
  • Basic Options > Android devices
  • Send Push Notifications for > Posts
  • Misc > In the Android notification payload add the message field

Then go to “Android Push Notifications (via GMC)” section and enter you Google Api key.

Do not forget to save.


iOS

Configure the WordPress plugin

Go to Push Notifications > Settings and check the following checkboxes:

  • Basic Options > Send push notifications when a new post is published
  • Basic Options > iOS devices
  • Send Push Notifications for > Posts

Do not forget to save.

Certificates and Provisioning profiles

This part is really painful (Generally when you have to use Apple’s service it is…). It is all well explained there: http://strangemilk.com/ionic-push-notifications-with-ios/

Create .pem

Get .perm files

Once you have got your .pem files upload them in the iOS Push Notifications section

Setup Ionic / Cordova

I recommend using NgCordova and the NgCordova pushNotifications plugin

Installation

cordova plugin add https://github.com/phonegap-build/PushPlugin.git

# Or if you are using Ionic CLI
ionic plugin add https://github.com/phonegap-build/PushPlugin.git

Register to “Push Notifications for WordPress (Lite)”

“Push Notifications for WordPress (Lite)” exposes a Web service API that you can access over HTTP.

It only takes the OS (iOS | Android) and the device token.

function register(os, token) {
        var baseUrl;
        baseUrl = 'http://yourDomainName.com/pnfw';
        if (!baseUrl) {
            return $q.reject();
        }
        return $http({
            method: 'POST',
            url: baseUrl + '/register',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            transformRequest: function(obj) {
                var p, str;
                str = [];
                for (p in obj) {
                    str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
                }
                return str.join('&');
            },
            data: {
                os: os,
                token: token
            }
        });
    };

iOS

$cordovaPush.register(iosConfig).then(function(deviceToken) {
    register('iOS', deviceToken).success(function() {
        return $log.info('Push notif Token stored');
    });
    $log.debug('iOS push notification registration success', deviceToken);
}, function(err) {
    $log.error('iOS push notification registration error', err);
});

$rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
    $log.debug('Push notif message', notification);
    if (notification.alert) {
        if (notification.foreground) { // If your user is using the app
            // Do something like opening the Post within the app
            // You have access to
            // notification.id which is the new Post ID
            // notification.alert which is the new Post Title
        } else { // If your user has clicked on the notification
            // Do something like opening the Post within the app
            // You have access to
            // notification.id which is the new Post ID
            // notification.alert which is the new Post Title
        }
    }
    if (notification.badge) {
        return $cordovaPush.setBadgeNumber(notification.badge).then(function(result) {
            $log.debug('Push notif badge ok', result);
        }, function(err) {
            $log.debug('Push notif badge error', err);
        });
    }
});

Android

$cordovaPush.register(androidConfig).then(function(result) {
    $log.debug('android push notification registration success', result);
}, function(err) {
    $log.error('android push notification registration error', err);
});
return $rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
    switch (notification.event) {
        case 'registered':
            if (!notification.regid.length) {
                return;
            }
            $log.debug('registration ID', notification.regid);
            register('Android', notification.regid).success(function() {
                return $log.info('Push notif Token stored');
            });
            break;
        case 'message':
            $log.debug('Push notif message', notification);
            if (notification.foreground) { // If your user is using the app
                // Do something like opening the Post within the app
                // You have access to
                // notification.payload.id which is the new Post ID
                // notification.payload.message which is the new Post Title
            } else { // If your user has clicked on the notification
                // Do something like opening the Post within the app
                // You have access to
                // notification.payload.id which is the new Post ID
                // notification.payload.message which is the new Post Title
            }
            break;
        case 'error':
            $log.debug('Push notif error', notification);
            break;
    }
});

All in one

angular.module('yourModuleName').run(function($log, $cordovaPush, $rootScope, $http, $ionicPlatform) {
    var androidConfig, iosConfig, register;

    androidConfig = {
        "senderID": ""
    };
    iosConfig = {
        "badge": true,
        "sound": true,
        "alert": true
    };

    register = function(os, token) {
        var baseUrl;
        baseUrl = 'http://yourDomainName.com/pnfw';
        if (!baseUrl) {
            return $q.reject();
        }
        return $http({
            method: 'POST',
            url: baseUrl + '/register',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            transformRequest: function(obj) {
                var p, str;
                str = [];
                for (p in obj) {
                    str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
                }
                return str.join('&');
            },
            data: {
                os: os,
                token: token
            }
        });
    };
    return $ionicPlatform.ready(function() {
        if (ionic.Platform.isAndroid()) {
            $cordovaPush.register(androidConfig).then(function(result) {
                $log.debug('android push notification registration success', result);
            }, function(err) {
                $log.error('android push notification registration error', err);
            });
            return $rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
                switch (notification.event) {
                    case 'registered':
                        if (!notification.regid.length) {
                            return;
                        }
                        $log.debug('registration ID', notification.regid);
                        register('Android', notification.regid).success(function() {
                            return $log.info('Push notif Token stored');
                        });
                        break;
                    case 'message':
                        $log.debug('Push notif message', notification);
                        if (notification.foreground) { // If your user is using the app
                            // Do something like opening the Post within the app
                            // You have access to
                            // notification.payload.id which is the new Post ID
                            // notification.payload.message which is the new Post Title
                        } else { // If your user has clicked on the notification
                            // Do something like opening the Post within the app
                            // You have access to
                            // notification.payload.id which is the new Post ID
                            // notification.payload.message which is the new Post Title
                        }
                        break;
                    case 'error':
                        $log.debug('Push notif error', notification);
                        break;
                }
            });
        } else if (ionic.Platform.isIOS()) {
            $cordovaPush.register(iosConfig).then(function(deviceToken) {
                register('iOS', deviceToken).success(function() {
                    return $log.info('Push notif Token stored');
                });
                $log.debug('iOS push notification registration success', deviceToken);
            }, function(err) {
                $log.error('iOS push notification registration error', err);
            });
            return $rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
                $log.debug('Push notif message', notification);
                if (notification.alert) {
                    if (notification.foreground) { // If your user is using the app
                        // Do something like opening the Post within the app
                        // You have access to
                        // notification.id which is the new Post ID
                        // notification.alert which is the new Post Title
                    } else { // If your user has clicked on the notification
                        // Do something like opening the Post within the app
                        // You have access to
                        // notification.id which is the new Post ID
                        // notification.alert which is the new Post Title
                    }
                }
                if (notification.badge) {
                    return $cordovaPush.setBadgeNumber(notification.badge).then(function(result) {
                        $log.debug('Push notif badge ok', result);
                    }, function(err) {
                        $log.debug('Push notif badge error', err);
                    });
                }
            });
        }
    }, false);
});

WordPress Hybrid Client

If you want your WordPress website available on iOS and Android there is a simple free and Open Sourced solution: WordPress Hybrid Client

With WPHC (WordPress Hybrid Client), your WordPress website application (iOS and Android) is just a build away.

Here is the features already available and a lot more is coming:

  1. Push Notifications
  2. Social buttons
  3. About Page
  4. Params Page
  5. Language switch [French|English|Chinese]
  6. Accessibility (Post font size)
  7. App rate
  8. Docker support for easier installation
  9. Syntax highlighter for tech blogs

MISC: Test Push Notifications on Android

If you want to test that GMC is correctly setup and that your device receive notifications you can follow this tutorial: Sending push notifications to Android via Gulp

Sending push notifications to Android via Gulp

If you ever wondered how to test that your push notifications work on Android without setting up any server here is how to do.

Install

npm install gulp node-gcm

Get Api key, Sender ID and Device ID

In order to be able to send push notifications we need only need the Google Cloud Api key, and the device ID(s).

To get the Api key and the senderID you can register there: https://developers.google.com/mobile/add

As for the device ID it can be found once your device is registered.

If you are using this Cordova plugin https://github.com/phonegap-build/PushPlugin you can get it like this (note that the senderID is used here):

document.addEventListener("deviceready", function() {
    var pushNotification = window.plugins.pushNotification;
    pushNotification.register(
        successHandler,
        errorHandler, {
            "senderID": "replace_with_sender_id (12 digits number)",
            "ecb": "onNotification"
        });

    function onNotification(e) {
        switch (e.event) {
            case 'registered':
                if (e.regid.length > 0) {
                    // Your GCM push server needs to know the regID before it can push to this device
                    // here is where you might want to send it the regID for later use.
                    console.log('Device id', e.regid);
                }
                break;
        }
    }

    function successHandler() {}

    function errorHandler() {}
});

Script

Now that you have both Device ID and Api key let’s create a script that send push notifications.

gulp.task('push:android', function() {
    if (!gutil.env.apiKey || gutil.env.apiKey === true) {
        throw new Error('You must specify the android Api key, refer to the documentation');
    }
    if (!gutil.env.deviceId || gutil.env.deviceId === true) {
        throw new Error('You must specify the android ID, refer to the documentation');
    }

    console.log('apiKey', gutil.env.apiKey);
    console.log('deviceId', gutil.env.deviceId);

    var gcm = require('node-gcm')

    var message = new gcm.Message({
        collapseKey: 'demo',
        delayWhileIdle: true,
        timeToLive: 3,
        data: {
            key1: 'message1',
            key2: 'message2'
        }
    });

    var sender = new gcm.Sender(gutil.env.apiKey);

    sender.send(message, (gutil.env.deviceId instanceof Array) ? gutil.env.deviceId : [gutil.env.deviceId], 5, function(err, result) {
        if (err) {
            console.error('Failed, status code', err);
        } else {
            console.log('Success', result);
        }
    });
})

Run

You can run the script like like this on one or several devices:

# One device
gulp push:android --apiKey YOUR_API_KEY --deviceId YOUR_DEVICE_ID

# Two devices
gulp push:android --apiKey YOUR_API_KEY --deviceId YOUR_DEVICE_ID --deviceId YOUR_DEVICE_ID

If everything is fine you should have your push notifications working.

Commun error

If your api key and senderId are not ok you will get this error message:

Success { multicast_id: 7412383159195664000,
  success: 0,
  failure: 1,
  canonical_ids: 0,
  results: [ { error: 'MismatchSenderId' } ] }

If so regenerate a api key using this link https://github.com/phonegap-build/PushPlugin.

Creating an application with AngularJS 1.4, ECMAScript 6, Material Design and Webpack

AngularJS 1.4 has now been released.

It introduces a new Router, a translation system similar to angular-translate created by Pascal Precht, some performance enhancement and a better Webpack, Browserify support (CommonJS) without any “hacks”. You can for example directly import AngularJS like this

import 'angular/angular.js';

instead of this

require('expose?angular!exports?window.angular!angular/angular.js')

Demo

Source available on Github : https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate


Basic Needs

Dependencies (package.json)

For this tutorial we will need AngularJS, Angular Material, the UI router (The new router is not ready for production yet) and a icon library.

"dependencies": {
    "angular": "~1.4.0",
    "angular-animate": "~1.4.0",
    "angular-aria": "~1.4.0",
    "angular-material": "^0.10.1",
    "angular-ui-router": "^0.2.14",
    "font-awesome": "^4.3.0"
}

Webpack

If you need an explanation on what is Webpack for, I suggest you go check out a previous post of mine: http://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/

We will need the following Webpack loaders to be able to compile ECMAScript 6 code and to process CSS, HTML files.

"devDependencies": {
    "babel-loader": "^5.0.0",
    "css-loader": "^0.12.0",
    "file-loader": "^0.8.1",
    "html-loader": "^0.3.0",
    "html-webpack-plugin": "^1.3.0",
    "style-loader": "^0.12.1"
}

The webpack.config.js cannot be easier:

module.exports = {
    entry: './lib/index.js',
    output: {
        path: './www',
        filename: 'bundle-[hash:6].js'
    },
    module: {
        loaders: [{
            test: /.html$/,
            loader: 'file?name=templates/[name]-[hash:6].html'
        }, {
            test: /.css$/,
            loader: "style!css"
        }, {
            test: /.js$/,
            exclude: /(node_modules)/,
            loader: "ng-annotate?add=true!babel"
        }, {
            test: [/fontawesome-webfont.svg/, /fontawesome-webfont.eot/],
            loader: 'file?name=fonts/[name].[ext]'
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './lib/index.html'
        })
    ]
};

Entry point (lib/index.js)

The following entry point gathers all our application basic needs: Angular, Material Design, the router and the icons. Here we use import which is the ECMAScript 6 way to require CommonJS modules, inject angularMaterial and angularUIRouter as our module dependencies and to finish we export our module as default (You can export several modules within a single file, default is the export you will get if you do not specify a specific import).

// Import angular
import 'angular/angular.js';
// Material design css
import 'angular-material/angular-material.css';
// Icons
import 'font-awesome/css/font-awesome.css';
// Materail Design lib
import angularMaterial from 'angular-material';
// Router
import angularUIRouter from 'angular-ui-router';

// Create our demo module
let demoModule = angular.module('demo', [
    angularMaterial,
    angularUIRouter
])

export default demoModule;

Index.html

The index.html needs two things. A way to bootstrap the application (here ng-app="demo") and a way to include the JavaScript file generated by Webpack (here src="{%=o.htmlWebpackPlugin.assets[chunk]%}").

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    </head>
    <body ng-strict-di ng-app="demo">
        {% for (var chunk in o.htmlWebpackPlugin.assets) { %}
        <script src="{%=o.htmlWebpackPlugin.assets[chunk]%}"></script>
        {% } %}
    </body>
</html>

Now you should have your demo module running. To make sure it works add the following lines to your entry point:

demoModule.run(($log) => {
    $log.info('demo running');
})

and check the console!


Going further

Create your own module

Now that our application is running let’s create a home module with ES6!

// Create a new module
let homeModule = angular.module('demo.home', []);
// Named export is needed to inject modules directly as Angular dependencies
export default homeModule = homeModule.name

Then we can import it the same way as other modules:

import home from './home/home.module.js';

// Create our demo module
let demoModule = angular.module('demo', [
    angularMaterial,
    angularUIRouter,
    home
])

Now let’s create a controller function './home.controller' that will be imported by our new module:

export default function($scope) {
    'ngInject';
}

'ngInject'; is an annotation of ng-annotate that allow us to use AngularJS in strict mode. If you want to know more about Ng-annotate here is an explanation: http://julienrenaux.fr/2015/01/18/angularjs-1-x-open-source-projects-to-follow-in-2015/#Ng-Annotate

We can then import the function that way:

let homeModule = angular.module('demo.home', []);

import HomeController from './home.controller';

homeModule.controller('HomeController', HomeController);

export default homeModule = homeModule.name

Full demo

A working example is available on Github, feel free to fork: https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate

Install

git clone git@github.com:shprink/angular1.4-ES6-material-webpack-boilerplate.git
cd angular1.4-ES6-material-webpack-boilerplate.git
npm install

Dev (liverelaod server)

npm run-script devserver

Build

npm run-script build

Creating an hybrid app in minutes with Ionic Framework

Creating hybrid apps with Ionic is really fast and powerful. I have gather a year of information to create an ultimate presentation of Ionic in a airpair blog post: A year using Ionic to build hybrid applications

If you only want a summary of what’s inside this post you can check out the below presentation. It contains all you need to know to create, build and package an hybrid app with Ionic!

[iframely]http://www.slideshare.net/julienrenaux/hybrid-apps-withionic[/iframely]

Some quick tips:

  • Develop in the browser with live reload: ionic serve
  • Add a platform (ios or Android): ionic platform add ios [android] Note: iOS development requires OS X currently
  • Build your app: ionic build
  • Simulate your app: ionic emulate
  • Run your app on a device: ionic run
  • Package an app using Ionic package service: ionic package

AngularJs 1.x Open Source projects to follow in 2015

Ionic Framework

ionic

Ionic needs no introduction, it is a HTML5 Mobile Framework for building, cross-platform hybrid native apps with HTML, JavaScript, and CSS.

In 2014 Ionic became one of the top 50 most popular open source projects in the world, with over 12,000 stars on GitHub and over 50,000 new apps were created using Ionic Framework.

2015 will be an important year for Ionic as they will slowly move from a simple HTML5 hybrid framework to a whole galaxy of tools to create hybrid apps. The npm ionic package is already available with features such as building cordova apps or creating splashscreens and icons for IOS and Android.

Developers to follow:


Angular Material Design

Material Design is a Google specification for a unified system of visual, motion, and interaction design that adapts across different devices.

angular/material is a lean, lightweight set of AngularJS-native UI elements that implement the material design specification for use in Angular single-page applications (SPAs). This is the official AngularJs Material Design library.

No doubt that 2015 will be the year of Material Design, it is already everywhere from Android to Polymer. I have a lot of expectations for this library that I already use in my current company. Unfortunately a lot of features are missing (menu, dropdown menu, select, multi-select etc.) and the development pace is not high enough to reach the planning explained at the end of this video:

Go Google go!

Developers to follow:


lumX Material Design

lumx

Material Design is a Google specification for a unified system of visual, motion, and interaction design that adapts across different devices.

LumX will help you to design beautiful applications, faster and easier, respecting Material Design specification in a pixel perfect way.

In a lot of aspects this set of directives is more advanced than the official Angular Material Design repository. I really hope this project will have the attention it deserves. A downside of it though is that it depends on jQuery..

Developers to follow:


Foundation for Apps

foundation_apps

Foundation for Apps is an Angular-powered framework for building powerful responsive web apps. With this project the Zurb foundation is clearly trying to compete with Ionic Framework. There is still a lot of work to do but it sounds really promissing!

Developers to follow:


Angular Hint – Runtime hinting for AngularJS

Whether you start a new project or want to have feedbacks on an existing Angular app, this project is for you. It basically tells you if you follow AngularJs’s standards or not.

If you do not want to add this project to your development dependencies you can use a Chrome plugin that includes it.

If you also wants to follow AngularJs’s best practice I suggest you to read John Papa’s angularjs-styleguide. There are a lot of great advices in there and I personally always go through it before starting a new project. Some are explained in this video:

Developers to follow:


Angular-google-maps

angular-google-map

Angular-google-maps is a set of directives for the Google Maps JavaScript API. It is part of the great Angular UI organization. This repository changed a lot in Q4 2014 and released 2.x versions that is really popular lately.

Developers to follow:


Ng-Annotate

If you are familiar with AngularJs and it’s concept of Dependency Injection (DI), you know that it can be really annoying to use when minifying your code:

Minification KO

angular.module('ngAppStrictDemo', [])
// BadController will fail to instantiate, due to relying on automatic function annotation,
// rather than an explicit annotation
.controller('BadController', function($scope) {
  $scope.a = 1;
  $scope.b = 2;
})

Minification OK

angular.module('ngAppStrictDemo', [])
// Unlike BadController, GoodController will not fail to be instantiated,
// due to using explicit annotations using the array style.
.controller('GoodController', ['$scope', function($scope) {
  $scope.a = 1;
  $scope.b = 2;
}])

angular.module('ngAppStrictDemo', [])
// Unlike BadController, GoodController2 will not fail to be instantiated,
// due to using the $inject property.
.controller('GoodController2', GoodController2);
function GoodController2($scope) {
  $scope.name = "World";
}
GoodController2.$inject = ['$scope'];

Before AngularJs 1.3 it was difficult to know if you code was production ready (minifiable) or not. To tackle this very problematic AngularJs 1.3 introduced the ngStrictDi directive which tells you if your code is production ready or not.

Ng-Annotate basically makes the “Minification KO” example a production ready code! You do not have to worry about the $inject property or the array style anymore. This project literally changed my life, with it I was able to remove all the duplicate service injection ['$scope', function($scope) and the $inject property GoodController2.$inject that I used before.

Developers to follow: