Download - Building Ambitious Web Apps with Ember
BUILDING AMBITIOUS WEB APPS WITHEMBER.JS
Desert Code Camp 2014
GREG BABIARSDeveloper at Swiftpage
http://gregbabiars.com
@gbabiars
https://github.com/gbabiars
WHAT IS EMBER?A framework for creating ambitious web applicationsMVC frameworkDesigned with productivity in mindInspired by Cocoa and RailsCommunity driven
WHY USE EMBER TO BUILD WEB APPS?Increases productivity and reduces boilerplateConventions guide you down the right pathAs your app grows the complexity stays constantLeverages work of community to solve common problemsEmbraces the URL
MYTHS ABOUT EMBERDocumentation sucksHard to testNot flexible
CORE CONCEPTSObservers/Computed PropertiesActions & EventsRun Loop
EMBER.OBJECTAll "classes" in Ember inherit from Ember.Object. This is the
building block for just about everything in Ember and provides:
The ability to create observers and computed properties.get and .set which allow us access and trigger propertiesthrough bindings.
EMBER.OBJECT INSTANTIATIONvar myObject = Ember.Object.create({ firstName: 'Greg', lastName: 'Babiars'});myObject.set('firstName', 'Gregory');myObject.get('firstName'); // Gregory
EXTENDING AN OBJECTvar Person = Ember.Object.extend({ firstName: '', lastName: '', sayName: function() { console.log(this.get('firstName') + ' ' + this.get('lastName'); }});var myPerson = Person.create({ firstName: 'John', lastName: 'Doe' });myPerson.sayName(); // John Doe
COMPUTED PROPERTIESMethods that can be accessed as propertiesAllows us to propagate changes through our applicationWe can specify our dependent properties that trigger anupdate
COMPUTED PROPERTIES
var Person = Ember.Object.extend({ firstName: '', lastName: '', name: function() { return this.get('firstName') + ' ' + this.get('lastName'); }.property('firstName', 'lastName')});var myPerson = Person.create({ firstName: 'John', lastName: 'Doe' });myPerson.get('name'); // John Doe
OBSERVERSMethods that are called when a dependent key has changed
OBSERVERS
var Person = Ember.Object.extend({ firstName: '', lastName: '', nameChanged: function() { console.log('A name has changed'); }.observes('firstName', 'lastName')});var myPerson = Person.create({ firstName: 'John', lastName: 'Doe' });myPerson.set('firstName', 'Jane'); // A name has changed will be logged
ACTIONSTriggered in templates using {{action}} or JS using .send()Can be handled in views, controllers or routesHandlers must be defined in the actions hashStarts in controller, bubbles up through parent routes untilhandler is found
EVENTSLow level DOM events (click, scroll, etc)Handled in views mostlyDoes not need to be namespaced
RUN LOOPA set of queues that batch and order workIntelligently executes your application to maximize efficiencyand effectivenessHave access to schedule using Ember.run
ARCHITECTUREApplicationRouterRoutesControllersViewsComponentsTemplates
EMBER.APPLICATIONInstantiate a single instance for your application. Can optionally
pass in an element id to use as the root of your application.Creates the namespace for your application.
var App = Ember.Application.create();
EMBER.ROUTERUsed to define the route structure of your application. This is
done using Router.map.
App.Router.map(function() { this.resource('posts', function() { this.route('post', { path: ':post_id' }); // Maps to /posts/1 }); this.resource('about', { path: 'my-about-page' });});
EMBER.ROUTERCan define routes and resources. Resources can have have other
routes and resources nested under them while routes cannot.Resources automatically defines index, loading and error routes.
Routes are terminal.
EMBER.ROUTERResources will generate a route, controller and template at run
time if one matching the naming convention is not found.
For example, our posts resource will lookup or generate:
PostsRoutePostsControllerposts.handlebars
EMBER.ROUTERoute objects give you control over what happens within a
specific route of your application. It has hooks that allows you tocustomize the following:
Loading the model for that routeSetting up the state of the controllerCustomize what is renderedCustom logic when entering/existing the routeHandle actions that bubble upAllows us to transition to other routes
EMBER.ROUTE
App.PostsRoute = Ember.Route.extend({ // Load the model, if a promise it will not continue until it resolves model: function() { return this.store.find('post'); }, // Customize the state of the controller setupController: function(controller, model) { controller.set('model', model); controller.set('isEditing', false); }, // Customize what is rendered renderTemplate: function(controller) { this.render('post-list', { controller: controller }); }});
EMBER.CONTROLLERControllers are designed to manage application state. They have
several properties:
One is generated for each routeCan depend on other controllersHolds transient state and logic for a specific templateTypically has a model that represents an object or arrayHandles actions triggered from the template
EMBER.OBJECTCONTROLLERExample of an object controller
App.PostController = Ember.ObjectController.extend({ hasComments: function() { return this.get('model.comments.length') > 0; }.property('model.comments.length')
actions: { cancel: function() { this.get('model').rollback(); } }});
EMBER.ARRAYCONTROLLERExample of an array controller
App.PostsController = Ember.ArrayController.extend({ hasReadAllPosts: function() { var unreadreadPosts = this.get('model').filterBy('isRead', false); return unreadPosts.get('length') === 0; }.property('[email protected]'),
actions: { readPost: function(post) { post.set('isRead', true'); } }});
EMBER.VIEWAble to specify the tagName, css classesHandles DOM events (click, key press, etc)Can have conditional html attributes (class, disabled, etc)Has a backing controllerNot commonly used
EMBER.VIEWApp.PostView = Ember.View.extend({ tagName: 'article', classNameBindings: ['selected:active'], selected: false, templateName: 'post-detail', click: function() { this.get('controller').doSomething(); }});
{{view App.PostView postBinding="post" selected="false"}}
EMBER.COMPONENTSubclass of Ember.View, designed for reuseSandboxed, backing controller and context is itselfAll properties must be passed in via templateMust explicitly bind external actions to actions inside thecomponentBest place to wrap 3rd party plugins, i.e. jQuery plugins
EMBER.COMPONENTApp.ButtonComponent = Ember.Component.extend({ tagName: 'button', classNames: ['btn'], click: function() { this.sendAction(); }});App.DemoController = Ember.Controller.extend({ buttonText: 'Click Me', actions: { doSomething: function() { console.log('button triggered this'); } }});
{{button text=buttonText action="doSomething"}}
EMBER.COMPONENTModal example
App.ModalComponent = Ember.Component.extend({ classNames: ['modal', 'fade'], isOpen: false, didInsertElement: function() { this.$().modal({ show: false }); }, actions: { submit: function() { this.sendAction(); } }, toggleVisible: function() { this.$().modal(this.get("isOpen") ? "show" : "hide"); }.observes("isOpen")});
EMBER.COMPONENTModal example (cont.)
Modal component template<div class="modal-content"> {{yield}}</div><div class="modal-footer"> <button {{action "submit"}}>Submit</button></div>
EMBER.COMPONENTModal example (cont.)
Person controllerApp.PersonController = Ember.Controller.extend({ formOpen: false, actions: { toggleForm: function() { this.toggleProperty('formOpen'); }, save: function() { this.get('model').save(); } }});
EMBER.COMPONENTModal example (cont.)
Person Template<button {{action "toggleForm"}}>Toggle Form</button>{{#modal action="save" isOpen=formOpen}} <label>Name:</label> {{input value=model.name}}{{/modal}}
TEMPLATESAlways have a backing context, typically a controllerHandlebars - Logicless templates, logic lives in JSAutomatically update propertiesCan trigger actions
TEMPLATESSimple syntax example
<div> <h1>{{person.name}}</h1> ##{{person.company}}</h2></div>
TEMPLATESUsing each and link-to
<ul> {{#each post in model}} <li> {{link-to post.name "post" post}} </li> {{/each}}</ul>
TEMPLATESTriggering an action
<button {{action "save" model}}></button>
WHAT ABOUT PERSISTENCE?Well that's a whole different talk!
PERSISTENCE LIBRARIESEmber DataEmber ModelEmber Persistence Foundation (EPF)ic-ajax
FURTHER LEARNINGhttp://emberjs.com/guideshttp://emberjs.com/apihttps://www.youtube.com/user/EmberNYChttp://emberweekly.com/