Vous êtes sur la page 1sur 32

EOA and Client side applications

Mihael Konjevi - @mihaelkonjevic


WebCamp Zagreb 2012

WHO AM I?
JavaScript developer at Bitovi Development, training and consulting JavaScriptMVC, CanJS, StealJS,
jQuery++... http://javascriptmvc.com http://canjs.us http://jquerypp.com

Syntax
can.Control('Controller.Name', { static : function(){ ... } }, { instance : function(){ ... }, ".selector click" : function(el, ev){ ... }, "{object} synEvent" : function(){ ... } })

WHAT WE WANT?
Ease of development Maintainability of code Testability

SRCHR APP

WHAT WELL COVER


Modules and isolation Directory structure Application glue

MODULES
Perfect module is dumb, lonely and replaceable

Modules should be Dumb

Modules should be Lonely

Modules should be Replaceable

Application structure

Search module

User can select services to search User can enter the search term and trigger search

History module

Keep track of searches

On click redo search


User can delete search

Search Results

Perform search List results

Tabs

Clicking on the tabs shows search results for that service

Events
DOM events Synthetic events on DOM elements Synthetic events on JavaScript objects

Search module
Triggers search event on the Search
model $([Models.Search]).trigger("search",search);

History module
Listens to search event on the search
model
"{Models.Search} search": function(el, ev, searchInst){ if(this.history.indexOf(searchInst) === -1){ this.history.push(searchInst) } },

Triggers selected event on the clicked


element
"li click" : function(el, ev){ el.trigger("selected", el.data('search')) }

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 activate": function( el, ev ) { this.activate(el); }, "li click": function( el, ev ) { ev.preventDefault(); el.trigger("activate"); },

Tabs module

Listens to show event on the element


triggered by the tabs module
activate: function( el ) { this.tab(this.element.find('.active').removeClass('active')).hide(); this.tab(el.addClass('active')).show().trigger("show"); }

Search Results module

Listens to search event on the search


model
"{Models.Search} search": function(el, ev, searchInst){ this.currentSearch = searchInst.query; ... },

What about disabled tabs?

What about disabled tabs?


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

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(); } } })

Application workflow

Events diagram

Summary
Keep your modules dumb, isolated and
replaceable

Define inputs and outputs Use events instead callbacks

The secret to building large apps is to never build large apps.


Justin Meyer

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

\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

Assembling the app


load
dependencies
\srchr \disabler \history \search \search_results search_results.js search_results.html search_results.css funcunit.html \tabs srchr.js srchr.html

initialize the code

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) })

Questions?

Vous aimerez peut-être aussi