Intro to Ember.js and Ember-CLI - ThunderPlainsConf 2015

Intro to Ember.js and Ember-CLI - ThunderPlainsConf 2015

This talk was on Ember.js and Ember-CLi and what I like about the framework as a developer and what i like about it as a designer.

E02ac480d0b92ec00e660be464d35c8d?s=128

Iheanyi Ekechukwu

November 03, 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. Like, 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. None
  32. Ember-Data

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

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

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

  36. 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
  37. // 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') });
  38. ember generate route contacts create app/routes/contacts.js create tests/unit/routes/contacts-test.js

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

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

    { return this.store.findAll('contact'); } });
  41. this.store.findAll('contact');

  42. this.store.findRecord('contact', params.id);

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

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

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

  46. contact.deleteRecord();

  47. contact.destroyRecord();

  48. Computed Properties

  49. // 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')}`; }) });
  50. this.store.createRecord('contact', {firstName: "Iheanyi", lastName: "Ekechukwu"}).then(function(contact) { contact.get('fullName'); // Iheanyi Ekechukwu

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

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

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

  54. Components for Reusability

  55. 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
  56. <div class="contact-card"> <h5>{{contact.fullName}}</h5> <p>{{contact.description}}</p> </div> {{yield}}

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

  58. Community

  59. Community

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

  61. Tooling

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

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

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

  67. ES6

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

  70. bower install bootstrap --save

  71. // 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(); };
  72. Cool! What about for JavaScript libraries?

  73. bower install moment --save

  74. // 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(); };
  75. And preprocessors?

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

  77. None
  78. RemEMBER those conventions?

  79. Generators

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

  81. 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
  82. Addons

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

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

  86. User Authentication?

  87. None
  88. Mock Data/API Services?

  89. None
  90. // 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) });
  91. // 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)}; }); }
  92. // 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); }
  93. // app/routes/contacts.js import Ember from 'ember'; export default Ember.Route.extend({ model()

    { return this.store.findAll('contact'); } });
  94. <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>
  95. None
  96. Testing

  97. QUnit

  98. ember generate acceptance-test list-contacts

  99. 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); }); });
  100. None
  101. Like Mocha? No problem.

  102. ember install ember-cli-mocha

  103. /* 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); }); }); });
  104. None
  105. Just wanna test from the CLI? Ember-CLI has your back.

  106. ember test

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

    # fail 8
  108. ember test --server

  109. Deploying

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

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

  113. ember deploy --environment production

  114. Firebase

  115. None
  116. npm install -g firebase-tools

  117. firebase init

  118. firebase deploy

  119. Trying to deploy to Heroku or IBM Bluemix?

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

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

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

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

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

  125. npm install -g ember-cli

  126. ember new ember-demo-project

  127. Now you're ready to dive in.

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

    (@lawnsea) Chan (@chantastic) Ember Core Team And everybody else.
  129. Thank You. @kwuchu