How to use Hammer.js with Angular.js

How to use Hammer.js with Angular.js

  • 2016-08-23
  • 3910

In this article, we will see how easy Angular 2 could work with HammerJS.

HammerJS is a fantastic library that helps you add support for touch gestures (e. g. swipe, pan, zoom, rotate) to your page.

Demo

Introduction

We will be building a carousel of avatars. The user can swipe left or swipe right to view each avatar. Test it out yourself here (works best lawn mowers of mobile, but tested on chrome and firefox computer’s desktop browser with an emulator).

In real time demo with full source code here:: https://plnkr.co/edit/BswEd6?p=preview

App Setup

Why don’t we look into how our directory structure look like.
We’ll have an app folder which contains our avatar carousel and main.ts file for bootstrapping our application.

|- app/
    |- app.component.html
    |- app.component.css
    |- app.component.ts
    |- main.ts
|- index.html
|- tsconfig.json

The App Component

Let’s start with our app component. In this component, we will define our list of avatars and handle the swipe event and show/hide an avatar based on the swipe sequence.

// app/app.component.ts

import { Component } from [email protected]/core';

@Component({
    moduleId: module.id,
    selector: 'my-app',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css']
})
export class AppComponent {
    // constant for swipe action: left or right
    SWIPE_ACTION = { LEFT: 'swipeleft', RIGHT: 'swiperight' };

    // our list of avatars
    avatars = [
        {
            name: 'kristy',
            image: 'http://semantic-ui.com/images/avatar2/large/kristy.png',
            visible: true
        },
        {
            name: 'matthew',
            image: 'http://semantic-ui.com/images/avatar2/large/matthew.png',
            visible: false
        },
        {
            name: 'chris',
            image: 'http://semantic-ui.com/images/avatar/large/chris.jpg',
            visible: false
        },
        {
            name: 'jenny',
            image: 'http://semantic-ui.com/images/avatar/large/jenny.jpg',
            visible: false
        }
    ];

    // action triggered when user swipes
    swipe(currentIndex: number, action = this.SWIPE_ACTION.RIGHT) {
        // out of range
        if (currentIndex > this.avatars.length || currentIndex < 0) return;

        let nextIndex = 0;

        // swipe right, next avatar
        if (action === this.SWIPE_ACTION.RIGHT) {
            const isLast = currentIndex === this.avatars.length - 1;
            nextIndex = isLast ? 0 : currentIndex + 1;
        }

        // swipe left, previous avatar
        if (action === this.SWIPE_ACTION.LEFT) {
            const isFirst = currentIndex === 0;
            nextIndex = isFirst ? this.avatars.length - 1 : currentIndex - 1;
        }

        // toggle avatar visibility
        this.avatars.forEach((x, i) => x.visible = (i === nextIndex));
    }
}

Notes:

  1. We will handle swipe left and swipe right event using the same function swipe.
  2. swipe takes two parameters:
    • 1st param is the current index of the selected avatar,
    • 2nd param is optional, the swipe action either left or right.
  3. You see that we declare a constant SWIPE_DIRECTION and the value is swipeleft or swiperight.
  4. Pertain to HammerJS documentation, HammerJS handles 5 swipe events: swipe, swipeleft, swiperight, swipeup, swipedown. In our case, we just handle swipeleft and swiperight.
  5. We will be calling this swipe action later in our HTML CODE view.

The HTML view

Here’s our HTML view.

<!-- app/app.component.html -->
<div>
    <h4>Swipe Avatars with HammerJS</h4>
    <!-- loop each avatar in our avatar list -->
    <div class="swipe-box"  
        *ngFor="let avatar of avatars; let idx=index"
        (swipeleft)="swipe(idx, $event.type)" (swiperight)="swipe(idx, $event.type)" 
        [class.visible]="avatar.visible" [class.hidden]="!avatar.visible">
        <div>
            <img [src]="avatar.image" [alt]="avatar.name">
        </div>
        <div>
            <a class="header">{{avatar.name}}</a>
        </div>
    </div>
</div>

