29
INTRO TO EMBER.JS Sandino Núñez @sandinosaso https://github.com/sandinosaso

Intro to Ember.JS 2016

Embed Size (px)

Citation preview

Page 1: Intro to Ember.JS 2016

INTRO TO EMBER.JS

Sandino Núñez@sandinosaso

https://github.com/sandinosaso

Page 2: Intro to Ember.JS 2016

YES, ANOTHER JAVASCRIPT FRAMEWORK

Page 3: Intro to Ember.JS 2016

EMBER.JS

Page 4: Intro to Ember.JS 2016

WHAT IS EMBER.JS ➤ A framework for creating ambitious web application➤ Built for productivity (provides architecture)➤ Opinionated (sometimes perceived as difficult to

learn)➤ Convention over Configuration

(besides awesome!)

Page 5: Intro to Ember.JS 2016

EMBER IN THE WILD

http://emberjs.com/ember-users/

Page 6: Intro to Ember.JS 2016

Simple apps can use simple tools

Page 7: Intro to Ember.JS 2016

APPS NEEDS

➤ Keep it organized➤ Modularize your code➤ Separate concerns➤ Establish conventions for smooth

teamwork➤ Keep it testable

ARCHITECTUREBIG

Page 8: Intro to Ember.JS 2016

EMBER CORE CONCEPTS➤ Classes and Instances➤ Computed Properties➤ Bindings➤ Templates➤ Route➤ Models➤ Components➤ Data Down - Actions Up➤ Lots of other features - we’ll just barely scratch the

surface in today’s session

Page 9: Intro to Ember.JS 2016

EMBER OBJECT➤ Base “class” that almost every object should inherit

from➤ Contains …

Page 10: Intro to Ember.JS 2016

EMBER OBJECT 1 import Ember from 'ember';

2 3 let Person = Ember.Object.extend({ 4 say(message) { 5 alert(message); 6 } 7 }); 8 9 let Bob = Person.create(); 10 Bob.say('Hello World'); 11 // alerts "Hello World" 12 13 let Man = Person.extend({ 14 say(message) { 15 message += ', says the man.'; 16 this._super(message); 17 } 18 }); 19 20 let Tom = Man.create(); 21 Tom.say('Hello World'); 22 // alerts "Hello World, says the man."

Page 11: Intro to Ember.JS 2016

EMBER OBJECT➤ Obj.create() instead of new instances➤ Obj.extend() for single inheritance (mixins exists as

well)➤ this._super() calls overridden implementation➤ Obj.reopen() to edit class definition➤ Obj.get(‘key’) and Obj.set(‘key’)➤ Allows dynamically created property values➤ Object can listen for properties changes➤ Use of .setProperties({ key: value }) for multiple at

time.

Page 12: Intro to Ember.JS 2016

COMPUTED PROPERTIES➤ Used to build a property that depends on other

properties➤ Provide any property key you access and the property

value will be recomputed if change➤ Should not contain application behavior, and should

generally not cause any side-effects when called. 1 import Ember from 'ember'; 2 3 let Person = Ember.Object.extend({ 4 firstName: '', 5 lastName: '', 6 7 fullName: Ember.computed('firstName', 'lastName', function() { 8 return this.get('firstName') + ' ' + this.get('lastName'); 9 }) 10 }); 11 12 let bob = Person.create({ 13 firstName: 'Bob', 14 lastName: 'Esponja' 15 }); 16 17 bob.get('fullName'); 18 // "Bob Esponja"

Page 13: Intro to Ember.JS 2016

COMPUTED PROPERTIES

(advanced usage)

