Skip to content

Commit a9045e6

Browse files
committed
Merge pull request #66 from angular-ui/scrollingOptimization
Scrolling optimization
2 parents 6df8a3d + 3c3107e commit a9045e6

9 files changed

+83
-41
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ The data source object implements methods and properties to be used by the direc
108108
**Important:** Make sure to respect the `index` and `count` parameters of the request. The array passed to the success method should have
109109
exactly `count` elements unless it hit eof/bof
110110

111+
* Properties `minIndex` and `maxIndex`
112+
113+
#### Description
114+
As the scroller recieves the items requested by the `get` method, the value of minimum and maximum values of the item index are placed in the `minIndex` and `maxIndex` properties respectively. The values of the properties are cumulative - the value of the `minIndex` will never increase, and the value of the `maIndex` will never decrease - except the values are reset in response to a call to the adapter `reload` method. The values of the properties are used to maintain the appearance of the scroller scrollBar.
115+
116+
Values of the properties can be assigned programmatically. If the range of the index values is known in advance, assigneing them programmatically would improve the usability of the scrollBar.
117+
111118
###Adapter
112119
The adapter object is an internal object created for every instance of the scroller. Properties and methods of the adapter can be used to manipulate and assess the scroller the adapter was created for. Adapter based API replaces old (undocumented) event based API introduced earlier for this purpose. The event based API is now deprecated and no longer supported.
113120

demo/examples/scopeDatasource.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
</head>
1111
<body ng-controller="mainController">
1212

13-
<h2 style="position: fixed; left: 150px; top: 0;">is loading: {{loading}}; &nbsp; &nbsp; &nbsp; <a href="../index.html"> browse sample code</a></h2>
13+
<h2 style="position: fixed; left: 150px; top: 0;">is loading: {{loading}}; &nbsp; &nbsp; &nbsp; <a href="../index.html"> browse sample code</a><br/>counters: ab {{adapter.abCount}} abf {{adapter.abfCount}} s {{adapter.sCount}}</h2>
1414

1515
<div ui-scroll-viewport style="width: 340px; height: 300px; display: block; background-color: white;">
1616
<ul>
17-
<li ui-scroll="item in datasource" is-loading="loading">*{{item}}*</li>
17+
<li ui-scroll="item in datasource" adapter="adapter" is-loading="loading">*{{item}}*</li>
1818
</ul>
1919
</div>
2020

dist/ui-scroll-jqlite.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*!
22
* angular-ui-scroll
33
* https://github.com/angular-ui/ui-scroll.git
4-
* Version: 1.3.3 -- 2016-03-16T09:12:39.242Z
4+
* Version: 1.3.3 -- 2016-03-17T12:18:01.421Z
55
* License: MIT
66
*/
77

dist/ui-scroll-jqlite.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ui-scroll.js

+28-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*!
22
* angular-ui-scroll
33
* https://github.com/angular-ui/ui-scroll.git
4-
* Version: 1.3.3 -- 2016-03-16T09:12:39.242Z
4+
* Version: 1.3.3 -- 2016-03-17T12:18:01.421Z
55
* License: MIT
66
*/
77

@@ -586,15 +586,21 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
586586
adapter.reload = reload;
587587

588588
// events and bindings
589-
viewport.bind('resize', resizeAndScrollHandler);
590-
viewport.bind('scroll', resizeAndScrollHandler);
589+
function bindEvents() {
590+
viewport.bind('resize', resizeAndScrollHandler);
591+
viewport.bind('scroll', resizeAndScrollHandler);
592+
}
591593
viewport.bind('mousewheel', wheelHandler);
592594

595+
function unbindEvents() {
596+
viewport.unbind('resize', resizeAndScrollHandler);
597+
viewport.unbind('scroll', resizeAndScrollHandler);
598+
}
599+
593600
$scope.$on('$destroy', function () {
594601
// clear the buffer. It is necessary to remove the elements and $destroy the scopes
595602
buffer.clear();
596-
viewport.unbind('resize', resizeAndScrollHandler);
597-
viewport.unbind('scroll', resizeAndScrollHandler);
603+
unbindEvents();
598604
viewport.unbind('mousewheel', wheelHandler);
599605
});
600606

