Adding infinite-scroll to the shopfront

For performance improvement with large data sets
This commit is contained in:
Rob Harrington
2016-08-03 12:45:45 +10:00
parent d40733d447
commit b957555c82
9 changed files with 28 additions and 24 deletions

View File

@@ -1,18 +1,21 @@
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
$scope.Products = Products
$scope.Cart = Cart
$scope.query = ""
$scope.taxonSelectors = FilterSelectorsService.createSelectors()
$scope.propertySelectors = FilterSelectorsService.createSelectors()
$scope.filtersActive = true
$scope.limit = 3
$scope.limit = 10
$scope.order_cycle = OrderCycle.order_cycle
$scope.$watch "Products.loading", (newValue, oldValue) ->
$scope.$broadcast("loadFilterSelectors") if !newValue
$scope.incrementLimit = ->
if $scope.limit < Products.products.length
$scope.limit = $scope.limit + 1
$scope.limit += 10 if $scope.limit < Products.products.length
$scope.$watchGroup ['query','taxonSelectors','propertySelectors'], ->
$scope.limit = 10
$scope.searchKeypress = (e)->
code = e.keyCode || e.which

View File

@@ -2,6 +2,7 @@ Darkswarm.filter 'products', (Matcher) ->
(products, text) ->
products ||= []
text ?= ""
return products if text == ""
products.filter (product) =>
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
Matcher.match propertiesToMatch, text

View File

@@ -1,2 +1,2 @@
/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */
var mod;mod=angular.module("infinite-scroll",[]),mod.directive("infiniteScroll",["$rootScope","$window","$timeout",function(i,n,e){return{link:function(t,l,o){var r,c,f,a;return n=angular.element(n),f=0,null!=o.infiniteScrollDistance&&t.$watch(o.infiniteScrollDistance,function(i){return f=parseInt(i,10)}),a=!0,r=!1,null!=o.infiniteScrollDisabled&&t.$watch(o.infiniteScrollDisabled,function(i){return a=!i,a&&r?(r=!1,c()):void 0}),c=function(){var e,c,u,d;return d=n.height()+n.scrollTop(),e=l.offset().top+l.height(),c=e-d,u=n.height()*f>=c,u&&a?i.$$phase?t.$eval(o.infiniteScroll):t.$apply(o.infiniteScroll):u?r=!0:void 0},n.on("scroll",c),t.$on("$destroy",function(){return n.off("scroll",c)}),e(function(){return o.infiniteScrollImmediateCheck?t.$eval(o.infiniteScrollImmediateCheck)?c():void 0:c()},0)}}}]);
/* ng-infinite-scroll - v1.3.0 - 2016-06-30 */
angular.module("infinite-scroll",[]).value("THROTTLE_MILLISECONDS",null).directive("infiniteScroll",["$rootScope","$window","$interval","THROTTLE_MILLISECONDS",function(a,b,c,d){return{scope:{infiniteScroll:"&",infiniteScrollContainer:"=",infiniteScrollDistance:"=",infiniteScrollDisabled:"=",infiniteScrollUseDocumentBottom:"=",infiniteScrollListenForEvent:"@"},link:function(e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;return z=angular.element(b),u=null,v=null,j=null,k=null,r=!0,y=!1,x=null,i=!1,q=function(a){return a=a[0]||a,isNaN(a.offsetHeight)?a.document.documentElement.clientHeight:a.offsetHeight},s=function(a){if(a[0].getBoundingClientRect&&!a.css("none"))return a[0].getBoundingClientRect().top+t(a)},t=function(a){return a=a[0]||a,isNaN(window.pageYOffset)?a.document.documentElement.scrollTop:a.ownerDocument.defaultView.pageYOffset},p=function(){var b,d,g,h,l;return k===z?(b=q(k)+t(k[0].document.documentElement),g=s(f)+q(f)):(b=q(k),d=0,void 0!==s(k)&&(d=s(k)),g=s(f)-d+q(f)),y&&(g=q((f[0].ownerDocument||f[0].document).documentElement)),h=g-b,l=h<=q(k)*u+1,l?(j=!0,v?e.$$phase||a.$$phase?e.infiniteScroll():e.$apply(e.infiniteScroll):void 0):(i&&c.cancel(i),j=!1)},w=function(a,b){var d,e,f;return f=null,e=0,d=function(){return e=(new Date).getTime(),c.cancel(f),f=null,a.call()},function(){var g,h;return g=(new Date).getTime(),h=b-(g-e),h<=0?(c.cancel(f),f=null,e=g,a.call()):f?void 0:f=c(d,h,1)}},null!=d&&(p=w(p,d)),e.$on("$destroy",function(){if(k.unbind("scroll",p),null!=x&&(x(),x=null),i)return c.cancel(i)}),n=function(a){return u=parseFloat(a)||0},e.$watch("infiniteScrollDistance",n),n(e.infiniteScrollDistance),m=function(a){if(v=!a,v&&j)return j=!1,p()},e.$watch("infiniteScrollDisabled",m),m(e.infiniteScrollDisabled),o=function(a){return y=a},e.$watch("infiniteScrollUseDocumentBottom",o),o(e.infiniteScrollUseDocumentBottom),h=function(a){if(null!=k&&k.unbind("scroll",p),k=a,null!=a)return k.bind("scroll",p)},h(z),e.infiniteScrollListenForEvent&&(x=a.$on(e.infiniteScrollListenForEvent,p)),l=function(a){if(null!=a&&0!==a.length){if(a.nodeType&&1===a.nodeType?a=angular.element(a):"function"==typeof a.append?a=angular.element(a[a.length-1]):"string"==typeof a&&(a=angular.element(document.querySelector(a))),null!=a)return h(a);throw new Error("invalid infinite-scroll-container attribute.")}},e.$watch("infiniteScrollContainer",l),l(e.infiniteScrollContainer||[]),null!=g.infiniteScrollParent&&h(angular.element(f.parent())),null!=g.infiniteScrollImmediateCheck&&(r=e.$eval(g.infiniteScrollImmediateCheck)),i=c(function(){return r&&p(),c.cancel(i)})}}}]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="infinite-scroll");

