128
JAVASCRIPT MODULAR E EVENT-DRIVEN @shiota 2013

JavaScript Modular e Event-Driven

Embed Size (px)

DESCRIPTION

Em aplicações de larga escala, certas interações que parecem simples aos olhos do usuário escondem a complexidade de múltiplas requisições assíncronas e updates no DOM toda vez que uma informação é modificada. Esta complexidade pode facilmente virar um inferno de callbacks, e nesta palestra mostrarei como através de uma estrutura event driven criada do zero é possível quebrar uma página em componentes modulares, desacoplados, e testáveis.

Citation preview

Page 1: JavaScript Modular e Event-Driven

JAVASCRIPT MODULARE EVENT-DRIVEN

@shiota 2013

Page 2: JavaScript Modular e Event-Driven

OLÁ!slideshare.net/eshiota

github.com/eshiota@shiota

Page 3: JavaScript Modular e Event-Driven

front-end engineer@

Page 4: JavaScript Modular e Event-Driven
Page 5: JavaScript Modular e Event-Driven

* 28/08/2013 https://github.com/search?p=1&q=stars%3A%3E1&s=stars&type=Repositories

Dos 50 repositórios maispopulares do Github, 28 repositórios são relacionados a JavaScript.

Page 6: JavaScript Modular e Event-Driven

JavaScript é legal!

Page 7: JavaScript Modular e Event-Driven
Page 8: JavaScript Modular e Event-Driven

Mas pode ser infernal também.

Page 9: JavaScript Modular e Event-Driven
Page 10: JavaScript Modular e Event-Driven

Ele pode ficar impossível de ser entendido ou alterado.

Page 11: JavaScript Modular e Event-Driven

