Skip to content

Commit

Permalink
Refactoring AngularJS Shop Variant filtering logic for improved speed
Browse files Browse the repository at this point in the history
  • Loading branch information
oeoeaio committed Aug 10, 2016
1 parent f9b58b7 commit 47df8d6
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 131 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,2 @@
Darkswarm.controller "CartCtrl", ($scope, Cart, $timeout) ->
$scope.Cart = Cart
initializing = true

$scope.$watchCollection "Cart.line_items_present()", ->
if initializing
$timeout ->
initializing = false
else
$scope.Cart.orderChanged()

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,35 @@ Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, Ord
$scope.filtersActive = true
$scope.limit = 10
$scope.order_cycle = OrderCycle.order_cycle
# $scope.infiniteDisabled = true

# All of this logic basically just replicates the functionality filtering an ng-repeat
# except that it allows us to filter a separate list before rendering, meaning that
# we can get much better performance when applying filters by resetting the limit on the
# number of products being rendered each time a filter is changed.

$scope.$watch "Products.loading", (newValue, oldValue) ->
$scope.updateFilteredProducts()
$scope.$broadcast("loadFilterSelectors") if !newValue

$scope.incrementLimit = ->
$scope.limit += 10 if $scope.limit < Products.products.length
if $scope.limit < Products.products.length
$scope.limit += 10
$scope.updateVisibleProducts()

$scope.$watch 'query', -> $scope.updateFilteredProducts()
$scope.$watchCollection 'activeTaxons', -> $scope.updateFilteredProducts()
$scope.$watchCollection 'activeProperties', -> $scope.updateFilteredProducts()

$scope.$watchGroup ['query','taxonSelectors','propertySelectors'], ->
$scope.updateFilteredProducts = ->
$scope.limit = 10
f1 = $filter('products')(Products.products, $scope.query)
f2 = $filter('taxons')(f1, $scope.activeTaxons)
$scope.filteredProducts = $filter('properties')(f2, $scope.activeProperties)
$scope.updateVisibleProducts()

$scope.updateVisibleProducts = ->
$scope.visibleProducts = $filter('limitTo')($scope.filteredProducts, $scope.limit)

$scope.searchKeypress = (e)->
code = e.keyCode || e.which
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Darkswarm.directive "shopVariant", ->
Darkswarm.directive "shopVariant", ->
restrict: 'E'
replace: true
templateUrl: 'shop_variant.html'
scope:
variant: '='
controller: ($scope, Cart) ->
$scope.$watchGroup ['variant.line_item.quantity', 'variant.line_item.max_quantity'], ->
Cart.adjust($scope.variant.line_item)
46 changes: 15 additions & 31 deletions app/assets/javascripts/darkswarm/services/cart.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
for line_item in @line_items
line_item.variant.line_item = line_item
Variants.register line_item.variant
line_item.variant.extended_name = @extendedVariantName(line_item.variant)

adjust: (line_item) =>
line_item.total_price = line_item.variant.price_with_fees * line_item.quantity
if line_item.quantity > 0
@line_items.push line_item unless line_item in @line_items
else
index = @line_items.indexOf(line_item)
@line_items.splice(index, 1) if index >= 0
@orderChanged()

orderChanged: =>
@unsaved()
Expand Down Expand Up @@ -48,7 +56,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
# TODO: These changes to quantity/max_quantity trigger another cart update, which
# is unnecessary.

for li in @line_items_present()
for li in @line_items when li.quantity > 0
if stockLevels[li.variant.id]?
li.variant.count_on_hand = stockLevels[li.variant.id].on_hand
if li.quantity > li.variant.count_on_hand
Expand All @@ -67,7 +75,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo

data: =>
variants = {}
for li in @line_items_present()
for li in @line_items when li.quantity > 0
variants[li.variant.id] =
quantity: li.quantity
max_quantity: li.max_quantity
Expand All @@ -89,45 +97,21 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
$(window).bind "beforeunload", ->
t 'order_not_saved_yet'

line_items_present: =>
@line_items.filter (li)->
li.quantity > 0

total_item_count: =>
@line_items_present().reduce (sum,li) ->
@line_items.reduce (sum,li) ->
sum = sum + li.quantity
, 0

empty: =>
@line_items_present().length == 0
@line_items.length == 0

total: =>
@line_items_present().map (li)->
li.variant.totalPrice()
@line_items.map (li)->
li.total_price
.reduce (t, price)->
t + price
, 0

register_variant: (variant)=>
exists = @line_items.some (li)-> li.variant == variant
@create_line_item(variant) unless exists

clear: ->
@line_items = []
storage.clearAll() # One day this will have to be moar GRANULAR

create_line_item: (variant)->
variant.extended_name = @extendedVariantName(variant)
variant.line_item =
variant: variant
quantity: null
max_quantity: null
@line_items.push variant.line_item

extendedVariantName: (variant) =>
if variant.product_name == variant.name_to_display
variant.product_name
else
name = "#{variant.product_name} - #{variant.name_to_display}"
name += " (#{variant.options_text})" if variant.options_text
name
17 changes: 4 additions & 13 deletions app/assets/javascripts/darkswarm/services/products.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
@extend()
@dereference()
@registerVariants()
@registerVariantsWithCart()
@loading = false

extend: ->
Expand All @@ -44,15 +43,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
registerVariants: ->
for product in @products
if product.variants
product.variants = (Variants.register variant for variant in product.variants)
variant.product = product for variant in product.variants
if product.master
product.master.product = product
product.master = Variants.register product.master

registerVariantsWithCart: ->
for product in @products
if product.variants
for variant in product.variants
Cart.register_variant variant
Cart.register_variant product.master if product.master
product.variants = for variant in product.variants
variant = Variants.register variant
variant.product = product
variant
21 changes: 17 additions & 4 deletions app/assets/javascripts/darkswarm/services/variants.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@ Darkswarm.factory 'Variants', ->
@variants[variant.id] ||= @extend variant

extend: (variant)->
# Add totalPrice method to calculate line item total. This should be on a line item!
variant.totalPrice = ->
variant.price_with_fees * variant.line_item.quantity
variant.basePricePercentage = Math.round(variant.price / variant.price_with_fees * 100)
variant.extended_name = @extendedVariantName(variant)
variant.base_price_percentage = Math.round(variant.price / variant.price_with_fees * 100)
variant.line_item ||= @lineItemFor(variant) # line_item may have been initialised in Cart#constructor
variant.line_item.total_price = variant.price_with_fees * variant.line_item.quantity
variant

extendedVariantName: (variant) =>
if variant.product_name == variant.name_to_display
variant.product_name
else
name = "#{variant.product_name} - #{variant.name_to_display}"
name += " (#{variant.options_text})" if variant.options_text
name

