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 memory stats

If you are familiar with AngularJS development, you know that memory consumption is one of the highest challenge you must face using it.

Introducing angular-memory-stats

angular-memory-stats

angular-memory-stats is a NPM package that allow you to follow the memory consumption of your AngularJS application.

Install via NPM

npm i angular-memory-stats --save

Include the AngularJS module to your application

angular.module('yourModule', [
    'angular-memory-stats'
])

Insert the directive in the dom

<angular-memory-stats></angular-memory-stats>

Enable/Disable angular-memory-stats

angular-memory-stats is enabled by default, if you wish to disable it use the angularMemoryStatsProvider Provider

angular.module('yourModule').config(function(angularMemoryStatsProvider){
    angularMemoryStatsProvider.enable(false)
});

Then all you need to do is to launch Chrome (only available on Chrome for now) with the --enable-precise-memory-info and --enable-memory-info flags

# Linux
google-chrome --enable-precise-memory-info --enable-memory-info

#MacOS
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome --enable-precise-memory-info --enable-memory-info

Open your application and you will have the following indicator on the bottom right corner of your browser:

angular-memory-stats

Source available on Github

AngularJs, Browserify Polymer and Sass boilerplate

Source available on Github : https://github.com/shprink/angularjs-browserify-polymer-boilerplate

Two way data biding

Using Polymer and AngularJs at the same time is a bit problematic. The two way data biding (AngularJs feature) cannot natively work with Polimer web components. Some project are emerging though:

Those projects are not mature enought to use, so I decided to directly use AngularJs’s resources within Polymer elements.

Using AngularJs’s services within Polymer

var userService = angular.injector(['boilerplate']).get('UserService');

Polymer('user-list', {
    ready: function() {
        this.list = userService.getList();
    },
    tapAction: function(e) {
        console.log('tap', e);
    }
});

Using AngularJs’s scope within Polymer

Polymer('boilerplate-login', {
    ready: function() {
        this.angularScope = angular.element(this).scope();
    },
    sendForm: function(){
        this.angularScope.goToHome();
    }
});

Ionic Framework features you may have missed

Ionic Framework is one of the best framework for developing hybrid mobile apps with HTML5. Based on AngularJS the set of available features is tremendous. This post presents, with examples, some of the best hidden features provided.

Scroll

Scroll documentation

Infinite Scroll

The ionInfiniteScroll directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”jukJh” default_tab=”result” user=”shprink”]See the Pen Infinite Scroll: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

List

List documentation

Collection repeat

The collection-repeat directive is a directive that allows you to render lists with thousands of items in them, and experience little to no performance penalty.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”HoIDJ” default_tab=”result” user=”shprink”]See the Pen collection-repeat: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Gesture

$ionicGesture documentation

Events

The gesture service has only two methods, on adds an event listener for an DOM element and off removes it. While AngularJS ngTouch provides only three touch events (ngClick, ngSwipeLeft and ngSwipeRight) $ionicGesture provides dozens (hold, tap, doubletap, drag, dragstart etc.).

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”txliu” default_tab=”result” user=”shprink”]See the Pen Ionic $ionicGesture example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Dom manipulation

DomUtil documentation

If you are accustomed to AngularJS I am sure that you experienced some difficulties when manipulating the DOM. JQlite helps but is itself very limited. Ionic provides some methods to help you deal with it.

ionic.DomUtil.ready

Call a function when the DOM is ready, or if it is already ready call the function immediately.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”BxufK” default_tab=”result” user=”shprink”]See the Pen ionic.DomUtil.ready Example by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.DomUtil.getParentWithClass

Returns the closest parent of element matching the className, or null.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”lDrpb” default_tab=”result” user=”shprink”]See the Pen ionic.DomUtil.getParentWithClass Example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Utilities

ionic.throttle

Only call a function once in the given interval. In this example the function should be called half as many as we tried.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”iefAE” default_tab=”result” user=”shprink”]See the Pen Ionic Throttle example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.debounce

Only call a function once in the given interval, the timer is reset on every call. In this example the function should never be called.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”yzrsD” default_tab=”result” user=”shprink”]See the Pen Ionic Debounce example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.Utils.arrayMove

