Event Oriented Architecture and Client side apps

Event Oriented Architecture and Client side apps

9976060bfb26220dd042340394d06b31?s=128

Mihael Konjević

November 16, 2012
Tweet

Transcript

  1. EOA and Client side applications Mihael Konjević - @mihaelkonjevic

  2. WHO AM I? • JavaScript developer at Bitovi • Development,

    training and consulting • JavaScriptMVC, CanJS, StealJS, jQuery++... http://javascriptmvc.com http://canjs.us http://jquerypp.com
  3. WHAT WE WANT?

  4. WHAT WE WANT? • Ease of development

  5. WHAT WE WANT? • Ease of development • Maintainability of

    code
  6. WHAT WE WANT? • Ease of development • Maintainability of

    code • Testability
  7. SRCHR APP

  8. WHAT WE’LL COVER

  9. WHAT WE’LL COVER • Modules and isolation

  10. WHAT WE’LL COVER • Modules and isolation • Directory structure

  11. WHAT WE’LL COVER • Modules and isolation • Directory structure

    • Application glue
  12. MODULES Perfect module is dumb, lonely and replaceable

  13. Modules should be Dumb

  14. Modules should be Lonely

  15. Modules should be Replaceable

  16. Application structure

  17. Search module • User can select services to search •

    User can enter the search term and trigger search
  18. History module • Keep track of searches • On click

    redo search • User can delete search
  19. Search Results • Perform search • List results

  20. Tabs • Clicking on the tabs shows search results for

    that service
  21. Events

  22. Events • DOM events

  23. Events • DOM events • Synthetic events on DOM elements

  24. Events • DOM events • Synthetic events on DOM elements

    • Synthetic events on JavaScript objects
  25. Search module • Triggers search event on the Search model

    $([Models.Search]).trigger("search",search);
  26. History module • Listens to search event on the search

    model • Triggers selected event on the clicked element "{Models.Search} search": function(el, ev, searchInst){ ! if(this.history.indexOf(searchInst) === -1){ ! ! this.history.push(searchInst) ! } }, "li click" : function(el, ev){ ! el.trigger("selected", el.data('search')) }
  27. Tabs module • Triggers activated event on clicked tab •

    Listens to activated event on clicked tab • Triggers show event on search results element this.tab(el.addClass('active')).show().trigger("show"); "li click": function( el, ev ) { ! ev.preventDefault(); ! el.trigger("activate"); }, "li activate": function( el, ev ) { ! this.activate(el); },
  28. Search Results module • Listens to show event on the

    element triggered by the tabs module • Listens to search event on the search model "{Models.Search} search": function(el, ev, searchInst){ ! this.currentSearch = searchInst.query; ! ... }, activate: function( el ) { ! this.tab(this.element.find('.active').removeClass('active')).hide(); ! this.tab(el.addClass('active')).show().trigger("show"); }
  29. What about disabled tabs?

  30. "li activate": function( el, ev ) { ! if(!el.hasClass('disabled')){ !

    ! this.activate(el); ! } } What about disabled tabs?
  31. Disabler module Disabler = can.Control({}, { ! "{Models.Search} search": function(el,

    ev, searchInst){ ! ! var types = searchInst.attr('types'); ! ! this.element.find('li').removeClass('disabled').map(function(i, el){ ! ! ! var $el = $(el); ! ! ! if(types.indexOf($el.data('service')) === -1){ ! ! ! ! $el.addClass('disabled'); ! ! ! } ! ! }); ! ! this.element.find('li:not(.disabled):first').trigger('activate') ! }, ! "li activate" : function(el, ev){ ! ! if(el.hasClass('disabled')){ ! ! ! ev.stopImmediatePropagation(); ! ! } ! } })
  32. Application workflow

  33. Events diagram

  34. • Keep your modules dumb, isolated and replaceable • Define

    inputs and outputs • Use events instead callbacks Summary
  35. The secret to building large apps is to never build

    large apps.
  36. button.js jquery.ui.calendar.js contactmanager.js tabs.js jquery.js nav.js resizer.js \test button_test.js contactmanager.js

    tabs_test.js nav_test.js
  37. \tabs tabs.js - the code for a tabs widget tabs.html

    - a demo page funcunit.html - a test page tabs_test.js - test code tabs.css - css for the tab
  38. Assembling the app • load dependencies • initialize the code

    \srchr \disabler \history \search \search_results search_results.js search_results.html search_results.css funcunit.html \tabs srchr.js srchr.html
  39. Gluing it together var searchController = new Search($("#searchArea")) new SearchResult($('#upcoming'),

    { modelType: Models.Upcoming, resultView: 'searchResultUpcomingEJS' }) new SearchResult($('#twitter'), { modelType: Models.Twitter, resultView: 'searchResultTwitterEJS' }) new Disabler($('#resultsTabs')) new Tabs($("#resultsTabs")) new History($('#history')) $('#history').bind("selected", function(ev, search){ ! searchController.val(search) })
  40. Questions?