(function(){ window.app = jQuery.extend({ init: function(){ tab = $('.tabs li > a.tab-toggle'); tabs = $('.tabs').find('> div');

if (tabs.length > 1){ tab.each(function (i){$(this).attr('href', '#content-' + ++i)}); tabs.each(function(i){$(this).attr('id', 'content-' + ++i)}); tabs.addClass('tab-inactive'); $('.tabs li:first-child a').addClass('state-active'); }

$('#initial-cash, #financing_value_vehicles, #tax, #bid-initial-cash, #bid-product-value').maskMoney({ thousands: '.', decimal: ',', allowZero: true, allowNegative: false, defaultZero: true });

/** FINANCING CALCULATOR **/ $("#financing_value_vehicles").on("blur", function(){ var price = (accounting.unformat($(this).val(), ",")) || 0;

var suggestedInitialPayment = price * 0.2;

var formattedResult = accounting.formatMoney(suggestedInitialPayment, "", "2", ".", ","); $("#initial-cash").val(formattedResult); });

$("#calculate-financing").click(function(event){ var price = (accounting.unformat($("#financing_value_vehicles").val(), ",")) || 0;

var rate = (accounting.unformat($("#tax").val(), ",") / 100) || 0;

var initialCash = (accounting.unformat($("#initial-cash").val(), ",")) || 0;

var value = (accounting.unformat($("#amount-finance").val(), ",")) || 0; var finance = price - initialCash;

var months = (accounting.unformat($("#prize_parcela").val(), ",")) || 0; var tax = parseFloat(rate);

var nominator = (Math.pow(1 + tax, months)); var denominator = ((Math.pow(1 + tax, months)) - 1);

var formattedFinance = accounting.formatMoney(finance, "", "2", ".", ","); $("amount-finance").val(formattedFinance);

var financingValue = finance*nominator*tax/denominator; var result = accounting.formatMoney(financingValue, "R$ ", "2", ".", ",");

$(".calculator_financing li.result p.value").text(result); this.button = $("#calc"); if( result != ""){ $("a.button").remove(); this.button.after("<a href='financiamento/new?vehicle_value="+price+"' class='button'>Cote Agora</a>"); };

event.preventDefault(); });

$("#initial-cash").bind("blur", function () { var price = (accounting.unformat($("#financing_value_vehicles").val(), ",")) || 0; var initialCash = (accounting.unformat($("#initial-cash").val(), ",")) || 0;

var finance = price - initialCash;

var formattedValue = accounting.formatMoney(finance, "", "2", ".", ","); $("#amount-finance").val(formattedValue); }); /** ------------ **/

/** BID CALCULATOR **/ $("input#calculate-bid").click(function(event){ var price = (accounting.unformat($("#bid-product-value").val(), ",")) || 0;

var rate = (accounting.unformat($("#bid-tax").val(), ",") / 100) || 0;

var initialCash = (accounting.unformat($("#bid-initial-cash").val(), ",")) || 0;

var value = (accounting.unformat($("#bid-amount-finance").val(), ",")) || 0; var finance = price - initialCash;

var months = (accounting.unformat($("#bid-prize_parcela").val(), ",")) || 0; var tax = parseFloat(rate);

var nominator = (Math.pow(1 + tax, months)); var denominator = ((Math.pow(1 + tax, months)) - 1);

var formattedFinance = accounting.formatMoney(finance, "", "2", ".", ","); $("#bid-amount-finance").val(formattedFinance);

var result = accounting.formatMoney(((finance*nominator*tax/denominator)), "R$ ", "2", ".", ","); $(".calculator_bid li.result p.value").text(result);

event.preventDefault(); });

$("#bid-initial-cash").bind("blur", function () { var price = (accounting.unformat($("#bid-product-value").val(), ",")) || 0; var initialCash = (accounting.unformat($("#bid-initial-cash").val(), ",")) || 0;

var finance = price - initialCash;

var formattedValue = accounting.formatMoney(finance, "", "2", ".", ","); $("#bid-amount-finance").val(formattedValue); }); /** ------------ **/

$('.state-active').each(function(i){ active_tab = $(this).attr('href') $(this).parents('section').find('div' + active_tab).addClass('tab-active') });

$('.tooltip').hide(); if ($("html").is(".lt-ie9")) { $('a').hover( function(){ $(this).siblings('.tooltip').show(); }, function(){ $(this).siblings('.tooltip').hide(); } ); } else { $('a').hover( function(){ $(this).siblings('.tooltip').fadeIn(); }, function(){ $(this).siblings('.tooltip').fadeOut(); } ); }

tab.live('click', function(event){ event.preventDefault(); link = $(this).attr('href') el = $(this).parents('.tabs')

el.find('div').removeClass('tab-active'); el.find('a').removeClass('state-active');

$(this).addClass('state-active') el.find('div' + link).addClass('tab-active');

});

$('a').unbind('click').hasClass('state-active'); $('a.state-active').unbind('click');

$("#schedule nav a").live("click", function(event){ $('#schedule nav a').removeClass('state-active') $(this).addClass('state-active') $(".window div").animate({ top: "" + ($(this).hasClass("prev") ? 0 : -210) + "px" }); event.preventDefault() });

app.advertisementNewForm(); },

advertisementNewForm: function(){ $('span.select-image').bind('click', function(){ $(this).parent('li').find('input[type="file"]').click(); });

}

}); $().ready(app.init);}).call(this);

Page 12: JavaScript Modular e Event-Driven

(um arquivo JS,uma função de 173 LOC,no mínimo 7 responsabilidades)

Page 13: JavaScript Modular e Event-Driven

Ele pode virar um CALLBACK HELL(e algumas libraries facilitam ainda mais isso)

Page 14: JavaScript Modular e Event-Driven

$(".submit-button").on("click", function () { $.ajax({ url : "/create", type : "POST", success : function (data) { $.each(data.created_items, function (index, value) { var item = $("<div />").text(value); $(".items-list").append(item).hide().fadeIn(400, function () { setTimeout(function () { item.fadeOut(function () { item.remove(); }); }, 1000); }); }); } });});

Page 15: JavaScript Modular e Event-Driven
Page 16: JavaScript Modular e Event-Driven

Uma estrutura modular e baseada em eventos resolve esses problemas e muito mais.

