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

Simple JavaScript Abstractions

Simple JavaScript Abstractions

Lightning talk at WebRebels about simple JavaScript abstractions. Mainly focuses on creating a simple abstraction for the DOM.

6c51c14716e24bc1f1a3fb5ad234e773?s=128

Kim Joar Bekkelund

May 24, 2012
Tweet

More Decks by Kim Joar Bekkelund

Other Decks in Programming

Transcript

  1. Simple JavaScript abstractions

  2. I’m Kim I work at BEKK I’m on Twitter: @kimjoar

    I’m on Github: @kjbekkelund
  3. $

  4. $ Stop using jQuery directly all over your code!

  5. Why? jQuery(function() { $(“.user form”).submit(function(e) { e.preventDefault(); $.ajax({ // ...

    success: function(data) { var name = data.name ? data.name : “Unknown”; $(“.user .info”).append(“<h1>” + name + “</h1>”); } }); }); });
  6. Why? jQuery(function() { $(“.user form”).submit(function(e) { e.preventDefault(); $.ajax({ // ...

    success: function(data) { var name = data.name ? data.name : “Unknown”; $(“.user .info”).append(“<h1>” + name + “</h1>”); } }); }); }); PAGE EVENT USER EVENT NETWORK I/O NETWORK EVENT TEMPLATING PARSING RESPONSE Slide inspired by https://speakerdeck.com/u/bkeepers/p/the-plight-of-pinocchio
  7. This is a mess

  8. “Internal quality is what lets us cope with continual and

    unanticipated change” Steve Freeman, Nat Pryce Growing Object-Oriented Software, Guided by Tests
  9. We need decoupling We need structure We need abstractions

  10. Abstracting views

  11. It owns an HTML element A view’s responsibility:

  12. Views can read from the DOM, change it, and listen

    for events
  13. Our view API var el = $(“.user”); var userView =

    new UserView(el); userView.showUserInfo(); UserView is now responsible for everything related to the DOM within `.user`
  14. View API implementation var UserView = function(el) { this.el =

    el; } UserView.prototype.showUserInfo = function() { this.el.append("<h1>Kim Joar</h1>"); } That’s right — it’s just convention
  15. … but how will the view get any data?

  16. Events!

  17. Events var events = new EventEmitter(); var UserView = function(el)

    { this.el = el; // Bind events events.addListener(“user:fetched”, this.showUserInfo, this); } UserView.prototype.showUserInfo = function(user) {} // Trigger events events.emit(“user:fetched”, { name: “Kim Joar” });
  18. An example jQuery(function() { new UserView($(“.user”)); events.addListener(“user:submit”, getUser()); }); function

    getUser() { $.ajax({ // ... success: function(data) { events.emit(“user:fetched”, data); } }); }
  19. Or, even better jQuery(function() { var user = new User();

    // user model! new UserView($(“.user”), user); // view is allowed to }); // call methods on model —
  20. Or, even better jQuery(function() { var user = new User();

    new UserView($(“.user”), user, ...); }); And similarly we can also pass in other dependencies as arguments (events are not always the answer)
  21. Our views ≈ Presenter or Controller

  22. We have encapsulated network requests in Models. We have encapsulated

    the DOM in Views. We communicate using events instead of relying on callbacks. We have code that is far easier to test. And we are on our way to an MV* architecture.
  23. Let’s add some sugar

  24. Localized lookup // as views are passed `el`, which is

    a jQuery object, // we can search through the descendants as follows: userView.el.find(“h1”) // … but if we add: UserView.prototype.$ = function(selector) { return this.el.find(selector); } // we can do this instead: userView.$("h1") // less coupled to the DOM!
  25. Event delegation UserView.prototype.events = { “submit .user-form”: “validateAndPost”, “click .title”:

    “editName” }; UserView.prototype.validateAndPost = function() {} // or (using Backbone.js): var UserView = View.extend({ events: { “submit .user-form”: “validateAndPost” }, validateAndPost: function() {} });
  26. Local events var UserView = function(el, user) { this.el =

    el; // Binding events on `user` instead of `events` user.addListener(“fetched”, this.showUserInfo, this); } User.prototype.addListener = function() { if (!this.events) this.events = new EventEmitter(); this.events.apply(this.events, arguments); } // and the same for `emit` user.emit(“fetch”); // triggers the “local” event
  27. Add sugar using layers, mixins, or an existing library

  28. If you like this, check out

  29. “An element’s cohesion is a measure of whether its responsibilities

    form a meaningful unit” Steve Freeman, Nat Pryce Growing Object-Oriented Software, Guided by Tests
  30. $ Don’t use it less, use it smarter!

  31. Questions?