lineItemFor: (variant) ->
variant: variant
quantity: null
max_quantity: null
16 changes: 8 additions & 8 deletions app/assets/javascripts/templates/price_breakdown.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,34 @@
%span.joyride-nub.right
.joyride-content-wrapper
.collapsed{"ng-show" => "!expanded"}
%price-percentage{percentage: 'variant.basePricePercentage'}
%price-percentage{percentage: 'variant.base_price_percentage'}
%a{"ng-click" => "expanded = !expanded"}
%span{"ng-bind" => "::'price_breakdown' | t"}
%i.ofn-i_005-caret-down
.expanded{"ng-show" => "expanded"}
%ul
%li.cost
.right {{ variant.price | localizeCurrency }}
.right {{ ::variant.price | localizeCurrency }}
%span{"ng-bind" => "::'item_cost' | t"}
%li.admin-fee{"ng-if" => "::variant.fees.admin"}
.right {{ variant.fees.admin | localizeCurrency }}
.right {{ ::variant.fees.admin | localizeCurrency }}
%span{"ng-bind" => "::'admin_fee' | t"}
%li.sales-fee{"ng-if" => "::variant.fees.sales"}
.right {{ variant.fees.sales | localizeCurrency }}
.right {{ ::variant.fees.sales | localizeCurrency }}
%span{"ng-bind" => "::'sales_fee' | t"}
%li.packing-fee{"ng-if" => "::variant.fees.packing"}
.right {{ variant.fees.packing | localizeCurrency }}
.right {{ ::variant.fees.packing | localizeCurrency }}
%span{"ng-bind" => "::'packing_fee' | t"}
%li.transport-fee{"ng-if" => "::variant.fees.transport"}
.right {{ variant.fees.transport | localizeCurrency }}
.right {{ ::variant.fees.transport | localizeCurrency }}
%span{"ng-bind" => "::'transport_fee' | t"}
%li.fundraising-fee{"ng-if" => "::variant.fees.fundraising"}
.right {{ variant.fees.fundraising | localizeCurrency }}
.right {{ ::variant.fees.fundraising | localizeCurrency }}
%span{"ng-bind" => "::'fundraising_fee' | t"}
%li.total
%strong
.right = {{ variant.price_with_fees | localizeCurrency }}
.right = {{ ::variant.price_with_fees | localizeCurrency }}
&nbsp;
%a{"ng-click" => "expanded = !expanded"}
Expand Down
5 changes: 2 additions & 3 deletions app/assets/javascripts/templates/price_percentage.html.haml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.progress
.right {{'fees' | t}}
.right {{::'fees' | t}}
.meter
{{'item_cost' | t}}

{{::'item_cost' | t}}
4 changes: 2 additions & 2 deletions app/assets/javascripts/templates/shop_variant.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
.small-12.medium-2.large-2.columns.total-price.text-right
.table-cell
%strong{"ng-class" => "{filled: variant.totalPrice()}"}
{{ variant.totalPrice() | localizeCurrency }}
%strong{"ng-class" => "{filled: variant.line_item.total_price}"}
{{ variant.line_item.total_price | localizeCurrency }}
7 changes: 3 additions & 4 deletions app/views/shared/menu/_cart.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
= t 'checkout'
%table
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_present()",
"ng-controller" => "LineItemCtrl", "id" => "cart-variant-{{ line_item.variant.id }}"}
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"}
%td
%small
%strong
Expand All @@ -33,9 +32,9 @@
%small
\=
%strong
.total-price.right {{ line_item.variant.totalPrice() | localizeCurrency }}
.total-price.right {{ line_item.total_price | localizeCurrency }}
%table{"ng-show" => "Cart.line_items_present().length > 0"}
%table{"ng-show" => "Cart.line_items.length > 0"}
%tr.total-cart
%td
%em
Expand Down
12 changes: 9 additions & 3 deletions app/views/shop/products/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@
.small-12.medium-6.large-6.large-offset-1.columns
= render partial: "shop/products/filters"
%div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "inifinite-scroll-disabled" => '{{filteredProducts.length <= limit}}' }
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) | limitTo:limit track by product.id ", "id" => "product-{{ product.id }}"}
%div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'filteredProducts.length <= limit' }
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in visibleProducts track by product.id", "id" => "product-{{ product.id }}"}
= render "shop/products/summary"
-# %shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"}
%shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.count_on_hand == 0}"}
-# Load more button, which can be used to initiate infinite scrolling.
-# %product{ "ng-hide" => "Products.loading || !infiniteDisabled || limit >= filteredProducts.length" }
-# .row.summary
-# .small-12.columns.text-center
-# %a.button{ ng: { click: 'infiniteDisabled = false; incrementLimit();' } }
-# Load More Products
%product{"ng-show" => "Products.loading"}
.row.summary
.small-12.columns.text-center
Expand Down
Loading

0 comments on commit 47df8d6

Please sign in to comment.