Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ember.js : Lessons from the trenches

Ember.js : Lessons from the trenches

From SEO to a highly performant infinite scrolling implementation, I will show you a handful collection of tips & tricks gathered by working on the largest Ember.js open-source application: Discourse.

Régis Hanol

January 30, 2014
Tweet

More Decks by Régis Hanol

Other Decks in Programming

Transcript

  1. SEO

  2. # topics_controller.rb ! @topic = ... ! respond_to do |format|

    format.html do store_preloaded("topic", @topic.to_json) render "topic" end ... end
  3. <!-- application.html.erb --> <%- if @preloaded.present? %> <script> <%- @preloaded.each

    do |key, json| %> PreloadStore.store("<%= key %>", <%= json %>); <% end %> </script> <%- end %>
  4. model: function() { // try the preload store first return

    PreloadStore.get("topic", function() { // hit the API return $.ajax("/topics/" + id + ".json"); }).then(function(result) { // instanciate a Topic return Discourse.Topic.create(result); }); }
  5. App.User = Ember.Object.extend({ ! staff: function() { return this.get("moderator") ||

    this.get("admin"); }.property("moderator", "admin") ! });
  6. App.User = Ember.Object.extend({ ! staff: function() { return this.get("moderator") ||

    this.get("admin"); }.property("moderator", "admin") ! }); var mod = App.User.create({ moderator: true });
  7. console.log(mod.get("staff")); // true App.User = Ember.Object.extend({ ! staff: function() {

    return this.get("moderator") || this.get("admin"); }.property("moderator", "admin") ! }); var mod = App.User.create({ moderator: true });
  8. App.User = Ember.Object.extend({ ! validUsername: function() { return this.get(‘username’).match(/^[a-z0-9]+$/); }.property(‘username’);

    ! adult: function() { return this.get(‘age’) >= 18; }.property(‘age’); ! french: function() { return this.get(‘country’) === ‘FR'; }.property(‘country’); ! });
  9. alias and any bool collect defaultTo empty equal filter filterBy

    gt gte intersect lt lte map mapBy match max min none not notEmpty oneWay or setDiff sort union uniq
  10. App.User = Ember.Object.extend({ ! adult: Ember.computed.gte('age', 18), ! french: Ember.computed.equal('country',

    ‘FR’), ! canVote: Ember.computed.and(‘adult’, ‘french’) ! });
  11. App.PostView = Ember.View.extend({ ! // right after it was inserted

    in the DOM didInsertElement: function() { var h = this.$().height(); // reflow this.$().height(h * 2); // reflow } ! });
  12. App.PostView = Ember.View.extend({ ! didInsertElement: function() { var element =

    this.$(); h = element.height(); // reads ! Ember.run.schedule('afterRender', function() { element.height(h * 2); // writes }); } ! });
  13. - Create a `CloakedView` instance ! - Listen for Window

    Scroll events ! = When off-screen # Record and fix height of parent view # Detach child instance ! = When on-screen # Re-attach child instance
  14. <!-- cloaked version --> {{cloaked-collection content=posts cloakView="post"}} <!-- regular version

    --> {{collection content=posts itemViewClass=“Discourse.PostView"}}