Skip to content

Commit 3ce47d4

Browse files
committed
added loadOnScroll option
1 parent f11090e commit 3ce47d4

File tree

7 files changed

+168
-8
lines changed

7 files changed

+168
-8
lines changed

docs/methods.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@ It will return a promise.
3131
| items | array | Array of element to append to the container |
3232
| parent | Element\|null | Container to append to. When none given it falls back to the configured container |
3333

34+
## enableLoadOnScroll
35+
36+
Enables the [`loadOnScroll`](options.md#loadOnScroll) setting on runtime.
37+
38+
## disableLoadOnScroll
39+
40+
Disables the [`loadOnScroll`](options.md#loadOnScroll) setting on runtime.

docs/options.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,15 @@ logger: {
162162
}
163163
```
164164

165+
## loadOnScroll
166+
167+
**Type:** `boolean`
168+
**Default:** `true`
169+
**Required:** no
170+
171+
Configures if the next/previous page should automatically be loaded when the users scrolls to the bottom or the top of the page.
172+
173+
When `loadOnScroll` is disabled the [`hit`](events.md#hit) event is still emitted, allowing you to manually trigger the next/prev page (for example by calling [`next`](methods.md#next)).
174+
175+
Use can use [`enableLoadOnScroll`](methods.md#enableLoadOnScroll) and [`disableLoadOnScroll`](methods.md#disableLoadOnScroll) to configure this setting on runtime.
176+

src/defaults.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ export default {
66
bind: true,
77
scrollContainer: window,
88
spinner: false,
9-
logger: true
9+
logger: true,
10+
loadOnScroll: true
1011
};

src/infinite-ajax-scroll.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,19 @@ export default class InfiniteAjaxScroll {
3838

3939
this.binded = false;
4040
this.paused = false;
41+
this.loadOnScroll = this.options.loadOnScroll;
4142
this.pageIndex = this.sentinel() ? 0 : -1;
43+
this.lastDistance = null;
4244

43-
this.on('hit', this.next);
45+
this.on('hit', () => {
46+
if (!this.loadOnScroll) {
47+
return;
48+
}
4449

50+
this.next();
51+
});
52+
53+
// initialize extensions
4554
this.pagination = new Pagination(this, this.options.pagination);
4655
this.spinner = new Spinner(this, this.options.spinner);
4756
this.logger = new Logger(this, this.options.logger);
@@ -51,7 +60,7 @@ export default class InfiniteAjaxScroll {
5160
this.on('binded', this.measure);
5261

5362
if (this.options.bind) {
54-
// @todo on document.ready?
63+
// @todo on document.ready? (window.addEventListener('DOMContentLoaded'))
5564
this.bind();
5665
}
5766
}
@@ -96,13 +105,14 @@ export default class InfiniteAjaxScroll {
96105

97106
Promise.resolve(this.nextHandler(event.pageIndex))
98107
.then((result) => {
108+
this.pageIndex = event.pageIndex;
109+
99110
if (!result) {
100111
this.emitter.emit('last');
101112

102113
return;
103114
}
104115

105-
this.pageIndex = event.pageIndex;
106116
this.resume();
107117
})
108118
;
@@ -203,6 +213,14 @@ export default class InfiniteAjaxScroll {
203213
this.measure();
204214
}
205215

216+
enableLoadOnScroll() {
217+
this.loadOnScroll = true;
218+
}
219+
220+
disableLoadOnScroll() {
221+
this.loadOnScroll = false;
222+
}
223+
206224
measure() {
207225
if (this.paused) {
208226
return;
@@ -216,9 +234,11 @@ export default class InfiniteAjaxScroll {
216234
distance = getDistanceToFold(sentinel, this.scrollContainer);
217235
}
218236

219-
if (distance <= 0) {
237+
if (distance <= 0 && (this.lastDistance === null || this.lastDistance > 0)) {
220238
this.emitter.emit('hit', {distance});
221239
}
240+
241+
this.lastDistance = distance;
222242
}
223243

224244
on(event, callback) {

src/paging.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ export default class Paging {
5050

5151
// @todo can be moved inside appended when eventStack is implemented
5252
let loaded = (event) => {
53-
// @todo event.xhr.response.title only works in case of responseType = "document"
5453
url = event.url;
55-
title = event.xhr.response.title
54+
55+
if (event.xhr.response) {
56+
title = event.xhr.response.title
57+
}
5658
};
5759

5860
this.ias.once('loaded', loaded);

src/spinner.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ export default class Spinner {
3333
this.ias = ias;
3434
this.options = extend({}, defaults, expand(options));
3535

36-
Assert.singleElement(this.options.element, 'spinner.element');
36+
if (this.options.element !== undefined) {
37+
Assert.singleElement(this.options.element, 'spinner.element');
38+
}
3739

3840
this.element = $(this.options.element)[0]; // @todo should we really cache this?
3941
this.hideFn = this.options.hide;

test/loadonscroll_spec.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
let ias;
2+
3+
describe('Load on scroll', () => {
4+
beforeEach(() => {
5+
// runs before each test in the block
6+
cy.visit('http://localhost:8080/test/fixtures/default/page1.html')
7+
});
8+
9+
it('should emit a next event when loadOnScroll enabled by default', () => {
10+
const spy = {
11+
next() {}
12+
};
13+
14+
cy.spy(spy, 'next');
15+
16+
cy.InfiniteAjaxScroll().then((InfiniteAjaxScroll) => {
17+
ias = new InfiniteAjaxScroll('.blocks', {
18+
item: '.blocks__block',
19+
});
20+
21+
ias.on('next', spy.next);
22+
23+
cy.scrollTo('bottom', {duration: 300}).then(function() {
24+
expect(spy.next).to.have.been.called;
25+
});
26+
});
27+
});
28+
29+
it('should emit a next event when loadOnScroll explicitly enabled', () => {
30+
const spy = {
31+
next() {}
32+
};
33+
34+
cy.spy(spy, 'next');
35+
36+
cy.InfiniteAjaxScroll().then((InfiniteAjaxScroll) => {
37+
ias = new InfiniteAjaxScroll('.blocks', {
38+
item: '.blocks__block',
39+
loadOnScroll: true
40+
});
41+
42+
ias.on('next', spy.next);
43+
44+
cy.scrollTo('bottom', {duration: 300}).then(function() {
45+
expect(spy.next).to.have.been.called;
46+
});
47+
});
48+
});
49+
50+
it('should not emit a next event when loadOnScroll is disabled', () => {
51+
const spy = {
52+
next() {}
53+
};
54+
55+
cy.spy(spy, 'next');
56+
57+
cy.InfiniteAjaxScroll().then((InfiniteAjaxScroll) => {
58+
ias = new InfiniteAjaxScroll('.blocks', {
59+
item: '.blocks__block',
60+
loadOnScroll: false
61+
});
62+
63+
ias.on('next', spy.next);
64+
65+
cy.scrollTo('bottom', {duration: 300}).then(function() {
66+
expect(spy.next).to.not.have.been.called;
67+
});
68+
});
69+
});
70+
71+
it('can be enabled (enableLoadOnScroll)', () => {
72+
const spy = {
73+
next() {}
74+
};
75+
76+
cy.spy(spy, 'next');
77+
78+
cy.InfiniteAjaxScroll().then((InfiniteAjaxScroll) => {
79+
ias = new InfiniteAjaxScroll('.blocks', {
80+
item: '.blocks__block',
81+
loadOnScroll: false
82+
});
83+
84+
ias.enableLoadOnScroll();
85+
86+
ias.on('next', spy.next);
87+
88+
cy.scrollTo('bottom', {duration: 300}).then(function() {
89+
expect(spy.next).to.have.been.called;
90+
});
91+
});
92+
});
93+
94+
it('can be disabled (disableLoadOnScroll)', () => {
95+
const spy = {
96+
next() {}
97+
};
98+
99+
cy.spy(spy, 'next');
100+
101+
cy.InfiniteAjaxScroll().then((InfiniteAjaxScroll) => {
102+
ias = new InfiniteAjaxScroll('.blocks', {
103+
item: '.blocks__block',
104+
loadOnScroll: true
105+
});
106+
107+
ias.disableLoadOnScroll();
108+
109+
ias.on('next', spy.next);
110+
111+
cy.scrollTo('bottom', {duration: 300}).then(function() {
112+
expect(spy.next).to.not.have.been.called;
113+
});
114+
});
115+
});
116+
});

0 commit comments

Comments
 (0)