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. 7.
  2. 8.
  3. 10.
  4. 12.
  5. 13.

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

    URLs, UI, and State are all in sync.
  6. 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'}); }); });
  7. 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>
  8. 23.
  9. 28.
  10. 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}}
  11. 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'); }); } });
  12. 31.
  13. 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
  14. 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') });
  15. 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')}`; }) });
  16. 58.
  17. 59.
  18. 61.
  19. 63.
  20. 64.
  21. 67.

    ES6

  22. 68.
  23. 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(); };
  24. 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(); };
  25. 77.
  26. 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
  27. 82.
  28. 84.
  29. 87.
  30. 89.
  31. 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) });
  32. 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)}; }); }
  33. 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); }
  34. 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>
  35. 95.
  36. 96.
  37. 97.
  38. 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); }); });
  39. 100.
  40. 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); }); }); });
  41. 104.
  42. 106.
  43. 109.
  44. 110.
  45. 114.
  46. 115.
  47. 128.