Trying out Meteor + Ionic

With meteors newly introduced official support for angular released this September, we are now able to integrate many of the third party libraries introduced with angular in our meteor application. This also introduces the possibility to use angular based frameworks in our meteor applications, Ionic being one of them!

For those not familiar with Ionic, it is a powerful HTML5 framework that let’s you build neatly wrapped mobile applications using core web technologies with great ease. In some sense we no longer need to rely on our mad css-skills in order to build nice and neat mobile applications in Meteor. Ionic will fix (all) that boilerplate for us!

So in order to start using all this new and exciting functionality, let’s start of by creating a new meteor-angular application. For reference, the documentation for the angular-meteor project can be found here.

The application itself will in the end aim to provide us with a list of all the consultants working at Squeed!

Let’s start with creating a new meteor application, adding the angular and ionic packages and remove the autopublish/insecure packages so that we don’t publish all and all.

meteor create squeeders
cd squeeders
meteor remove autopublish
meteor remove insecure

meteor add angular
meteor add driftyco:ionic

Next let’s add some folder structure and some basic files for our application packaging.

- client
  index.html
  - templates
  - scripts
    - controllers
    - lib
  - stylesheets
- server
- lib

We start by defining our top level index.html file where we will in ionic fashion render our ionic-views.

client/index.html

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
  <title>Squeeders</title>
</head>
 
<body>
<ion-nav-view></ion-nav-view>
</body>

Just to have it in place, let’s create the mongo collection and publish it from the server to interested clients.

lib/collections.js

Squeeders = new Mongo.Collection("squeeders");

server/publications.js

Meteor.publish("squeeders", function() {
   return Squeeders.find({});
});

Next let’s add our angular “app.js”

client/scripts/lib/app.ng.js

angular.module('squeeders', ['angular-meteor','ionic']);
 
if (Meteor.isCordova) {
  angular.element(document).on('deviceready', onReady);
}
else {
  angular.element(document).ready(onReady);
}
 
function onReady() {
  angular.bootstrap(document, ['squeeders']);
}

Note that we want this to be placed in our ../lib folder in order to guarantee that its loaded first.
Also note that we want to name all our files that contains angular specific code with the .ng extension in order for the angular module to recognize this as angular.js code. Including our html, in order for angular to properly load our html templates.

Now for some ionic and angular specifics. We are interested in having a side menu. So let’s create a main content holder which we can later load as a main abstract template in our angular router.

client/templates/main.ng.html

<ion-side-menus enable-menu-with-back-views="false">

  <ion-side-menu-content>
    <ion-nav-bar class="bar-squeed">
      <ion-nav-back-button>
      </ion-nav-back-button>

      <ion-nav-buttons side="left">
        <button class="button button-icon button-clear ion-navicon" menu-toggle="left">
        </button>
      </ion-nav-buttons>

    </ion-nav-bar>

    <ion-nav-view name="menuContent"></ion-nav-view>
  </ion-side-menu-content>

  <ion-side-menu side="left">
    <ion-header-bar class="bar-squeed">
      <h1 class="title">Menu</h1>
    </ion-header-bar>
    <ion-content>
      <ul class="list">
        <!-- Note each link has the 'menu-close' attribute so the menu auto closes when clicking on one of these links -->
        <a href="#/main/list" class="item squeed-orange" menu-close>Squeeders</a>
      </ul>
    </ion-content>
  </ion-side-menu>

</ion-side-menus>

Just for some look and feel, lets color it in Squeed colors!

client/stylesheets/squeed.css

.bar.bar-squeed {
  border-color: #e6b400;
  background-color: black;
  background-image: linear-gradient(0deg, #e6b400, #e6b400 50%, transparent 50%);
  color: #fff;
}
.bar.bar-squeed .title {
  color: #EAA42F;
}

.squeed-orange {
  color: #EAA42F !important
}

Now we need to query our list from the database and provide it to our template. Lets create our angular ListController.

client/scripts/controllers/list.ng.js

angular.module('squeeders').controller('ListController', function ($scope) {
   $scope.$meteorSubscribe('squeeders');
   $scope.squeeders = $scope.$meteorCollection(Squeeders, false);
});

$meteorSubscribe will subscribe on our collection squeeders and provision our local client side database.
We then use $scope.$meteorCollection binding our $scope variables to reactive changes on our squeeders collection.

Next we create our template to display the actual list.

client/templates/list.ng.html

<ion-view view-title="Squeeders">
   <ion-content>
      <ion-list>
         <ion-item href="{{squeeder.profile}}" ng-repeat="squeeder in squeeders | orderBy:'name'"
            class="item-thumbnail-left item-text-wrap">
            <img ng-src="{{squeeder.img}}">
            <h2>{{squeeder.name}}</h2>
            <p>{{squeeder.desc}}</p>
         </ion-item>
      </ion-list>
   </ion-content>
</ion-view>

Let’s bind it together and route to the appropriate template. We create our angular router.

client/scripts/routes.ng.js

angular.module('squeeders').config(function($stateProvider, $urlRouterProvider) {
   $stateProvider
      .state('main', {
         url: '/main',
         abstract: true,
         templateUrl: 'client/templates/main.ng.html'
      })
      .state('main.list', {
         url: '/list',
         views: {
           'menuContent': {
              templateUrl: 'client/templates/list.ng.html',
              controller: 'ListController'
           }
         }
      });
   $urlRouterProvider.otherwise('main/list');
});

So let’s fetch the data that we want to show in our actual list and insert it to the database.
In this particular case we are interested in showing a list of all squeeders currently working on Squeed.
This information is easily accessible from www.squeed.com/squeeders, but since there is no api to conveniently query this we turn to simply scraping it off our webpage. For that we will need to add some additional packages (just because it’s fun to scrape stuff).

meteor add http
meteor add mrt:cheerio

Using cheerio we can now scrape the homepage for the information we need. Let’s add this to a startup script run when the meteor server starts, adding all the squeeders to our database collection.

server/bootstrap.js

Meteor.startup(function () {
   Squeeders.remove({});
   result = Meteor.http.get("http://www.squeed.com/squeeders");
   $ = cheerio.load(result.content);
   var ones = $('.sixteen.columns.content.content-page > div');
   ones.each(function(index) {
      Squeeders.insert({
         name:$(this).find('div.team > h4').text(),
         img:$(this).find('div.thumb > img').attr('src'),
         desc:$(this).find('div.member-content > p > span').text(),
         profile:$(this).find('a').attr('href')
      });
   });
});

And there we have it! Check out the final result on http://squeeders.meteor.com surfing in on your mobile device.
If we also wanted to build this as an actual mobile application. We can simply add the respective platform (android in this case) by so:

meteor add-platform android

And follow the procedure, which might include installing the android sdk etc with some simple meteor commands. Then we can use:

meteor build output --server <Location where mobile builds connect to the Meteor server>

And in our build output we will find the apk file to install.

If you want to checkout the complete example, you can find the source here

One thought to “Trying out Meteor + Ionic”

Leave a Reply

Your email address will not be published. Required fields are marked *