mobile animation and gesture with ember

Make mobile animation and touch gesture with EmberJS

Today, I’m going to take you along on a quick journey through some very basic mobile animation and touch gesture implementations using Ember.js, with a more comprehensive deep dive planned for another article in the near future. I’m sorry if I go quickly and skip over some of the basics, but there are many great beginner ember.js tutorials out there and this article assumes a solid grasp of the fundamentals.

Three libraries that we will be using:

Ember-animated-outlets: Uses CSS3 transitions to animate between ember outlets and views.

Ember-touch: A solid foundation for building custom gestures and touch-based events with ember.

Ember-fastclick: A fork of fastclick.js that removes the 300ms delay on click events in mobile browsers while they wait to see if the user double-taps.

Also, full disclosure: I’m partial to Rails for building JSON APIs and managing builds/assets, Emblem.js for sweet, sugary templates and have included Bootstrap 3 CSS to add a little style to our demo app.

With all of that out of the way, sit back, relax, crunch your toes deep into the sand and let’s get started. Vamanos!

First, your javascript manifest file should look something like this:

//= require jquery
//= require handlebars
//= require ember                  # ember-rc.6
//= require ember-data             # ember-data-rev13
//= require ember-fastclick        # gets rid of 300ms delay on mobile events
//= require ember-touch            # ember add-on for touch-based gestures
//= require ember-animated-outlet  # outlet and view-based animations and transitions
//= require_self
//= require app

Now that we have all of our libraries loaded, let’s run through the code. I have set up a simple demo app with a basic hasMany relationship between two models: Posts and Comments.

App.Post = DS.Model.extend({
  title: DS.attr('string'),
  body: DS.attr('string'),
  comments: DS.hasMany('App.Comment')
});

App.Comment = DS.Model.extend({
  post: DS.belongsTo('App.Post'),
  text: DS.attr('string')
});
The routing is very basic: 

App.Router.map(function() {
  this.resource("posts", function() {
    this.resource('post', { path: ':post_id' });
   });
});

When the app is initialized, the app IndexRoute auto-redirects to PostsIndex.

App.IndexRoute = Ember.Route.extend({
  redirect: function() {
    this.transitionTo('posts.index');
  }
});

The posts_index.emblem template has a list group of each post that’s loaded up in our controller.

each post in controller
  post.title

It’s time for our first animation. When any of the posts in the list are clicked, we want the screen to slide out to the left, with the “show” page for the clicked post object to slide in from the right iOS-style. To do this, we’ll use ember-animated-outlets to make it sizzle.

Define a PostsView and put an animatedOutlet in your posts.emblem template.

App.PostsView = Ember.View.extend({
  templateName: 'posts'
});
= animatedOutlet name="posts"

Let’s define an event ‘goToPost’ in our application_route.js that transitions to our clicked post object’s “show” page.

App.ApplicationRoute = Em.Route.extend({
  events: {
    goToPost: function(post) {
      this.transitionToAnimated('post', {posts: 'slideLeft'}, post);
    }
  }
});

Awesome, now all we have to do is call this action from our posts_index.emblem template and we’ve completed our first animated route transition!

each post in controller
  a click="goToPost post"
    post.title

That wasn’t so hard now, was it?

How about we add in a back button to transition from our post.index “show” route back to our list of posts in the posts.index route? Of course, we will also want to animate this, this time making our current view slide to the right out of the way, while our new view slides in from the left. First, define an event in our application route again:

App.ApplicationRoute = Em.Route.extend({
  events: {
    goToPost: function(startingPoint) {
      this.transitionToAnimated('post', {posts: 'slideLeft'}, post);
    },
    backToPosts: function() {
      this.transitionToAnimated('posts.index', {posts: 'slideRight'})
    }
  }
});

Now, just call this action from your post.emblem template, and we have another animated transition back to our posts.index route.

a click="backToPosts"
    button.btn.btn-small.btn-white
      i.icon-chevron-left
      | Back

“All right,” you say, “that’s pretty cool, but what I really want is to trigger animated transitions with touch-gestures.” No problem! Enter ember-touch.

How about we mimic the behavior of the back button we just implemented on the post “show” page when the user swipes his finger from left-to right, causing the posts.index list to slide in from left-to-right. This is actually pretty simple to do.

In your post_view.js, when a left-to-right swipe is detected, send along the “backToPosts” event to the controller, where it’s undefined, and then watch it bubble up to be handled by the Application Route events hook.

App.PostView = Ember.View.extend({
  templateName: 'post',

  swipeOptions: {
      direction: Em.OneGestureDirection.Right,
      cancelPeriod: 100,
      swipeThreshold: 10
    },

    touchMove: function(event) {
      event.preventDefault();
    },

    swipeEnd: function(recognizer, evt) {
      var direction = recognizer.get('swipeDirection');

      if (direction === Em.OneGestureDirection.Right) {
        this.get('controller').send('backToPosts')
      }
    }
});

Now, when you swipe left-to-right, you go back to the initial posts.index view with an animated transition!

So there you have it: some very basic mobile animated transitions and gestures with ember.js.

You can test demo and download full code at GitHub.

Thanks Bryan Langslet for very helpful article.