Page 17: JavaScript Modular e Event-Driven

DISCLAIMER #1Sem MV* frameworks

Page 18: JavaScript Modular e Event-Driven

DISCLAIMER #2jQuery (para encurtar os exemplos)

Page 19: JavaScript Modular e Event-Driven

DISCLAIMER #3Pseudo-implementações =)

Page 20: JavaScript Modular e Event-Driven

MÓDULOS

Page 21: JavaScript Modular e Event-Driven

Responsabilidade única, integrante de um sistema complexo.

Page 22: JavaScript Modular e Event-Driven
Page 23: JavaScript Modular e Event-Driven

Responsabilidades e comportamentos isolados.

Page 24: JavaScript Modular e Event-Driven
Page 25: JavaScript Modular e Event-Driven

Testáveis.

Page 26: JavaScript Modular e Event-Driven
Page 27: JavaScript Modular e Event-Driven

Extensíveis e modificáveis (até certo ponto).

Page 28: JavaScript Modular e Event-Driven
Page 29: JavaScript Modular e Event-Driven

Podem ser substituídos, ou reutilizados.

Page 30: JavaScript Modular e Event-Driven
Page 31: JavaScript Modular e Event-Driven

Nesta apresentaçãosingle entry points

namespacesmodule pattern

constructorsModule.js

mediator & pub/submixins

Page 32: JavaScript Modular e Event-Driven

Single entry points

Page 33: JavaScript Modular e Event-Driven

(function(){ window.app = jQuery.extend({ init: function(){ tab = $('.tabs li > a.tab-toggle'); tabs = $('.tabs').find('> div');

if (tabs.length > 1){ tab.each(function (i){$(this).attr('href', '#content-' + ++i)}); tabs.each(function(i){$(this).attr('id', 'content-' + ++i)}); tabs.addClass('tab-inactive'); $('.tabs li:first-child a').addClass('state-active'); }

$('#initial-cash, #financing_value_vehicles, #tax, #bid-initial-cash, #bid-product-value').maskMoney({ thousands: '.', decimal: ',', allowZero: true, allowNegative: false, defaultZero: true });

/** FINANCING CALCULATOR **/ $("#financing_value_vehicles").on("blur", function(){ var price = (accounting.unformat($(this).val(), ",")) || 0;

var suggestedInitialPayment = price * 0.2;

var formattedResult = accounting.formatMoney(suggestedInitialPayment, "", "2", ".", ","); $("#initial-cash").val(formattedResult); });

$("#calculate-financing").click(function(event){ var price = (accounting.unformat($("#financing_value_vehicles").val(), ",")) || 0;

var rate = (accounting.unformat($("#tax").val(), ",") / 100) || 0;

var initialCash = (accounting.unformat($("#initial-cash").val(), ",")) || 0;

var value = (accounting.unformat($("#amount-finance").val(), ",")) || 0; var finance = price - initialCash;

var months = (accounting.unformat($("#prize_parcela").val(), ",")) || 0; var tax = parseFloat(rate);

var nominator = (Math.pow(1 + tax, months)); var denominator = ((Math.pow(1 + tax, months)) - 1);

var formattedFinance = accounting.formatMoney(finance, "", "2", ".", ","); $("amount-finance").val(formattedFinance);

var financingValue = finance*nominator*tax/denominator; var result = accounting.formatMoney(financingValue, "R$ ", "2", ".", ",");

$(".calculator_financing li.result p.value").text(result); this.button = $("#calc"); if( result != ""){ $("a.button").remove(); this.button.after("<a href='financiamento/new?vehicle_value="+price+"' class='button'>Cote Agora</a>"); };

event.preventDefault(); });

$("#initial-cash").bind("blur", function () { var price = (accounting.unformat($("#financing_value_vehicles").val(), ",")) || 0; var initialCash = (accounting.unformat($("#initial-cash").val(), ",")) || 0;

var finance = price - initialCash;

var formattedValue = accounting.formatMoney(finance, "", "2", ".", ","); $("#amount-finance").val(formattedValue); }); /** ------------ **/

/** BID CALCULATOR **/ $("input#calculate-bid").click(function(event){ var price = (accounting.unformat($("#bid-product-value").val(), ",")) || 0;

var rate = (accounting.unformat($("#bid-tax").val(), ",") / 100) || 0;

var initialCash = (accounting.unformat($("#bid-initial-cash").val(), ",")) || 0;

var value = (accounting.unformat($("#bid-amount-finance").val(), ",")) || 0; var finance = price - initialCash;

var months = (accounting.unformat($("#bid-prize_parcela").val(), ",")) || 0; var tax = parseFloat(rate);

var nominator = (Math.pow(1 + tax, months)); var denominator = ((Math.pow(1 + tax, months)) - 1);

var formattedFinance = accounting.formatMoney(finance, "", "2", ".", ","); $("#bid-amount-finance").val(formattedFinance);

var result = accounting.formatMoney(((finance*nominator*tax/denominator)), "R$ ", "2", ".", ","); $(".calculator_bid li.result p.value").text(result);

event.preventDefault(); });

$("#bid-initial-cash").bind("blur", function () { var price = (accounting.unformat($("#bid-product-value").val(), ",")) || 0; var initialCash = (accounting.unformat($("#bid-initial-cash").val(), ",")) || 0;

var finance = price - initialCash;

var formattedValue = accounting.formatMoney(finance, "", "2", ".", ","); $("#bid-amount-finance").val(formattedValue); }); /** ------------ **/

$('.state-active').each(function(i){ active_tab = $(this).attr('href') $(this).parents('section').find('div' + active_tab).addClass('tab-active') });

$('.tooltip').hide(); if ($("html").is(".lt-ie9")) { $('a').hover( function(){ $(this).siblings('.tooltip').show(); }, function(){ $(this).siblings('.tooltip').hide(); } ); } else { $('a').hover( function(){ $(this).siblings('.tooltip').fadeIn(); }, function(){ $(this).siblings('.tooltip').fadeOut(); } ); }

tab.live('click', function(event){ event.preventDefault(); link = $(this).attr('href') el = $(this).parents('.tabs')

el.find('div').removeClass('tab-active'); el.find('a').removeClass('state-active');

$(this).addClass('state-active') el.find('div' + link).addClass('tab-active');

});

$('a').unbind('click').hasClass('state-active'); $('a.state-active').unbind('click');

$("#schedule nav a").live("click", function(event){ $('#schedule nav a').removeClass('state-active') $(this).addClass('state-active') $(".window div").animate({ top: "" + ($(this).hasClass("prev") ? 0 : -210) + "px" }); event.preventDefault() });

app.advertisementNewForm(); },

advertisementNewForm: function(){ $('span.select-image').bind('click', function(){ $(this).parent('li').find('input[type="file"]').click(); });

}

}); $().ready(app.init);}).call(this);

Page 34: JavaScript Modular e Event-Driven

Page load

jQuery load

jQuery plugins

application.js

Page 35: JavaScript Modular e Event-Driven

Sem pontos de entrada, é difícil segmentar a execução por página ou rota.

Page 36: JavaScript Modular e Event-Driven

Pontos únicos de entrada controlam o flow da aplicação.

Page 37: JavaScript Modular e Event-Driven

Page load

Vendor code

Application modules

application.js

dispatcher.js

beforeCommand controllerCommand actionCommand afterCommand

Page 38: JavaScript Modular e Event-Driven

Page load

Vendor code

Application modules

application.js

dispatcher.js

beforeCommand controllerCommand actionCommand afterCommand

Page 39: JavaScript Modular e Event-Driven

O dispatcher executa funções baseadas no controller e na action da página.

Page 40: JavaScript Modular e Event-Driven

<body data-dispatcher="<%= dispatcher_label %>">

Page 41: JavaScript Modular e Event-Driven

def dispatcher_label action_name = controller.action_name action_name.gsub!(/_/, "")

"#{controller_name}##{action_name}"end

Page 42: JavaScript Modular e Event-Driven

<body data-dispatcher="products#show">

Page 43: JavaScript Modular e Event-Driven

dispatcher.js

beforeCommand()

productsControllerCommand()

productsShowCommand()

afterCommand()

products#show

Page 44: JavaScript Modular e Event-Driven

Os commands não contêm lógica, apenas inicializam outros módulos.

Page 45: JavaScript Modular e Event-Driven

Namespaces

Page 46: JavaScript Modular e Event-Driven

ns("MYAPP.commands.productsShowCommand", function () { console.log("Execute code from products#show page");});

// Same as:

window.MYAPP = { commands : { productsShowCommand : function () { console.log("Execute code from products#show page"); } }};

Page 47: JavaScript Modular e Event-Driven

Ajuda na organização dos módulos.

Page 48: JavaScript Modular e Event-Driven

/javascripts /myapp /commands /productsShowCommand.js

Page 49: JavaScript Modular e Event-Driven

Não polui o contexto global.

Page 50: JavaScript Modular e Event-Driven

Module pattern

Page 51: JavaScript Modular e Event-Driven

ns("EDEN.modules.checkoutModule", (function () {

// Stores the module's main element var element;

// Private methods // ---------------

// Prints a silly phrase var printSillyPhrase = function () { console.log("I love sushi"); console.log(this); };

return {

// Public methods // --------------

// Inits the module init : function (el) { element = $(el);

printSillyPhrase.call(this); }

};})());

Page 52: JavaScript Modular e Event-Driven

Isola um comportamento e disponibiliza uma API pública.

Page 53: JavaScript Modular e Event-Driven

É "Singleton-like".

Page 54: JavaScript Modular e Event-Driven

Constructors & Prototypes

Page 55: JavaScript Modular e Event-Driven

ns("EDEN.forms.AddressForm", function (el) { this.element = $(el); this.init();});

$.extend(EDEN.forms.AddressForm.prototype, {

// Public methods // --------------

// Inits the instance init : function () { // Do something }

});

var shippingAddressForm = new EDEN.forms.AddressForm($("#shipping-address"));

Page 56: JavaScript Modular e Event-Driven

Permite múltiplas instâncias e heranças por prototype.

Page 57: JavaScript Modular e Event-Driven

Module.js

Page 58: JavaScript Modular e Event-Driven

* github.com/fnando/module

Page 59: JavaScript Modular e Event-Driven

Define namespaces e coloca açúcar sintático na definição de funções construtoras.

Page 60: JavaScript Modular e Event-Driven

ns("EDEN.forms.AddressForm", function (el) { this.element = $(el); this.init();});

$.extend(EDEN.forms.AddressForm.prototype, {

// Public methods // --------------

// Inits the instance init : function () { // Do something }

});

var shippingAddressForm = new EDEN.forms.AddressForm($("#shipping-address"));

Page 61: JavaScript Modular e Event-Driven