Notes

  1. We loop through each avatar using *ngFor directive, we declare a local variable idx to hold the current index of the avatar.
  2. Then, we will handle swipeleft and swiperight event, call the swipe function that we declared earlier.
  3. $event is the event object. We don’t need the information of the whole $event object. We need only $event.type which returns a string of swipeleft or swiperight.
  4. [class.visible] or [class.hidden]. We will add or remove these two CSS classes based on the avatar.visible property.

The Component Styling

We can use semantic-ui CSS to ease our styling, but that’s not neccessary for our purposes. Apart from that, there are a couple of custom CSS classes that we need to add for our component.

.swipe-box {
    display: block;
    width: 100%;
    float: left;
    margin: 0;
}

.visible {
    display: block;
}

.hidden {
    display: none;
}

Notes

  1. We want all our avatar cards stack on top of each other, therefore, we use .swipe-box to float all the avatars.
  2. .visible and .hidden are used to show/hide the avatar card.

Include HammerJS Javascript

We’re now done with our component. Let’s move on to setting up HammerJS. First, we need to include the HammerJS Javascript file in our main view index.html file.

<!-- index.html -->
<head>
...
    <!-- Hammer JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js"></script>
....
</head>

By default, the desktop browser doesn’t support the touch event. HammerJS has an extension called touch-emulator.js that provides a debug tool to emulate touch support in the browser. You can include these lines in the index.html like this before the HammerJS file:

<!-- index.html -->
<head>
...
    <!-- Hammer JS Touch Emulator: Uncomment if for desktop -->
    <script src="http://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script>
    <script>
    TouchEmulator();
    </script>
...
</head>

For details on how the emulator works, please refer to the their official documentation.

Because I run this example in plunker, I just include the HammerJS CDN url. If you want to manage your package locally, you may run the following command:

npm install hammerjs --save

Then, include the JS files in your build.

If we do not include HammerJS file, an error message will be thrown: “Hammer.js is not loaded, can not bind swipeleft event”.

Application Bootstrap

By default, if you do not have any custom configuration, you can use HammerJS straight away. Angular2 supports HammerJs out of the box. No need to include anything during application bootstrap. Your application bootstrap will look something like this:

// main.ts

import { bootstrap }    from [email protected]/platform-browser-dynamic;
import { AppComponent } from './app.component';

bootstrap(AppComponent);

Customize HammerJS

What if you would like to apply some custom settings like increasing the velocity and threshold?

Quick explanation:

  • threshold: Minimal distance required before swipe is recognized. Default: 10
  • velocity: Minimal velocity required before swipe is recognized, unit is in px per ms. Default: 0.3

There are other settings you can apply as well. For details, refer to HammerJS documentation.

Angular 2 provides a token called HAMMER_GESTURE_CONFIG which accepts a HammerGestureConfig type.

In the simplest way, we can extend HammerGestureConfig like this:

// main.ts

import { bootstrap }    from [email protected]/platform-browser-dynamic';
import { provide } from [email protected]/core';
import { HammerGestureConfig, HAMMER_GESTURE_CONFIG } from [email protected]/platform-browser';

import { AppComponent } from './app.component';

// extend default HammerGestureConfig
// should put this class in another individual file
export class MyHammerConfig extends HammerGestureConfig  {
    overrides = <any>{
        'swipe': { velocity: 0.8, threshold: 20 } // our custom settings
    }
}

bootstrap(AppComponent, [

    // provide our own implementation
    provide(HAMMER_GESTURE_CONFIG, {
        useClass: MyHammerConfig
    }),
]);

In our case, we just want to override some default settings of the swipe action. You may implement the HammerGestureConfig class yourself if you want to have more controls.

Take a look at HammerGestureConfig not so complicated sourcode or the documentation. The whole class only have two properties (events, overrides) and a function (buildHammer).

Summary

Angular 2 make it really easy to integrate with HammerJS for touch gesture event detection. That’s it. Happy coding!

Suggest

Lazyload controllers and modules in Angular.JS

How to Leverage MongoDB, MVC and AngularJS

JavaScript Promises: Applications in ES6 and AngularJS

Learn Angular 2 Development By Building 10 Apps

Angular 2 and NodeJS - The Practical Guide to MEAN Stack 2.0