Really useful function that manipulates array items position.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”HghBw” default_tab=”result” user=”shprink”]See the Pen Ionic arrayMove example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Tabs

Starting from ionic beta.14 we can select the position of the tabs through configuration.

Tabs top

.config(function($ionicConfigProvider){
    $ionicConfigProvider.tabs.position('top');
})

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”qlECF” default_tab=”result” user=”shprink”]See the Pen Tabs Top: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Tabs bottom

.config(function($ionicConfigProvider){
    $ionicConfigProvider.tabs.position('bottom');
})

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”emXyjV” default_tab=”result” user=”shprink”]See the Pen Tabs bottom: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Delegation

Delegation allow you to have several instances of the same component within the same view. You have this capability on ion-side-menus, ion-tabs,ion-scroll ion-content, ion-list and ion-slide-box using the delegate-handle directive attribute.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”CsBhf” default_tab=”result” user=”shprink”]See the Pen Ionic Side Menu delegation: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Create a “load more” widget using AngularJS, Ajax and Bootstrap 3

<

div class=”btn-group btn-group-justified”>
Demo<a class=”btn btn-info btn-lg btn-block”” href=”http://julienrenaux.fr/wp-content/uploads/2013/10/load-more-angularjs.zip”> Download

Prerequisite

Make sure you have basics on Bootstrap 3 Framework and AngularJS. If you are used to Boostrap 2.3.2 here is a post I wrote about what’s new in Twitter Bootstrap 3

Step 1: Getting the data ready

Before doing anything a good practice is to focus on the data format you want your API to return. Within this demo we will not focus on how to get the data (BackEnd code) but instead we will just pretend the API works and return the data we want in the way we want.

An example of the backend code using PHP and WordPress is shown on the demo.

By knowing the format, data manipulation gets easier. For my demo I want the API to return an array filled with post objects: [{},{}, ...] which is a pretty classic format.

Example

[
    {
        "post_title":"How to automatically checkout the latest tag of a Git repository",
        "post_content":"Now that you know how to automatically tag a Git repository an interesting command to know about is "How to automatically checkout the latest tag of a Git repository". Let's imagine that you want to a...",
        "post_name":"how-to-automatically-checkout-the-latest-tag-of-a-git-repository",
        "post_date":"2013-10-04 18:31:00",
        "post_img":"path/to/your/img.png",
        "ID":"1292"
    },
    {
        "post_title":"Sidr",
        "post_content":"rn rn Sidr is a jQuery plugin for creating side menus. It is the library that I use to create "Previous" and "Next" post button on my Open Sourced WordPress theme (the one you are using righ...",
        "post_name":"sidr",
        "post_date":"2013-09-24 20:16:04",
        "post_img":"path/to/your/img.png",
        "ID":"1279"
    }
]

Step 2: Creating a basic scaffolding

Insert Scripts and Style-sheets

Insert the following lines within the head section of your HTML.

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" type="text/css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular-resource.min.js"></script>

Create a module

Creating a module facilitate the dependency handling. At the moment we will not have any dependencies but we will add a Factory later on.

<script type="text/javascript">
    angular.module('demo');
</script>

To link the module to the DOM you need to tells AngularJS to be active in a portion of the page by adding data-ng-app attribute. In this case the entire document.

<body data-ng-app="demo">
</body>

Add a controller

AngularJS introduces the MVC (Model, View, Controller) model and dependency injection, both concepts are illustrated here. Our Controller MyCtrl can manipulate the Model $scope that was injected via MyCtrl.$inject. Those concept are extremely important to understand in order to go further.

<script type="text/javascript">
    angular.module('demo');

    function MyCtrl($scope) {}
    MyCtrl.$inject = ['$scope'];
</script>

We now have a basic AngularJS application ready.

Step 3: Creating a Factory

An elegant way communicate with the server is to create a Factory. This lets the controller focus on the behavior rather than the complexities of server access. Interaction with server-side data sources can be made through the module “ngResource” (previously included: angular-resource.min.js).

