Skip to content

Instantly share code, notes, and snippets.

@coderberry
Created June 26, 2014 22:00
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save coderberry/26c4a12b1f77ae868232 to your computer and use it in GitHub Desktop.
Save coderberry/26c4a12b1f77ae868232 to your computer and use it in GitHub Desktop.
Instructions to creating a hybrid mobile app with EmberCLI and Ratchet

Building Guru App with EmberCLI

Example app found at http://goo.gl/K0Lf61

This app requires EmberCLI to be installed. You can install it via npm using npm install -g ember-cli

$ ember new guru-app
$ cd guru-app

Install additional npm and bower dependencies

$ npm install --save-dev broccoli-merge-trees
$ npm install --save-dev broccoli-static-compiler
$ npm install --save-dev broccoli-sass
$ bower install --save ratchet

Modify your Brocfile

/* global require, module */

var mergeTrees = require('broccoli-merge-trees');
var pickFiles = require('broccoli-static-compiler');

var EmberApp = require('ember-cli/lib/broccoli/ember-app');

var app = new EmberApp();

app.import('vendor/ratchet/js/modals.js');
app.import('vendor/ratchet/js/popovers.js');
app.import('vendor/ratchet/js/segmented-controllers.js');
app.import('vendor/ratchet/js/sliders.js');
app.import('vendor/ratchet/js/toggles.js');

var fonts = pickFiles('vendor/ratchet/fonts', {
  srcDir: '/',
  files: ['ratchicons.eot', 'ratchicons.svg', 'ratchicons.ttf', 'ratchicons.woff'],
  destDir: '/fonts'
});

module.exports = mergeTrees([app.toTree(), fonts]);

Rename app/styles/app.css to app/styles/app.scss


Run the application

$ ember serve

and open http://localhost:4200


Modify index.html head

<!-- Sets initial viewport load and disables zooming  -->
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

<!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">

Create Application Adapter

$ ember g adapter application
import DS from 'ember-data';

export default DS.RESTAdapter.extend({
  host: 'http://addressbook-api.herokuapp.com'
});

Create Model

$ ember g model contact
import DS from 'ember-data';

export default DS.Model.extend({
  first  : DS.attr('string'),
  last   : DS.attr('string'),
  avatar : DS.attr('string'),
  github : DS.attr('string'),
  notes  : DS.attr('string'),

  fullName: function() {
    return this.get('first') + ' ' + this.get('last');
  }.property('first', 'last')
});

Create Routes

$ ember g route index
import Ember from 'ember';

export default Ember.Route.extend({
  redirect: function() {
    this.transitionTo('contacts.index');
  }
});

$ ember g route contacts/index
import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return this.store.find('contact');
  },

  actions: {
    refresh: function() {
      this.controller.set('isRefreshing', true);
      Ember.run.later(this, function() {
        this.store.find('contact').then(function(data) {
          this.controller.set('content', data);
          this.controller.set('isRefreshing', false);
        }.bind(this));
      }, 3000);
    }
  }
});

$ ember g route contacts/show
import Ember from 'ember';

export default Ember.Route.extend({
  model: function(params) {
    return this.store.find('contact', params.id);
  }
});

Update Router

import Ember from 'ember';

var Router = Ember.Router.extend({
  location: GuruAppENV.locationType
});

Router.map(function() {
  this.resource('contacts', { path: '/contacts' }, function() {
    this.route('show', { path: '/:id' });
  });
});

export default Router;

Update app.scss

@import "vendor/ratchet/sass/ratchet";

.content {
  background-color: #efeff4;
  &.has-footer {
    padding-bottom: 45px;
  }
}

.bar-nav {
  background-color: #f7f7f7;
}

.table-view.has-header {
  margin-top: 0px !important;
}

.table-view-cell.media img {
  width: 40px;
  height: 40px;
  border-radius: 20px;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
}

.card.padded {
  padding: 20px;
}

.spin {
  -webkit-animation: spin 2s infinite linear;
  -moz-animation: spin 2s infinite linear;
  -o-animation: spin 2s infinite linear;
  animation: spin 2s infinite linear;
}

@-moz-keyframes spin {
  from { -moz-transform: rotate(0deg); }
  to { -moz-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
  from { -webkit-transform: rotate(0deg); }
  to { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
  from {transform:rotate(0deg);}
  to {transform:rotate(360deg);}
}

Handlebars Templates

application.hbs
{{outlet}}
contacts/index.hbs
<header class="bar bar-nav">
  <h1 class="title">JavaScript Gurus</h1>
</header>

<div class="content has-footer">
  <div class="card">
    <ul class="table-view">
      {{#each contact in controller}}
      <li class="table-view-cell media">
        {{#link-to "contacts.show" contact class="navigate-right"}}
          <img class="media-object pull-left" {{bind-attr src=contact.avatar}}>
          <div class="media-body">
            {{contact.fullName}}
            <p>{{contact.id}}</p>
          </div>
        {{/link-to}}
      </li>
      {{/each}}
    </ul>
  </div>
</div>

<div class="bar bar-standard bar-footer">
  <a {{action "refresh"}} {{bind-attr class=":icon :icon-refresh isRefreshing:spin :pull-right"}}></a>
</div>
contacts/show.hbs
<header class="bar bar-nav">
  {{#link-to 'contacts' class="icon icon-left-nav pull-left"}}{{/link-to}}
  <h1 class="title">JavaScript Gurus</h1>
</header>

<div class="content">
  <div class="card padded">
    <h3>{{fullName}}</h3>
    <p>Data would go here...</p>
  </div>
</div>
@kristianmandrup
Copy link

Awesome rundown ;) I also wached your SLC meetup video. I made my own little modifications to your Brocfile steps. I like to avoid polluting my Brocfile too much, so I extract configurations into separate files in a /brocs folder.

https://gist.github.com/kristianmandrup/91f4148b1b4a8553e9d9

And adding initial Ratchet setup to my ember-config generator (for cli)

https://github.com/kristianmandrup/ember-config

@kristianmandrup
Copy link

Would be awesome to turn this into an ember-cli addon and ratchet components.
Then it might be a lot easier to get rollin doing hybrid mobile apps with Ember ;)

@kristianmandrup
Copy link

For smooth transitions (and mobile features in general), this looks promising...

http://discuss.emberjs.com/t/animation-support-in-ember-1-1/1977/56
https://github.com/ef4/liquid-fire
https://github.com/kikinteractive/app/ (uses liquid-fire)
http://code.kik.com/app/2/index.html (app.js demo)
http://code.kik.com/app/2/docs.html (app.js docs)
https://github.com/christophery/pushy (off canvas menu)
http://blangslet.com/post/56963208586/ember-js-mobile-responsive-swipe-push-menu-navigation

https://github.com/kikinteractive/app/issues/49 (iOs + Android icons)
http://ionicons.com/

Looks like App.js could "easily" be integrated with the Ember router to call an App.js controller to perform a page transition ;) ?

I made a few patches to App.js so it should be easier to integrate with an external MV* framework

https://github.com/kristianmandrup/app

Includes proto instructions for use with Ember. I think it could work!?

@kristianmandrup
Copy link

Created a gist with some initial ideas for some simple ratchet components...

https://gist.github.com/kristianmandrup/8ec0dc2b9419d9afcbb5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment