Slide 1

Slide 1 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Here’s something we do all the time…

Slide 2

Slide 2 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App Useful Library or API

Slide 3

Slide 3 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App Useful Library or API Not a core task Not our code Abstract semantics

Slide 4

Slide 4 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Bad. My Amazing App Useful Library or API

Slide 5

Slide 5 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Hard to update My Amazing App Useful Library or API

Slide 6

Slide 6 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Duplication My Amazing App Useful Library or API

Slide 7

Slide 7 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd API Semantics My Amazing App Useful Library or API

Slide 8

Slide 8 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App Useful Library or API Wrapper

Slide 9

Slide 9 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Better. My Amazing App Useful Library or API Wrapper

Slide 10

Slide 10 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Updateable My Amazing App Useful Library or API Wrapper

Slide 11

Slide 11 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Abstractable My Amazing App Useful Library or API Wrapper

Slide 12

Slide 12 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd App semantics My Amazing App Useful Library or API Wrapper

Slide 13

Slide 13 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App Useful Library or API

Slide 14

Slide 14 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM

Slide 15

Slide 15 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM Wrapper

Slide 16

Slide 16 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd The DOM is not your application Noel Rappin / Table XI @noelrap /noelrappin.com CODEMASH_36

Slide 17

Slide 17 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM Wrapper

Slide 18

Slide 18 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM jQuery?

Slide 19

Slide 19 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM jQuery? Wrapper

Slide 20

Slide 20 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM Backbone? Ember? Angular?

Slide 21

Slide 21 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Category Item Banana Fruit

Slide 22

Slide 22 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd @initListInForm = -> window.items = {} $("#item_list option").each (index, option) -> $option = $(option) unless window.items[$option.data("category")] window.items[$option.data("category")] = [] if $option.data("category") window.items[$option.data("category")].push(option) $("#item_list option").remove() $("#order_category_id").change -> $("#item_list option").remove() category_id = $(this).val() _.each window.items[category_id], (option) -> $("#item_list").append($(option))

Slide 23

Slide 23 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd @initListInForm = -> window.items = {} $("#item_list option").each (index, option) -> $option = $(option) unless window.items[$option.data("category")] window.items[$option.data("category")] = [] if $option.data("category") window.items[$option.data("category")].push(option) $("#item_list option").remove() $("#order_category_id").change -> $("#item_list option").remove() category_id = $(this).val() _.each window.items[category_id], (option) -> $("#item_list").append($(option)) Reading initial values

Slide 24

Slide 24 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd @initListInForm = -> window.items = {} $("#item_list option").each (index, option) -> $option = $(option) unless window.items[$option.data("category")] window.items[$option.data("category")] = [] if $option.data("category") window.items[$option.data("category")].push(option) $("#item_list option").remove() $("#order_category_id").change -> $("#item_list option").remove() category_id = $(this).val() _.each window.items[category_id], (option) -> $("#item_list").append($(option)) Clearing select

Slide 25

Slide 25 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd @initListInForm = -> window.items = {} $("#item_list option").each (index, option) -> $option = $(option) unless window.items[$option.data("category")] window.items[$option.data("category")] = [] if $option.data("category") window.items[$option.data("category")].push(option) $("#item_list option").remove() $("#order_category_id").change -> $("#item_list option").remove() category_id = $(this).val() _.each window.items[category_id], (option) -> $("#item_list").append($(option)) Event handler

Slide 26

Slide 26 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd @initListInForm = -> window.items = {} $("#item_list option").each (index, option) -> $option = $(option) unless window.items[$option.data("category")] window.items[$option.data("category")] = [] if $option.data("category") window.items[$option.data("category")].push(option) $("#item_list option").remove() $("#order_category_id").change -> $("#item_list option").remove() category_id = $(this).val() _.each window.items[category_id], (option) -> $("#item_list").append($(option)) Access Query Change

Slide 27

Slide 27 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd describe "item List Form", -> describe "with category and item list", -> ! beforeEach -> affix("select#order_category_id") $("#order_category_id").append($("").val("0")) $("#order_category_id").append($("").val("1")) $("#order_category_id").append($("").val("2")) $("#order_category_id").val("0") affix("select#item_list") $("#item_list").append($("").data("category", "1").val(1)) $("#item_list").append($("").data("category", "1").val(2)) $("#item_list").append($("").data("category", "2").val(3)) initListInForm()

Slide 28

Slide 28 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd it "extracts items from the initial page load", -> expect(_.pluck(window.items[1], 'value')).toEqual(["1", "2"]) expect(_.pluck(window.items[2], 'value')).toEqual(["3"]) it "removes the original options after extracting", -> expect($("#item_list option").length).toEqual(0) it "adds the proper items on change", -> $("#order_category_id").val("1") $("#order_category_id").change() expect(_.pluck($("#item_list option"), 'value')).toEqual(["1", "2"])

Slide 29

Slide 29 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd

Slide 30

Slide 30 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Extract to class

Slide 31

Slide 31 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd class @DualSelect constructor: -> @items = {} ! initialize: -> this.extractItems() this.setChangeHandler() this.updateItemList() this Extract to class

Slide 32

Slide 32 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd ! extractItems: -> $("#item_list option").each (index, option) => this.additemOptionToList(option) ! addItemOptionToList: (option) -> categoryId = $(option).data("category") @items[categoryId] = [] unless @items[categoryId] @items[categoryId].push(option) if categoryId ! clearItemList: -> $("#item_list option").remove() ! Access Query Change Extract to class

