Estella Madison
Front End Engineer
@chicagoing
We used the online documentation but relied heavily on comments included with the unminified source file:
/**
An `Ember.Binding` connects the properties of two objects so that whenever
the value of one property changes, the other property will be changed also.
## Automatic Creation of Bindings with `/^*Binding/`-named Properties
You do not usually create Binding objects directly but instead describe
bindings in your class or object definition using automatic binding
detection.
Earlier versions of Ember didn't automatically create your controllers. We started off with adding most of them to the global namespace.
App.bookController = App.BookController.create();
App.editorController = App.EditorController.create();
App.pageController = App.PageController.create();
connectControllers()
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
var bookController = this.controllerFor('book'),
pageController = this.controllerFor('page'),
editorController = this.controllerFor('editor');
bookController.connectControllers('editor', 'page');
}
});
No more connectControllers
NO!
We noticed a needs
property in Ember.ControllerMixin:
Ember.ControllerMixin.reopen({ concatenatedProperties: ['needs'], needs: [],
...
});
But no comments; no online documentation.
connectControllers
ourselves:var connectControllers = function() {
var controllerName,
controllerNames = Array.prototype.slice.apply(arguments);
for (var i=0, l=controllerNames.length; i<l; i++) {
controllerName = controllerNames[i];
this.set(
controllerName+'Controller',
route.controllerFor(controllerName));
}
};
Ember.Controller.reopen({ connectControllers: connectControllers });
Ember.ObjectController.reopen({ connectControllers: connectControllers });
Ember.ArrayController.reopen({ connectControllers: connectControllers });
This allowed us to focus on updates for
view context and the new router.
App.BookController = Ember.Controller.extend({
needs: ['page', 'editor']
...
});
We quickly realized that moving more of logic into our controllers made our app more maintainable.
Source madhatted.com
View context was changed to the supplied controller.
Chrome Dev Tools is the obvious debugging tool, but some of the vague errors thrown by Ember made tracing the source difficult.
{{#if}}
handlebar helpers.if (this.get('state') === 'inDOM')
Prints out a readable string for the object.
Given the ID of a view, you can get the view properties.
http://vimeo.com/37539737
Sometimes Ember.beforeObserver() helped. Other times we added additional properties to cascade observers.
App.MockController = Ember.Controller.extend({
property1: null,
observer1: function() {
...
}.observes('property1'),
// We want this observer to trigger first
observer2: function() {
...
}.observes('property1')
});
App.MockController = Ember.Controller.extend({
property1: null,
// We add a second property to trigger the rest of the observers
observer2triggered: false,
observer1: function() {
...
}.observes('observer2triggered'),
// We want this observer to trigger first
observer2: function() {
this.set('observer2triggered', true);
}.observes('property1')
});
Big Ember.CollectionViews caused browsers to render slowly
Display all the images and media files uploaded by the users.
Gives an overview of the book, displaying a thumbnail size view of each page.
We built a custom IncrementalCollectionView.
var obj = Ember.Object.create({
valueBinding: Ember.Binding.oneWay('value')
});
According to the documentation:
One way bindings are almost twice as fast to setup and twice as fast to execute because the binding only has to worry about changes to one side.
At first, we overused jQuery because it was what we knew best.
.$().fadeIn()
& .$().fadeOut()
Replaced these with the CSS transition property.
.$().append()
& .$().remove()
Instead of using jQuery to append/remove DOM elements, we use Ember.ContainerViews when possible.
Especially jQuery UI. We knew these would bloat our code.
Source: Stackoverflow.com, "EmberJS Set Multiple Properties At Once", Luke Melia's response
set/setProperties
Set a list of properties on an object. These properties are set inside a single `beginPropertyChanges` and `endPropertyChanges` batch, so observers will be buffered.
this.set({ property1: 'val1', property2: 'val2' });
... so that notifications will not be sent until the changes are finished. Useful for making a large number of changes at once.
Ember.beginPropertyChanges
Call this at the beginning of the changes to begin deferring change
notifications.Ember.endPropertyChanges
Delivers the deferred change notifications and ends deferring.// Suspend observer triggers
Ember.beginPropertyChanges();
if (this.get('condition1')) { obj1.set('property1', 'val1'); }
if (this.get('condition2')) { obj2.set('property2', 'val2'); }
// Restore triggers and flush
Ember.endPropertyChanges();
Ember.changeProperties
Accepts a callback and calls Ember.beginPropertyChanges, then the callback, and then Ember.endPropertyChanges, even if your callback raised an exception.
Ember.changeProperties(function() {
obj1.set('property1', 'changing this make things blow up');
obj2.set('property2', 'val2');
});
As a parting gift we're extending a coupon to attendees:
COUPON CODE: ember.js