1 export default Ember.Component.extend({ 2 selectedTodo: null, 3 4 todos: [ 5 Ember.Object.create({ isDone: true }), 6 Ember.Object.create({ isDone: false }), 7 Ember.Object.create({ isDone: true }) 8 ], 9 10 // Custom 11 incomplete: Ember.computed('[email protected]', function() { 12 var todos = this.get('todos'); 13 return todos.filterBy('isDone', false); 14 }), 15 16 // Using defined macro 17 incomplete: Ember.computed.filterBy('todos', 'isDone', false), 18 19 indexOfSelectedTodo: Ember.computed('selectedTodo', 'todos.[]', function() { 20 return this.get('todos').indexOf(this.get('selectedTodo')); 21 }) 22 });

Page 14: Intro to Ember.JS 2016

BINDINGS➤ Unlike most other frameworks that include some sort of

binding implementation, bindings in Ember can be used with any object.

➤ A one-way binding only propagates changes in one direction, using computed.oneWay()

1 wife = Ember.Object.create({ 2 householdIncome: 80000 3 }); 4 5 Husband = Ember.Object.extend({ 6 householdIncome: Ember.computed.alias('wife.householdIncome') 7 }); 8 9 husband = Husband.create({ 10 wife: wife 11 }); 12 13 husband.get('householdIncome'); // 80000 14 15 // Someone gets raise. 16 wife.set('householdIncome', 90000); 17 husband.get('householdIncome'); // 90000

Page 15: Intro to Ember.JS 2016

TEMPLATES➤ Uses Handlebars + Ember helpers➤ Ember adds partial, render, view and control helpers➤ Each template is backed by a model➤ They include helpers such as: other templates, if

else, loops, formatting helpers, expressions like {{model.firstName}}, outlets (which are placeholders), components

1 <div id="main"> 2 <div class="container-fluid"> 3 4 {{outlet}} 5 6 </div> 7 </div>

Page 16: Intro to Ember.JS 2016

ROUTES➤ Url representation of your application’s objects, telling the

template ➤ The router.js file defines the mapping between routes/urls

1 import Ember from 'ember'; 2 import config from './config/environment'; 3 4 const Router = Ember.Router.extend({ 5 location: config.locationType 6 }); 7 8 Router.map(function() { 9 this.route('login'); 10 11 this.route('patients', function() { 12 this.route('new'); 13 this.route('edit', { path: 'edit/:id' }); 14 this.route('view', { path: 'view/:id' }); 15 this.route('audit', { path: 'audit/:id' }); 16 17 this.route('activities', { path: '/activities/:patient_id' }, function() { 18 this.route('new', { path: 'new' }); 19 this.route('view', { path: 'view/:id' }); 20 }); 21 22 this.route('events', { path: '/events/:patient_id' }, function() { 23 this.route('new', { path: '/new/:eventType' }); 24 this.route('view', { path: '/view/:id' }); 25 }); 26 27 }); 28 }); 29 30 export default Router;

Page 17: Intro to Ember.JS 2016

1 import Ember from 'ember'; 2 3 export default Ember.route.extend({ 4 5 model: function() { 6 return [ 7 { 8 title: “London Palace" 9 }, 10 { 11 title: "Eiffel Tower" 12 } 13 ]; 14 } 15 });

ROUTING(implementation of a base route)

The model usually is a record. The result of a query to ember-data store

1 import Ember from 'ember'; 2 3 export default Ember.route.extend({ 4 5 model(params) { 6 var url = 'https://api.github.com/repos/' + params.repo_id; 7 return Ember.$.getJSON(url); 8 } 9 });

The model can be a POJO

1 import Ember from 'ember'; 2 3 export default Ember.route.extend({ 4 5 model: function(params) { 6 return this.store.find('myModel', params); 7 }, 8 9 setupController: function(controller, model) { 10 controller.set('model', model); 11 } 12 });

The result of an ajax call

Page 18: Intro to Ember.JS 2016

ROUTING(returning multiple models)

1 import Ember from 'ember'; 2 3 export default Ember.route.extend({ 4 5 setupController(controller, model) { 6 controller.setProperties({ 7 patient: model.patient, 8 products: model.products 9 }); 10 11 set(controller, 'isLoading', false); 12 }, 13 14 model(params) { 15 return RSVP.hash({ 16 patient: this.store.findRecord('patient', params.id), 17 products: this.store.findAll('product') 18 }); 19 } 20 });

Page 19: Intro to Ember.JS 2016

ROUTES➤ The route queries the model and makes it available in the controller

and templates➤ When the template or models being shown to the user changes, Ember

automatically keeps the url in the browser’s address bar up-to-date➤ This means that at any point, users are able to share the URL of your

app➤ Ember Add-on for Chrome and Firefox let you inspect routes / data /

promises➤ error and loading routes automatically created and used on model

loading and error states

Page 20: Intro to Ember.JS 2016

MODELS➤ Define a mapping to the application data➤ Has default types: string, number, boolean, date. Supports

customs types 1 import Ember from 'ember'; 2 import Model from 'ember-data/model'; 3 import attr from 'ember-data/attr'; 4 import { belongsTo, hasMany } from 'ember-data/relationships'; 5 6 const { computed } = Ember; 7 8 export default Model.extend({ 9 'name': attr('string'), 10 'surname': attr('number'), 11 'is_admin': attr('boolean'), 12 13 'roles': hasMany('roles', { embedded: 'always'}), 14 'office': belongsTo('office', { async: 'true' }), 15 16 fullName: computed('name', 'surname', () => { 17 return this.get('name') + ' ' + this.get('surname'); 18 }), 19 20 roleList: computed('roles.@each', () => { 21 return this.get('roles').map((role) => { 22 return role.get('name'); 23 }) 24 }) 25 });

Page 21: Intro to Ember.JS 2016

MODELS

➤ In the first case the data comes from backend in the model itself (payload)

➤ In the second case the model only contains the ‘ID’ of the related model and is loaded asynchrony with an specific call when required.

13 'roles': hasMany('roles', { embedded: 'always'}), 14 'office': belongsTo('office', { async: 'true' }),

(relationships)

You can also define custom attr options, for example (readOnly):

16 'entityId': attr('string', { readOnly: true }),17 'entityType': attr('string', { readOnly: true }),

Page 22: Intro to Ember.JS 2016

MODELS➤ You can define custom types to fit any kind of data➤ Makes it easy to maintain as you only need to change in

one place 1 // app/transforms/utc.js 2 import DS from 'ember-data'; 3 import moment from 'moment'; 4 5 export default DS.Transform.extend({ 6 serialize(value) { 7 let formatedDate = moment.utc(value).format('YYYY-MM-DDTHH:mm:ss', 'en'); 8 return formatedDate; 9 }, 10 11 deserialize(value) { 12 return value; 13 } 14 });

1 export default Model.extend({ 2 'productId': attr('number'), 3 'eventTypeID': attr('number'), 4 'reasonSVID': attr('string'), 5 'notes': attr('string'), 6 7 'eventDate': attr('utc', { defaultValue: () => new Date() }) 8 }

Page 23: Intro to Ember.JS 2016

ADAPTER / SERIALIZER➤ By default ember-data uses JSON-API format

➤ You can override default behavior either application level or for particular models

(fit any backend data even legacy one !!)

Page 24: Intro to Ember.JS 2016

➤ In Ember Data, the Adapter determines how data is persisted to a backend data store, such as the URL format and headers for a REST API.

➤ You can change default functionality (if your backend conventions differ from ember-data assumptions) by extending it

ADAPTER(customization example)

1 import Ember from 'ember'; 2 import DS from 'ember-data'; 3 4 export default DS.JSONAPIAdapter.extend({ 5 host: 'https://api.example.com', 6 namespace: 'api', 7 8 session: Ember.inject.service('session'), 9 10 headers: Ember.computed('session.authToken', function() { 11 return { 12 'API_KEY': this.get('session.authToken'), 13 'ANOTHER_HEADER': 'Some header value' 14 }; 15 }) 16 });

Page 25: Intro to Ember.JS 2016

➤ In Ember Data, serializers format the data sent to and received from the backend store.

SERIALIZER(customization example)

Page 26: Intro to Ember.JS 2016

ADAPTER / SERIALIZER

(customization/ methods)

Page 27: Intro to Ember.JS 2016

COMPONENTS➤ A completed isolated view that has no access to the

surrounding context ➤ A great way to build reusable components for your application➤ routable-components will be the future

Page 28: Intro to Ember.JS 2016

DATA DOWN! ACTIONS UP!➤ DDAU - single data flow (hence unidirectional)➤ Apps easier to reason about➤ Improves performance

(GoodBye MVC)

Page 29: Intro to Ember.JS 2016

DEMO - SHOWCASE - TIME