Slide 33

Slide 33 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd setChangeHandler: -> $("#order_category_id").change (event) => this.updateItemList() ! updateItemList: -> this.clearItemList() category_id = $("#order_category_id").val() _.each @items[category_id], (option) => $("#item_list").append($(option)) Access Query Change Extract to class

Slide 34

Slide 34 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Create Access Methods

Slide 35

Slide 35 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd itemList: -> $("#item_list") ! itemListOptions: -> $("#item_list option") ! categoryList: -> $("#order_category_id") Access Query Change Create DOM Methods

Slide 36

Slide 36 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd extractItems: -> this.itemListOptions().each (index, option) => this.additemOptionToList(option) ! addItemOptionToList: (option) -> categoryId = $(option).data("category") @items[categoryId] = [] unless @items[categoryId] @items[categoryId].push(option) if categoryId ! clearItemList: -> this.itemListOptions().remove() Access Query Change Create DOM Methods

Slide 37

Slide 37 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd setChangeHandler: -> this.categoryList().change (event) => this.updateItemList() ! updateItemList: -> this.clearItemList() category_id = this.categoryList().val() _.each @items[category_id], (option) => this.itemList().append($(option)) Access Query Change Create DOM Methods

Slide 38

Slide 38 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Extract DOM Class

Slide 39

Slide 39 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd class @DualSelectDom itemList: -> $("#item_list") ! itemListOptions: -> $("#item_list option") ! categoryList: -> $("#order_category_id") class @DualSelect constructor: -> @items = {} @dom = new DualSelectDom Access Query Change Extract DOM Class

Slide 40

Slide 40 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd extractItems: -> @dom.itemListOptions().each (index, option) => this.additemOptionToList(option) ! addItemOptionToList: (option) -> categoryId = $(option).data("category") @items[categoryId] = [] unless @items[categoryId] @items[categoryId].push(option) if categoryId Access Query Change Extract DOM Class

Slide 41

Slide 41 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd clearItemList: -> @dom.itemListOptions().remove() ! setChangeHandler: -> @dom.categoryList().change (event) => this.updateItemList() ! updateItemList: -> this.clearItemList() category_id = @dom.categoryList().val() _.each @items[category_id], (option) => @dom.itemList().append($(option)) Access Query Change Extract DOM Class

Slide 42

Slide 42 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Move Queries

Slide 43

Slide 43 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd class @DualSelectDom itemList: -> $("#item_list") itemListOptions: -> $("#item_list option") ! itemListData: -> this.itemListOptions().map (index, option) -> {category: $(option).data("category"), value: $(option).val()} ! Access Query Change Move Queries

Slide 44

Slide 44 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd ! categoryList: -> $("#order_category_id") ! categoryValue: -> this.categoryList().val() ! clearItemList: -> this.itemListOptions().remove() ! appendToItemList: (value) -> this.itemList().append($("").val(value)) Access Query Change Move Queries

Slide 45

Slide 45 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd extractItems: -> @dom.itemListData().each (index, data) => this.addItemOptionToList(data) ! addItemOptionToList: (data) -> categoryId = data.category @items[categoryId] = [] unless @items[categoryId] @items[categoryId].push(data.value) if categoryId ! Access Query Change Move Queries

Slide 46

Slide 46 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd setChangeHandler: -> @dom.categoryList().change (event) => this.updateItemList() ! updateItemList: -> @dom.clearItemList() _.each @items[@dom.categoryValue()], (value) => @dom.appendToItemList(value) Access Query Change Move Queries

Slide 47

Slide 47 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Stub for Tests

Slide 48

Slide 48 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd describe "item List Form", -> describe "with category and item list", -> beforeEach -> @result = new DualSelect() @result.dom = new TestDom() @result.initialize() ! it "extracts items from the initial page load", -> expect(@result.items[1]).toEqual(["1", "2"]) expect(@result.items[2]).toEqual(["3"]) Stub For Tests

Slide 49

Slide 49 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd ! ! it "removes the original options after extracting", -> expect($("#item_list option").length).toEqual(0) ! it "adds the proper items on change", -> @result.dom.categoryList().val("1") @result.dom.categoryList().change() expect(_.pluck(@result.dom.itemList().children(), 'value')).toEqual(["1", "2"]) Stub For Tests

Slide 50

Slide 50 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd class TestDom itemListData: -> [{category: 1, data: 1}, {category: 1, data: 2}, {category: 2, data: 3}] ! categoryList: -> change: -> value: 1 ! categoryValue: -> this.categoryList().value ! clearItemList: -> ! appendToItemList: (value) -> Stub For Tests

Slide 51

Slide 51 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Widget jQuery and the DOM Wrapper

Slide 52

Slide 52 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Amazing App DOM Backbone? Ember? Angular?

Slide 53

Slide 53 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Frameworks allow separation

Slide 54

Slide 54 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Frameworks don’t enforce it

Slide 55

Slide 55 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd My Widget jQuery and the DOM Wrapper

Slide 56

Slide 56 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd The DOM is an API

Slide 57

Slide 57 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Isolate it from your code

Slide 58

Slide 58 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd You can do this in stages

Slide 59

Slide 59 text

http://www.tablexi.com ⦿ http://www.noelrappin.com/mstwjs ⦿ http://www.noelrappin.com/trdd Isolation will make code more readable

Slide 60

Slide 60 text

http://www.noelrappin.com/mstwjs http://www.noelrappin.com/trdd @noelrap CODEMASH_36 http://www.tablexi.com @tablexi