Tindercards.js

I wanted to create a similar experience to those cards that you can swipe left and right in Tinder, but with web technology. So I did. There are already 2 libs that do this but they’re based on Ionic which I didn’t want to have a dependency on. Tindercards.js only requires jQuery and Hammer.js.

The result looks like this:

Video demo

On YouTube: https://youtu.be/LqZ3wqvvZwE

Screenshot

Tindercards.js demo screenshot

Live Demo

Works best on iPhone: http://www.timo-ernst.net/misc/tindercardsjsdemo/

Dependencides

Tested on

  • iOS Safari

API Documentation

There are just two components that you need. A prototype object called Tindercardsjs.card and a method called Tindercardsjs.render. The signatures are like this:

/**
 * Representation of 1 card on the stack.
 * This is a prototype object! Initialize with "new" keyword
 *
 * @param {String} cardid Pass a unique id for each card so you know later which card is which
 * @param {String} name The name of the person on the card
 * @param {String} description The description text of that person
 * @param {String} imgpath The path to the img
 */
Tindercardsjs.card(cardid, name, description, imgpath)
 
/**
 * Renders the given stack into the given jQuery element.
 *
 * This is a method, just call it. Parameter "cards" must be an
 * array of Tindercardsjs.card
 *
 * @param {Array} cards An array of cards (@see Tindercardsjs.card)
 * @param {jQuery} target The target in which the stack should be rendered to
 * @param {function} onSwiped Callback function when swipe has occurred. Will pass an event object as parameter with properties event.cardid (the card id), event.card (The jQuery object that contains the card dom element) and event.direction ('left' or 'right').
 */
Tindercardsjs.render(cards, target, onSwiped)

How to use

  1. Make sure you have hammer.js und jQuery referenced
  2. Then, add tindercards.js from /lib
  3. Initialize like this:
var cards = [
  new Tindercardsjs.card(2, 'Geordi Laforge', 'I like big butts', 'gfx/pics/01.jpg'),
  new Tindercardsjs.card(1, 'Agro Picard', 'Hates Klingons, likes beer.', 'gfx/pics/02.jpg'),
  new Tindercardsjs.card(0, 'Jean-Luc, Worf & William', 'Swipe right if you also like funny hats like us :D', 'gfx/pics/03.jpg')
];

And pass them to Tindercards.js like this:

Tindercardsjs.render(cards, $('#main'), function (event) {
  console.log('Swiped ' + event.direction + ', cardid is ' + event.cardid + ' and target is:');
  console.log(event.card);
});

The stack will then be rendered to a HTML container that has id “main”. You can of course change that to some other name if you want.

Important