@@ -634,6 +640,10 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
634640
viewport.resetTopPaddingHeight();
635641
viewport.resetBottomPaddingHeight();
636642

643+
adapter.abCount = 0;
644+
adapter.abfCount = 0;
645+
adapter.sCount = 0;
646+
637647
if (arguments.length) {
638648
buffer.clear(arguments[0]);
639649
} else {
@@ -755,6 +765,7 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
755765
function adjustBuffer(rid) {
756766
// We need the item bindings to be processed before we can do adjustment
757767
return $timeout(function () {
768+
adapter.abCount++;
758769
processBufferedItems(rid);
759770

760771
if (viewport.shouldLoadBottom()) {
@@ -772,6 +783,7 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
772783
function adjustBufferAfterFetch(rid) {
773784
// We need the item bindings to be processed before we can do adjustment
774785
return $timeout(function () {
786+
adapter.abfCount++;
775787
var keepFetching = processBufferedItems(rid);
776788

777789
if (viewport.shouldLoadBottom() && keepFetching) {
@@ -787,6 +799,7 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
787799

788800
if (!pending.length) {
789801
adapter.loading(false);
802+
bindEvents();
790803
return adapter.calculateProperties();
791804
}
792805

@@ -852,7 +865,16 @@ angular.module('ui.scroll', []).directive('uiScrollViewport', function () {
852865

853866
function resizeAndScrollHandler() {
854867
if (!$rootScope.$$phase && !adapter.isLoading) {
855-
adjustBuffer();
868+
adapter.sCount++;
869+
if (viewport.shouldLoadBottom()) {
870+
enqueueFetch(ridActual, true);
871+
} else if (viewport.shouldLoadTop()) {
872+
enqueueFetch(ridActual, false);
873+
}
874+
875+
if (pending.length) {
876+
unbindEvents();
877+
}
856878
}
857879
}
858880

dist/ui-scroll.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ui-scroll.js

+27-5
Original file line numberDiff line numberDiff line change
@@ -568,15 +568,21 @@ angular.module('ui.scroll', [])
568568
adapter.reload = reload;
569569

570570
// events and bindings
571-
viewport.bind('resize', resizeAndScrollHandler);
572-
viewport.bind('scroll', resizeAndScrollHandler);
571+
function bindEvents() {
572+
viewport.bind('resize', resizeAndScrollHandler);
573+
viewport.bind('scroll', resizeAndScrollHandler);
574+
}
573575
viewport.bind('mousewheel', wheelHandler);
574576

577+
function unbindEvents() {
578+
viewport.unbind('resize', resizeAndScrollHandler);
579+
viewport.unbind('scroll', resizeAndScrollHandler);
580+
}
581+
575582
$scope.$on('$destroy', () => {
576583
// clear the buffer. It is necessary to remove the elements and $destroy the scopes
577584
buffer.clear();
578-
viewport.unbind('resize', resizeAndScrollHandler);
579-
viewport.unbind('scroll', resizeAndScrollHandler);
585+
unbindEvents();
580586
viewport.unbind('mousewheel', wheelHandler);
581587
});
582588

@@ -610,6 +616,10 @@ angular.module('ui.scroll', [])
610616
viewport.resetTopPaddingHeight();
611617
viewport.resetBottomPaddingHeight();
612618

619+
adapter.abCount = 0;
620+
adapter.abfCount = 0;
621+
adapter.sCount = 0;
622+
613623
if (arguments.length) {
614624
buffer.clear(arguments[0]);
615625
} else {
@@ -725,6 +735,7 @@ angular.module('ui.scroll', [])
725735
function adjustBuffer(rid) {
726736
// We need the item bindings to be processed before we can do adjustment
727737
return $timeout(() => {
738+
adapter.abCount++;
728739
processBufferedItems(rid);
729740

730741
if (viewport.shouldLoadBottom()) {
@@ -742,6 +753,7 @@ angular.module('ui.scroll', [])
742753
function adjustBufferAfterFetch(rid) {
743754
// We need the item bindings to be processed before we can do adjustment
744755
return $timeout(() => {
756+
adapter.abfCount++;
745757
let keepFetching = processBufferedItems(rid);
746758

747759
if (viewport.shouldLoadBottom() && keepFetching) {
@@ -757,6 +769,7 @@ angular.module('ui.scroll', [])
757769

758770
if (!pending.length) {
759771
adapter.loading(false);
772+
bindEvents();
760773
return adapter.calculateProperties();
761774
}
762775

@@ -821,7 +834,16 @@ angular.module('ui.scroll', [])
821834

822835
function resizeAndScrollHandler() {
823836
if (!$rootScope.$$phase && !adapter.isLoading) {
824-
adjustBuffer();
837+
adapter.sCount++;
838+
if (viewport.shouldLoadBottom()) {
839+
enqueueFetch(ridActual, true);
840+
} else if (viewport.shouldLoadTop()) {
841+
enqueueFetch(ridActual, false);
842+
}
843+
844+
if (pending.length) {
845+
unbindEvents();
846+
}
825847
}
826848
}
827849

test/BasicSetupSpec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ describe('uiScroll', function () {
1414
runTest(scrollSettings,
1515
function (viewport) {
1616
expect($.fn.bind.calls.all().length).toBe(3);
17-
expect($.fn.bind.calls.all()[0].args[0]).toBe('resize');
17+
expect($.fn.bind.calls.all()[0].args[0]).toBe('mousewheel');
1818
expect($.fn.bind.calls.all()[0].object[0]).toBe(viewport[0]);
19-
expect($.fn.bind.calls.all()[1].args[0]).toBe('scroll');
19+
expect($.fn.bind.calls.all()[1].args[0]).toBe('resize');
2020
expect($.fn.bind.calls.all()[1].object[0]).toBe(viewport[0]);
21-
expect($.fn.bind.calls.all()[2].args[0]).toBe('mousewheel');
21+
expect($.fn.bind.calls.all()[2].args[0]).toBe('scroll');
2222
expect($.fn.bind.calls.all()[2].object[0]).toBe(viewport[0]);
2323
}, {
2424
cleanupTest: function (viewport, scope, $timeout) {

test/BasicTestsSpec.js

+12-21
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ describe('uiScroll', function () {
265265

266266
viewport.scrollTop(400);
267267
viewport.trigger('scroll');
268-
flush();
269268

270269
viewport.scrollTop(0);
271270
viewport.trigger('scroll');
@@ -302,7 +301,6 @@ describe('uiScroll', function () {
302301

303302
viewport.scrollTop(400);
304303
viewport.trigger('scroll');
305-
flush();
306304

307305
viewport.scrollTop(0);
308306
viewport.trigger('scroll');
@@ -397,11 +395,10 @@ describe('uiScroll', function () {
397395
var flush = $timeout.flush;
398396
viewport.scrollTop(viewportHeight + itemHeight);
399397
viewport.trigger('scroll');
400-
flush();
398+
401399
viewport.scrollTop(viewportHeight + itemHeight * 2);
402400
viewport.trigger('scroll');
403401
flush();
404-
expect(flush).toThrow();
405402

406403
expect(spy.calls.all().length).toBe(4);
407404

@@ -434,19 +431,15 @@ describe('uiScroll', function () {
434431

435432
viewport.scrollTop(0); //first full, scroll to -2
436433
viewport.trigger('scroll');
437-
flush();
438434

439435
viewport.scrollTop(0); //last full, scroll to -5, bof is reached
440436
viewport.trigger('scroll');
441437
flush();
442438

443-
expect(flush).toThrow();
444439
viewport.scrollTop(0); //empty, no scroll occurred (-8)
445440
viewport.trigger('scroll');
446441
flush();
447442

448-
expect(flush).toThrow();
449-
450443
expect(spy.calls.all().length).toBe(5);
451444
expect(spy.calls.all()[0].args[0]).toBe(1);
452445
expect(spy.calls.all()[1].args[0]).toBe(4);
@@ -500,15 +493,15 @@ describe('uiScroll', function () {
500493
wheelEventElement.dispatchEvent(getNewWheelEvent()); //now we are at the top but preventDefault is occurred because of bof will be reached only after next scroll trigger
501494
expect(documentScrollBubblingCount).toBe(2); //here! the only one prevented wheel-event
502495

503-
flush();
496+
//flush();
504497

505498
wheelEventElement.dispatchEvent(getNewWheelEvent()); //preventDefault will not occurred but document will not scroll because of viewport will be scrolled
506499
expect(documentScrollBubblingCount).toBe(3);
507500

508501
viewport.scrollTop(0);
509502
viewport.trigger('scroll'); //bof will be reached right after that
510503

511-
flush();
504+
//flush();
512505

513506
wheelEventElement.dispatchEvent(getNewWheelEvent()); //preventDefault will not occurred because of we are at the top and bof is reached
514507
expect(documentScrollBubblingCount).toBe(4);
@@ -560,19 +553,17 @@ describe('uiScroll', function () {
560553

561554
expect(!!scope.container1 && !!scope.container1.adapter && !!scope.container2).toBe(true);
562555

563-
scope.$watch('container2.isLoading', function(newValue, oldValue) {
564-
switch(++isLoadingChangeCount) {
565-
case 1: expect(newValue).toBe(true); expect(oldValue).toBe(true); break;
566-
case 2: expect(newValue).toBe(false); expect(oldValue).toBe(true); break;
567-
}
568-
expect(scope.container1.adapter.isLoading).toBe(newValue);
556+
// need to review: isLoading=true can't be catched since subscribe/unsibscribe optimization
557+
scope.$watch('container1.adapter.isLoading', function(newValue) {
558+
isLoadingChangeCount++;
559+
expect(scope.container2.isLoading).toBe(newValue);
569560
});
570561

571562
viewport.scrollTop(100);
572563
viewport.trigger('scroll');
573564
$timeout.flush();
574565

575-
expect(isLoadingChangeCount).toBe(2);
566+
expect(isLoadingChangeCount).toBe(1);
576567
}
577568
);
578569
});
@@ -636,16 +627,16 @@ describe('uiScroll', function () {
636627
for(i = 0; i < limit; i++) {
637628
viewport.scrollTop(viewport.scrollTop() + scrollDelta);
638629
viewport.trigger('scroll');
639-
$timeout.flush();
640630
}
641631

642632
// scroll up, return to the top
643633
for(i = 0; i < limit; i++) {
644634
viewport.scrollTop(viewport.scrollTop() - scrollDelta);
645635
viewport.trigger('scroll');
646-
$timeout.flush();
647636
}
648637

638+
$timeout.flush();
639+
649640
// scroll down + expectation
650641
for(i = 0; i < limit; i++) {
651642
viewport.scrollTop(viewport.scrollTop() + scrollDelta);
@@ -683,16 +674,16 @@ describe('uiScroll', function () {
683674
for(i = 0; i < limit; i++) {
684675
viewport.scrollTop(viewport.scrollTop() - scrollDelta);
685676
viewport.trigger('scroll');
686-
$timeout.flush();
687677
}
688678

689679
// scroll down, return to the bottom
690680
for(i = 0; i < limit; i++) {
691681
viewport.scrollTop(viewport.scrollTop() + scrollDelta);
692682
viewport.trigger('scroll');
693-
$timeout.flush();
694683
}
695684

685+
$timeout.flush();
686+
696687
// unstable delta passing
697688
viewport.scrollTop(viewport.scrollTop());
698689

0 commit comments

Comments
 (0)