<script type="text/javascript">
    angular.module('demo', ['demoFactory']);

    angular.module('demoFactory', ['ngResource']).factory('ResourceFactory', function($resource) {
        return $resource('?desiredPosts=:desiredPosts&start=:start', {}, {
            // Declaration of custom action that should extend the default set of resource actions
            query: {
                isArray: true,
                cache: false
            }
        });
    });
    function MyCtrl($scope, ResourceFactory,) {}
    MyCtrl.$inject = ['$scope', 'ResourceFactory'];
</script>
Please note that I have added the newly created demoFactory as a dependency of my module and the ResourceFactory object to my controller MyCtrl via MyCtrl.$inject.

Step 4: Interacting with the DOM (Document Object Model)

To understand how AngularJS manipulates the DOM let’s try to display the number of posts already loaded within our widget. To do so in our controller we initiate the post list $scope.list to an empty array (no posts loaded at the beginning) and set the $scope.count property to the list length.

function MyCtrl($scope, ResourceFactory,) {
    $scope.list = []
    $scope.count = $scope.list.length;
}

$scope contains your model data. It is the glue between the controller and the view (HTML). To access the data within the view you must declare the data binding locations using {{ }}. AngularJS will automatically update the post list and the post count whenever the $scope properties changes.

Now let’s use a Bootstrap 3 panel to create our widget. We need a header with the widget title (plus the post count) and a post body.

<body data-ng-app="demo">
    <div id="widget" class="panel panel-default" data-ng-controller="MyCtrl">
        <div class="panel-heading">Widget Title <span class="badge">{{count}}</span></div>
        <div class="panel-body"></div>
    </div>
</body>

As soon as we will load posts into our list the {{count}} property that you can see in the HTML above will be updated.

Create an empty “load more” function

Now that we know how AngularJS updates the DOM we need to populate it with fresh data. Let’s create a function “loadMore” that we will trigger on a button click event.

function MyCtrl($scope, ResourceFactory,) {
    $scope.list = []
    $scope.count = $scope.list.length;
    $scope.loadMore = function(e) {}
}

Bind the “load more” function to a DOM node

data-ng-click is a directive, directives are instructions that tell the AngularJS compiler to attach a given behavior to a DOM node when a certain marker appears in the DOM. Here the directive will trigger the “loadMore” function once clicked.

<body data-ng-app="demo">
    <div id="widget" class="panel panel-default" data-ng-controller="MyCtrl">
        <div class="panel-heading">Widget Title <span class="badge">{{count}}</span></div>
        <button class="more btn btn-primary btn-block" data-ng-click="loadMore($event)">More</button>
    </div>
</body>

Populate the “load more” function

To keep it simple the “load more” function will query our factory “ResourceFactory” with a start and desiredPosts parameters. The result will be stored inside $scope.list.

function MyCtrl($scope, ResourceFactory,) {
    $scope.list = []
    $scope.count = $scope.list.length;
    $scope.loadMore = function(e) {
        ResourceFactory.query({
            start: $scope.count,
            desiredPosts: 2
        }, function(data) {
            if (data.length > 0) {
                // update list
                $scope.list = $scope.list.concat(data);
            }
        });
    }
}

Now every time a user hits the “More” button an Ajax request will be sent and fresh new data will be populated inside $scope.list.

Iterate through the list

By using the data-ng-repeat directive we tell AngularJS to inject the $scope.list items within the DOM. Every time $scope.list is updated the DOM will be automatically updated.

<body data-ng-app="demo">
    <div id="widget" class="panel panel-default" data-ng-controller="MyCtrl">
        <div class="panel-heading">Widget Title <span class="badge">{{count}}</span></div>
        <div class="content panel-body">
            <div id="item-{{item.ID}}" class="item" data-ng-repeat="item in list">
                <img class="thumbnail pull-left" src="{{item.post_img}}">
                <a href="#">
                    <h4 style="margin: 5px 0px;">{{item.post_title}}</h4>
                </a>
                <p>{{item.post_content}}</p>
                <div class="well well-sm">{{item.post_date}}</div>
            </div>
        </div>
        <button class="more btn btn-primary btn-block" data-ng-click="loadMore($event)">More</button>
    </div>
</body>
Please note that you can access items properties using {{item.yourProperty}} within the data-ng-repeat directive.

Our “Load More” widget is now finished. Go checkout the demo to see the result!