Ember.js and Ember-CLI

Ember.js and Ember-CLI

Sldies from my talk on Ember.js and Ember-CLI from the Austin JavaScript meetup.

E02ac480d0b92ec00e660be464d35c8d?s=128

Iheanyi Ekechukwu

August 18, 2015
Tweet

Transcript

  1. Ember.js & Ember-CLI Iheanyi Ekechukwu @kwuchu IBM Watson Life http://iheanyi.com

  2. What is Ember?

  3. A framework for creating ambitious web applications.

  4. Why Ember?

  5. As a Designer

  6. I can make ambitious UIs. Really ambitious.

  7. None
  8. None
  9. Let's see another "ambitious" UI

  10. None
  11. How is this possible?

  12. None
  13. Just kidding. Ember's Router and Nested Routes = <3 Data,

    URLs, UI, and State are all in sync.
  14. import Ember from 'ember'; import config from './config/environment'; var Router

    = Ember.Router.extend({ location: config.locationType }); export default Router.map(function() { this.route('contacts', function() { this.route('show', {path: '/:id'}); }); });
  15. URL:t URL: /contacts/1

  16. Animations help take your UI to the next level.

  17. Liquid Fire (https://github.com/ef4/liquid- fire)

  18. Gif of Barbr here.

  19. Wow, that must've been really complicated.

  20. ember install liquid-fire

  21. {{liquid-outlet}} # previously {{outlet}} <nav class="navbar navbar-default"> <div class="container"> <div

    class="navbar-header"> {{#link-to 'index' class="navbar-brand"}} Barber Application {{/link-to}} </div> <ul class="nav navbar-nav"> <li>{{link-to 'Barbershops' 'barbershops'}}</li> </ul> <ul class="nav navbar-nav navbar-right"> {{#if this.currentUser}} <li><p class="navbar-text">Signed in as {{currentUser.username}}</p></li> <li><a class="logout-link" {{action 'logout'}}>Logout</a></li> {{else}} <li>{{link-to "Login" 'login'}}</li> <li>{{link-to 'Register' 'users.new'}}</li> {{/if}} </ul> </div> </nav>
  22. export default function() { this.transition( this.fromRoute('index'), this.use('toLeft'), this.reverse('toRight') ); this.transition(

    this.fromRoute('barbershops'), this.use('toLeft'), this.reverse('toRight') ); }
  23. None
  24. As a Developer

  25. Convention over Configuration.

  26. HTMLBars for Templating

  27. Simple Template Action Handling by Components, Controllers, and Routes

  28. None
  29. <a href="#" class="btn btn-custom btn-social btn-md btn-facebook" {{action 'signIn'}}> <i

    class="fa fa-facebook"></i> Sign In With Facebook </a> {{/if}} {{#if session.isAuthenticated}} <a href="#" class="btn btn-custom btn-social btn-md btn-facebook" {{action 'invalidateSession'}}> <i class="fa fa-facebook"></i> Logout </a> {{else}}
  30. import Ember from 'ember'; import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin'; export default

    Ember.Controller.extend(LoginControllerMixin, { authenticator: 'simple-auth-authenticator:torii', actions: { signIn: function() { var controller = this.controllerFor('index'); var session = this.get('session'); session.authenticate('simple-auth-authenticator:torii', 'facebook- connect').then(function() { controller.transitionToRoute('likes'); }); } });
  31. Ember-Data

  32. Let's see a quick example/overview.

  33. ember generate adapter application create app/adapters/application create tests/unit/adapters/application-test.js

  34. import DS from 'ember-data'; export default DS.RESTAdapter.extend({ namespace: 'api' });

  35. ember generate model contact firstName:string lastName:string \ email:string avatar:string description:string

    create app/models/contact.js create tests/unit/models/contacts-test.js
  36. // app/models/contact.js import DS from 'ember-data'; export default DS.Model.extend({ firstName:

    DS.attr('string'), lastName: DS.attr('string'), avatar: DS.attr('string'), email: DS.attr('string'), description: DS.attr('string') });
  37. ember generate route contacts create app/routes/contacts.js create tests/unit/routes/contacts-test.js

  38. // app/routes/contacts.js import Ember from 'ember'; export default Ember.Route.extend({ });

  39. // app/routes/contacts.js import Ember from 'ember'; export default Ember.Route.extend({ model()

    { return this.store.find('contact'); } });
  40. this.store.find('contact');

  41. this.store.find('contact', params.id);

  42. this.store.createRecord('contact', data);

  43. this.store.query('contact', query);

  44. this.store.find('contact', params.id).then(function(contact) { contact.set('firstName', 'Iheanyi'); contact.save(); }); }

  45. contact.deleteRecord();

  46. contact.destroyRecord();

  47. And that's not all...

  48. this.store.filter('contact', function(contact) { return contact.get('firstName')[0] === "A"; });

  49. Computed Properties

  50. // app/models/contact.js import DS from 'ember-data'; export default DS.Model.extend({ firstName:

    DS.attr('string'), lastName: DS.attr('string'), avatar: DS.attr('string'), email: DS.attr('string'), description: DS.attr('string'), fullName: Ember.computed('firstName', 'lastName', function(key, value) { return `${this.get('firstName')} ${this.get('lastName')}`; }) });
  51. this.store.createRecord('contact', {firstName: "Iheanyi", lastName: "Ekechukwu"}).then(function(contact) { contact.get('fullName'); // Iheanyi Ekechukwu

    });
  52. import Ember from 'ember'; export default Ember.Controller.extend({ sortProperties: ['fullName'], sortedContacts:

    Ember.computed.sort('model', 'sortProperties') });
  53. Bound Attributes

  54. <p>E-Mail: <a href="mailto:{{model.email}}">{{model.email}}</a></p>

  55. Components for Reusability

  56. ember generate component contact-card create app/components/contact-card.js create app/templates/components/contact-card.hbs installing component-test

    create tests/integration/components/contact-card-test.js
  57. <div class="contact-card"> <h5>{{contact.fullName}}</h5> <p>{{contact.description}}</p> </div> {{yield}}

  58. {{contact-card contact=model}}

  59. Community

  60. Community

  61. Ember Community Slack Channel (https://ember-community- slackin.herokuapp.com/)

  62. Tooling

  63. Ember-Inspector (https://github.com/ emberjs/ember-inspector)

  64. None
  65. None
  66. Let's talk more about Ember- CLI (www.ember-cli.com)

  67. What's the hype around Ember-CLI?

  68. ES6 via Esperanto

  69. None
  70. But Iheanyi, what about third party libraries or preprocessors?

  71. bower install bootstrap --save

  72. // ember-cli-build.js var EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function(defaults) {

    var app = new EmberApp(defaults, { // Add options here }); app.import('bower_components/bootstrap/dist/css/bootstrap.css'); return app.toTree(); };
  73. Cool! What about for JavaScript libraries?

  74. bower install moment --save

  75. // ember-cli-build.js var EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function(defaults) {

    var app = new EmberApp(defaults, { // Add options here }); ... app.import('bower_components/moment/moment.js'); return app.toTree(); };
  76. And preprocessors?

  77. ember install ember-cli-sass mv app/styles/app.css app/styles/app.scss

  78. None
  79. RemEMBER those conventions?

  80. Generators

  81. ember generate [options] <type> <name> [properties]

  82. acceptance-test adapter adapter-test addon addon-import app blueprint component component-addon component-test

    controller controller-test helper helper-test http-mock http-proxy in-repo-addon initializer initializer-test lib mixin mixin-test model model-test resource route route-test serializer serializer-test server service service-test template test-helper transform transform-test util util-test view view-test
  83. Addons

  84. Ember Observer (http://emberobserver.com/)

  85. None
  86. There's an addon for almost everything.

  87. User Authentication?

  88. None
  89. Mock Data/API Services?

  90. None
  91. // app/mirage/factories/contact.js import Mirage, {faker} from 'ember-cli-mirage'; export default Mirage.Factory.extend({

    firstName: faker.name.firstName, lastName: faker.name.lastName, email: faker.internet.email, avatar: faker.internet.avatar, description: faker.lorem.paragraphs(4) });
  92. // app/mirage/config.js export default function() { this.namespace = '/api'; this.get('/contacts',

    function(db, request) { return {contacts: db.contacts}; }); this.get('/contacts/:id', function(db, request) { return {contacts: db.contacts.find(request.params.id)}; }); }
  93. // app/mirage/scenarios/default.js export default function( server ) { // Seed

    your development database using your factories. This // data will not be loaded in your tests. server.createList('contact', 10); }
  94. // app/routes/contacts.js import Ember from 'ember'; export default Ember.Route.extend({ model()

    { return this.store.find('contact'); } });
  95. <div class="container"> <h1>Contacts Route</h1> <div class="contacts__sidebar"> <ul class="contacts__list"> {{#each sortedContacts

    as |contact|}} <li class="contacts__list__item"> {{#link-to 'contacts.show' contact.id}} <div class="contacts-list-item-detail"> <img class="contact__sidebar__picture" src={{contact.avatar}}> <span class="contact__sidebar__name">{{contact.fullName}}</span> </div> {{/link-to}} </li> {{/each}} </ul> </div> <div class="contacts__detail"> {{outlet}} </div> </div>
  96. None
  97. Testing

  98. QUnit

  99. ember generate acceptance-test list-contacts

  100. import Ember from 'ember'; import { module, test } from

    'qunit'; import startApp from 'front-porch-demo/tests/helpers/start-app'; var application; module('Acceptance: ListContacts', { beforeEach: function() { application = startApp(); }, afterEach: function() { Ember.run(application, 'destroy'); } }); test('visiting /contacts should list 10 contacts', function(assert) { server.createList('contact', 10); // Thanks Mirage! visit('/contacts'); andThen(function() { assert.equal(find('.contacts__list__item').length, 10); }); });
  101. None
  102. Like Mocha? No problem.

  103. ember install ember-cli-mocha

  104. /* jshint expr:true */ import { describe, it, beforeEach, afterEach

    } from 'mocha'; import { expect } from 'chai'; import Ember from 'ember'; import startApp from '../helpers/start-app'; describe('Acceptance: ListContacts', function() { var application; beforeEach(function() { application = startApp(); }); afterEach(function() { Ember.run(application, 'destroy'); }); it('can visit /contacts and see 10 contacts', function() { server.createList('contact', 10); visit('/contacts'); andThen(function() { expect(currentPath()).to.equal('contacts.index'); expect(find('.contacts__list__item').length).to.equal(10); }); }); });
  105. None
  106. Just wanna test from the CLI? Ember-CLI has your back.

  107. ember test

  108. ember test ... 1..32 # tests 32 # pass 24

    # fail 8
  109. ember test --server

  110. Deploying

  111. None
  112. Adapters for Azure, Redis, and S3

  113. npm install ember-cli-deploy --save-dev

  114. ember deploy --environment production

  115. Divshot.io

  116. None
  117. npm install --save-dev ember-cli-divshot

  118. ember generate divshot

  119. ember divshot push

  120. Trying to deploy to Heroku or IBM Bluemix?

  121. There's a buildpack for that. (https://github.com/tonycoco/ heroku-buildpack-ember-cli)

  122. heroku create --buildpack https://github.com/tonycoco/heroku-buildpack-ember-cli.git

  123. cf push ember_contacts_demo -b \ https://github.com/tonycoco/heroku-buildpack-ember-cli.git

  124. All of these deployment methods run the Ember Build command

    prior to deployment.
  125. Getting started with Ember-CLI is easy enough.

  126. npm install -g ember-cli

  127. ember new ember-demo-project

  128. Now you're ready to dive in.

  129. Links and Thanks http://emberjs.com http://ember-cli.com Brandon (@tehviking) Stanley (@fivetanley) Lon

    (@lawnsea) Chan (@chantastic) Ember Core Team And everybody else.
  130. Thank You. @kwuchu http://iheanyi.com