Module("EDEN.forms.AddressForm", function (AddressForm) {

AddressForm.fn.initialize = function (el) { this.element = $(el);

// Do something }

});

var shippingAddressForm = Module.run("EDEN.forms.AddressForm", $("#shipping-address"));

Page 62: JavaScript Modular e Event-Driven

Padroniza a criação de novos módulos.

Page 63: JavaScript Modular e Event-Driven

EVENTOS

Page 64: JavaScript Modular e Event-Driven

Pub/Sub

Page 65: JavaScript Modular e Event-Driven
Page 66: JavaScript Modular e Event-Driven

PUB (server)"Quando sair o torrent do último episódio, vou avisar pra galera."

Page 67: JavaScript Modular e Event-Driven

SUB (cliente piratinha)"Quando o server avisar que tem um episódio, vou começar a baixar."

Page 68: JavaScript Modular e Event-Driven

SUB PUB

Page 69: JavaScript Modular e Event-Driven

Yo, me avisa quando sair o eppy de Game of

Thrones? \o/

Blz é nóish véi

Page 70: JavaScript Modular e Event-Driven

AE SAIU O"THE RAINS OF

CASTAMERE" PRA BAIXAR, GALERE!

Massa, vou baixar!Acho que vai ser um

episódio feliz =D

Page 71: JavaScript Modular e Event-Driven

// Pirate subscribes to torrent servertorrentServer.on("new-got-episode", function (name) { this.download(name);});

// Torrent server publishes that it has a new GoT episodethis.trigger("new-got-episode", "The Rains of Castamere");

Page 72: JavaScript Modular e Event-Driven

Mediator

Page 73: JavaScript Modular e Event-Driven

Interface central de comunicação entre módulos.

Page 74: JavaScript Modular e Event-Driven

MEDIATOR

Page 75: JavaScript Modular e Event-Driven

Nenhum módulo tem conhecimento do outro.

Page 76: JavaScript Modular e Event-Driven

MEDIATOR

Mediator, me avisa quando sair o novo do The

Walking Dead?

Blz

Page 77: JavaScript Modular e Event-Driven

MEDIATOR

Mediator, me avisa quando sair o novo do

Mythbusters?

É nóish.

Page 78: JavaScript Modular e Event-Driven

MEDIATOR

Mediator, saiu um eppy novo de The Walking

Dead.

Subscribers, saiu um eppy novo de The

Walking Dead!

Ae, vou baixar!

Page 79: JavaScript Modular e Event-Driven

MEDIATOR

Mediator, saiu um eppy novo de Mythbusters.

Subscribers, saiu um eppy novo de Mythbusters!

Ae, vou baixar!

Page 80: JavaScript Modular e Event-Driven

// Pirate 1 subscribes to mediatormediator.on("new-twd-episode", function (name) { console.log("Downloading The Walking Dead - " + name);});

// Pirate 2 subscribes to mediatormediator.on("new-mythbusters-episode", function (name) { console.log("Downloading Mythbusters - " + name);});

// Torrent server 1 publishes on mediatormediator.trigger("new-twd-episode", "The Suicide King");

// Torrent server 2 publishes on mediatormediator.trigger("new-mythbusters-episode", "Food Fables");

Page 81: JavaScript Modular e Event-Driven

Todos conhecem apenas o Mediator.

Page 82: JavaScript Modular e Event-Driven

Mixin

Page 83: JavaScript Modular e Event-Driven

Module("EDEN.forms.AddressForm", function (AddressForm) {

// AddressForm now has the `on`, `off` and `trigger` methods $.extend(AddressForm.fn, EDEN.events);

AddressForm.fn.initialize = function (el) { this.element = $(el); }

});

Page 84: JavaScript Modular e Event-Driven

MUNDO REAL

Page 85: JavaScript Modular e Event-Driven
Page 86: JavaScript Modular e Event-Driven
Page 87: JavaScript Modular e Event-Driven
Page 88: JavaScript Modular e Event-Driven
Page 89: JavaScript Modular e Event-Driven
Page 90: JavaScript Modular e Event-Driven
Page 91: JavaScript Modular e Event-Driven
Page 92: JavaScript Modular e Event-Driven

Modularizando

Page 93: JavaScript Modular e Event-Driven
Page 94: JavaScript Modular e Event-Driven
Page 95: JavaScript Modular e Event-Driven
Page 96: JavaScript Modular e Event-Driven
Page 97: JavaScript Modular e Event-Driven
Page 98: JavaScript Modular e Event-Driven

Exemplos

Page 99: JavaScript Modular e Event-Driven

#1Mudança no endereço de entrega muda o endereço de cobrança

Page 100: JavaScript Modular e Event-Driven
Page 101: JavaScript Modular e Event-Driven
Page 102: JavaScript Modular e Event-Driven
Page 103: JavaScript Modular e Event-Driven

// Code inside ShippingAddressForm

_attachEvents : function () { this.element.find(".main-address-input").on("keyup paste cut change", this._onAddressModification.bind(this)); },

_onAddressModification : function (event) { EDEN.mediator.trigger("shipping-address-change", event.target.value);}

Page 104: JavaScript Modular e Event-Driven
Page 105: JavaScript Modular e Event-Driven

// Code inside BillingAddressSelector

_registerInterests : function () { EDEN.mediator.on("shipping-address-change", this.updateAddressInfo, this);}

updateAddressInfo : function (address) { this.element.find(".address-info").text(address);}

Page 106: JavaScript Modular e Event-Driven

#2Mudança no CEP de entrega muda frete, total e parcelas

Page 107: JavaScript Modular e Event-Driven
Page 108: JavaScript Modular e Event-Driven
Page 109: JavaScript Modular e Event-Driven
Page 110: JavaScript Modular e Event-Driven
Page 111: JavaScript Modular e Event-Driven
Page 112: JavaScript Modular e Event-Driven

// Code inside ShippingAddressForm

_registerInterests : function () { this.element.find(".cep-input").on("keyup paste cut", this._onCepModification.bind(this)); },

_onCepModification : function (event) { if (this.isCepFilled()) { EDEN.mediator.trigger("shipping-cep-change", event.target.value); } else { EDEN.mediator.trigger("shipping-cep-incomplete", event.target.value); }}

Page 113: JavaScript Modular e Event-Driven
Page 114: JavaScript Modular e Event-Driven

// Code inside checkoutModule

_registerIntests : function () { EDEN.mediator.on("shipping-cep-change", this._onShippingCepChange, this); this.shippingService.on("get-success", this._onShippingGetSuccess, this);},

_onShippingCepChange : function (cep) { this.shippingService.get(cep);}

_onShippingGetSuccess : function (data) { EDEN.mediator.trigger("shipping-rate-change", data.rate); EDEN.mediator.trigger("delivery-estimate-change", data.estimate);}

Page 115: JavaScript Modular e Event-Driven
Page 116: JavaScript Modular e Event-Driven

// Code inside purchaseInfo

_registerInterests : function () { EDEN.mediator.on("shipping-rate-change", this._onShippingRateChange, this); EDEN.mediator.on("delivery-estimate-change", this._onDeliveryEstimateChange, this);},

_onShippingRateChange : function (rate) { this.updateShippingRate(rate);},

_onDeliveryEstimateChange : function (days) { this.updateDeliveryEstimate(days);},

updateShippingRate : function (rate) { var formatter = EDEN.currency.formatter;

this.element.find(".shipping-rate").text(formatter(rate)); this.shippingRate = rate;

this.updateTotal();},

updateTotal : function () { var total = this.subtotal + this.shippingRate, formatter = EDEN.currency.formatter;

this.element.find(".total").text(formatter(total));

EDEN.mediator.trigger("cart-total-change", total);}

Page 117: JavaScript Modular e Event-Driven
Page 118: JavaScript Modular e Event-Driven

// Code inside installmentSelector

_registerInterests : function () { EDEN.mediator.on("cart-total-change", this._onCartTotalChange, this);},

_onCartTotalChange : function (total) { this.updateInstallments(total);},

updateInstallments : function (total) { // Updates the values}

Page 119: JavaScript Modular e Event-Driven

LIVE DEMO

Page 120: JavaScript Modular e Event-Driven

futuro.

Page 121: JavaScript Modular e Event-Driven

Sempre há espaço para melhoras.

Page 122: JavaScript Modular e Event-Driven

Framework MV*?

Page 123: JavaScript Modular e Event-Driven

Framework próprio?

Page 124: JavaScript Modular e Event-Driven

Melhoria nas padronizações?

Page 125: JavaScript Modular e Event-Driven

Sistema de eventos mais robusto?

Page 126: JavaScript Modular e Event-Driven

É por isso que JavaScript é legal. =)

Page 127: JavaScript Modular e Event-Driven
Page 128: JavaScript Modular e Event-Driven

THANKSslideshare.net/eshiota

github.com/eshiota@shiota