View File

@@ -9,4 +9,4 @@
"ng-model" => "variant.line_item.quantity",
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}",
"ng-disabled" => "!variant.on_demand && variant.count_on_hand == 0",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}

View File

@@ -1,4 +1,5 @@
.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::variant.product.group_buy"}
%span.bulk-input-container
%span.bulk-input
%input.bulk.first{type: :number,
@@ -6,18 +7,18 @@
integer: true,
min: 0,
"ng-model" => "variant.line_item.quantity",
placeholder: "{{'shop_variant_quantity_min' | t}}",
placeholder: "{{::'shop_variant_quantity_min' | t}}",
"ofn-disable-scroll" => true,
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}
%span.bulk-input
%input.bulk.second{type: :number,
"ng-disabled" => "!variant.line_item.quantity",
integer: true,
min: 0,
"ng-model" => "variant.line_item.max_quantity",
placeholder: "{{'shop_variant_quantity_max' | t}}",
placeholder: "{{::'shop_variant_quantity_max' | t}}",
"ofn-disable-scroll" => true,
min: "{{variant.line_item.quantity}}",
name: "variant_attributes[{{variant.id}}][max_quantity]",
id: "variants_{{variant.id}}_max"}
name: "variant_attributes[{{::variant.id}}][max_quantity]",
id: "variants_{{::variant.id}}_max"}

View File

@@ -1,23 +1,23 @@
.variants.row
.small-12.medium-4.large-4.columns.variant-name
.table-cell
.inline {{ variant.name_to_display }}
.inline {{ ::variant.name_to_display }}
.bulk-buy.inline{"ng-if" => "::variant.product.group_buy"}
%i.ofn-i_056-bulk><
%em><
\ {{'bulk' | t}}
\ {{::'bulk' | t}}
%ng-include{src: "'partials/shop_variant_no_group_buy.html'"}
%ng-include{src: "'partials/shop_variant_with_group_buy.html'"}
.small-3.medium-1.large-1.columns.variant-unit
.table-cell
%em {{ variant.unit_to_display }}
%em {{ ::variant.unit_to_display }}
.small-4.medium-2.large-2.columns.variant-price
.table-cell.price
%i.ofn-i_009-close
{{ variant.price_with_fees | localizeCurrency }}
{{ ::variant.price_with_fees | localizeCurrency }}
-# Now in a template in app/assets/javascripts/templates !
%price-breakdown{"price-breakdown" => "_", variant: "variant",

View File

@@ -1,6 +1,5 @@
.footer-pad.small-12.columns
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true,
"infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"}
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true }
// TODO: Needs an ng-show to slide content down
.row.animate-slide{ "ng-show" => "query || appliedPropertiesList() || appliedTaxonsList()" }
@@ -29,10 +28,10 @@
.small-12.medium-6.large-6.large-offset-1.columns
= render partial: "shop/products/filters"
%div.pad-top
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) track by product.id ", "id" => "product-{{ product.id }}"}
%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 }}"}
= render "shop/products/summary"
%shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"}
-# %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}"}
%product{"ng-show" => "Products.loading"}

View File

@@ -18,4 +18,4 @@
%span{"ng-bind" => "::enterprise.name"}
.small-2.medium-2.large-1.columns.text-center
.taxon-flag
%render-svg{path: "{{product.primary_taxon.icon}}"}
%render-svg{path: "{{::product.primary_taxon.icon}}"}

View File

@@ -30,9 +30,9 @@ describe 'ProductsCtrl', ->
it "increments the limit up to the number of products", ->
scope.limit = 0
scope.incrementLimit()
expect(scope.limit).toEqual 1
expect(scope.limit).toEqual 10
scope.incrementLimit()
expect(scope.limit).toEqual 1
expect(scope.limit).toEqual 10
it "blocks keypresses on code 13", ->
event =