The html container (in this case #main) should have either position:absolute or position:relative!

Download lib & example code

Grab it on GitHub

Experiment: An iPhone app built with Framework7, TypeScript, and Angular 1.x


Disclaimer: Since this post is getting quite some attention I have to state some things clear, so read this first!
This example is not best practice on how to use Framework7, it’s more of an experiment to see how it works with Angular and TypeScript. Framework7 has an own templating engine called Template7 so Angular is not mandatory. Also F7 designed to work with JavaScript, rather than TypeScript.
So, if you’re new to Framework7, do not assume that this example is the way you should create F7 apps! It was an experiment to see what happens if you combine these technologies. After all I can say that I wouldn’t use TypeScript with F7 again, just stick to plain old JavaScript. If you know how to use Angular, then you should be safe using it. If you don’t know Angular, then use Template7.

If you want to learn how to use Framework7 with AngularJS, go check out my video screencast tutorial!

Also, please keep in mind that both tutorials are older and thus refer to Angular 1.x. If you start a new project, it’s highly recommended to use a more recent version of Angular!


In my last post I created a template for Framework7 based on TypeScript and Angular. Since Angular is still such a big hype and there doesn’t seem to be any examples of Framework7 with Angular, I decided to create a little demo application that demonstrates Angular’s data binding technique with TypeScript on top of Framework7. This demo will display lists of upcoming and current movies in theaters. Tapping on a movie will show additional information. The result looks like this:

Screenshot

Framework7 with Angular movie list demo

Demo

Check it out here: http://www.timo-ernst.net/misc/f7angulardemo/

Before you check the code, read this!

The demo code is based on this template for Framework 7. For some people this might look a little complicated since you will have to know how to use npm and grunt. So if you want a simpler version of the template without a compile process and just pure html, css and javascript, try this.

Code explanation

Let’s dive into the code. I’ll explain piece by piece what I did. At the bottom of this post you will find a link to Github where you can clone the repo and get the sources.

The view

To build this, I simply saved all movie data into a model “movies” and bound that with Angular expression to the view. In order to not repeat to many list item elements I used ng-repeat:

<ul>
  <li class="ft-movielist-item" ng-repeat="movie in movies">
    <a href="#detailsPage" ng-click="events.onListItemClicked(movie)" class="item-link">
      <div class="item-content">
        <div class="item-media">
          <img class="ft-movielist-item-img" src="{{movie.posters.thumbnail}}">
        </div>
        <div class="item-inner">
          <div class="item-title-row">
            <div class="item-title">{{movie.title}}</div>
          </div>
          <div class="item-subtitle">{{movie.stars}}</div>
          <div class="item-text">{{movie.synopsis}}</div>
        </div>
      </div>
    </a>
  </li>
</ul>

TypeScript model definition

Since TypeScript is well.. strictly typed we first need to define how our model looks like:

  export interface Movie{
    id:String;
    synopsis:String;
    title:String;
    posters:MoviePosters;
    ratings:MovieRatings;
    release_dates:MovieReleaseDates;
    stars:String;
    date:String;
  }

Data binding

I bound an empty array of this type as a model via angular scope:

var movies:Movie[] = [];
$scope.movies = movies;

Get the data and update the model

To fill the model array with data, I start an ajax call and then copy the data from the json response into my model array:

var ajaxconfig:ng.IRequestConfig = {
  method: 'JSONP',
  url: (type == 'upcoming' ? this.API_URL_UPCOMINGLIST : this.API_URL_THEATERSLIST)
};
 
// Do ajax call to rotten api
this.$http(ajaxconfig)
  .success((data: Movies.AjaxResultData, status: number, headers: (headerName: string) => string, config: ng.IRequestConfig): void => {
    // Update angular model
    angular.copy(data.movies, this.movies);
  })
  .error((data: Movies.AjaxResultData, status: number, headers: (headerName: string) => string, config: ng.IRequestConfig): void => {
    alert('Failed connecting to rotten tomatoes db. Status code ' + status);
  });

And boom! That’s it. Angular will automatically display the data in the view. When ever you modify the model, Angular will sync this to HTML.

No jQuery. No DOM manipulation. Enjoy :-)

Full source code

Download on GitHub

Lessons learned

Angular will greatly help to reduce your amount of javascript code. TypeScript is cool because of strict typing and support of classes but it will make your code much much more complicated. The stuff that you saw here in this post is just a tiny small part of the whole thing which involves modules, type declarations, path references, compiler nagging and a lot more (check the full source to see the whole disaster). So at the end it eats up all the code that Angular has saved. Next time I use Angular I will stick with JavaScript and ditch TypeScript which could be interesting though for Node apps. I’ll try that next time maybe. Framework7 is still the best HTML-based iOS framework that I have ever seen. It’s super fast and perfectly mimics the look and feel of native apps. Make sure to check it out: http://www.idangero.us/framework7/

How to hide the address bar on iPhone5 Safari browser

If you created a website with 100% height, you might encounter the problem that iPhone5 doesn’t hide the address bar while iPhone 4/4s and older do hide it.

Existing solutions

There are quite some JavaScript-based solutions on this issue that use scrollTop() and add a margin at the bottom of your page, e.g.:

That’s pretty complicated and I encountered the problem that this approach can lead to whitespace at the bottom of your page.

So I found a really way easier solution.

The better approach

Since you created a website with 100% height, I assume that you applied via css:

html,body{height:100%}

Now, for iPhone5 simply change this to:

html{height:504px}
body{height:100%}

This will tell Safari that your website is just 1px taller than the maximum visible part of your html document and the browser will automatically hide the address bar. That simple :-)

Warning!

Do not apply this to any other phone except for iPhone 5!

If you need to detect iPhone5, I recommend this script: Simple iPhone 5 detection with JavaScript

So you could do:

if (isIphone5()) $("html").css("height", "504px");
else $("html").css("height", "100%");
$("body").css("height", "100%");