-
Notifications
You must be signed in to change notification settings - Fork 13.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(infinite): add scroll in opposite direction #8099
Changes from 8 commits
6d8a6a6
d5066e1
b841b6f
8837fcd
480e5a6
2b0283b
4d74f05
73ebcc5
c770083
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Component, NgModule } from '@angular/core'; | ||
import { IonicApp, IonicModule } from '../../../../../ionic-angular'; | ||
|
||
|
||
@Component({ | ||
templateUrl: 'main.html' | ||
}) | ||
export class E2EPage {} | ||
|
||
|
||
@Component({ | ||
template: '<ion-nav [root]="root"></ion-nav>' | ||
}) | ||
export class E2EApp { | ||
root = E2EPage; | ||
} | ||
|
||
@NgModule({ | ||
declarations: [ | ||
E2EApp, | ||
E2EPage, | ||
], | ||
imports: [ | ||
IonicModule.forRoot(E2EApp) | ||
], | ||
bootstrap: [IonicApp], | ||
entryComponents: [ | ||
E2EApp, | ||
E2EPage, | ||
] | ||
}) | ||
export class AppModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<ion-content scrollDownOnLoad="true"> | ||
<b>This page should scroll down on load</b> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<p> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi scelerisque dolor lacus, ut vehicula arcu dapibus id. Morbi iaculis fermentum blandit. Curabitur tempus, ante et vehicula tempor, urna velit rutrum massa, quis suscipit purus lacus eget est. Sed nisi nulla, tempus id dictum a, cursus ut felis. Aliquam orci magna, rutrum nec tempor ac, fermentum quis eros. Sed ullamcorper felis sit amet tristique sagittis. Nullam sed tempus mi. Morbi sit amet lacinia leo. Nunc facilisis orci id consectetur dignissim. Integer dictum consectetur enim. Vivamus auctor, turpis ut eleifend pharetra, purus magna mattis arcu, vel pharetra tellus orci eget ex. Integer blandit posuere vehicula. Ut ipsum lorem, efficitur vitae eleifend tincidunt, fermentum nec lacus. Ut nec fermentum dui. | ||
</p> | ||
<b>It worked!</b> | ||
</ion-content> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ import { DomController } from '../../platform/dom-controller'; | |
* @name InfiniteScroll | ||
* @description | ||
* The Infinite Scroll allows you to perform an action when the user | ||
* scrolls a specified distance from the bottom of the page. | ||
* scrolls a specified distance from the bottom or top of the page. | ||
* | ||
* The expression assigned to the `infinite` event is called when | ||
* the user scrolls to the specified distance. When this expression | ||
|
@@ -148,6 +148,7 @@ export class InfiniteScroll { | |
_thr: string = '15%'; | ||
_thrPx: number = 0; | ||
_thrPc: number = 0.15; | ||
_position: string = POSITION_BOTTOM; | ||
_init: boolean = false; | ||
|
||
|
||
|
@@ -192,6 +193,21 @@ export class InfiniteScroll { | |
this.enable(shouldEnable); | ||
} | ||
|
||
/** | ||
* @input {string} The position of the infinite scroll element. | ||
* The value can be either `top` or `bottom`. | ||
* Default is `bottom`. | ||
*/ | ||
@Input() | ||
get position(): string { | ||
return this._position; | ||
} | ||
set position(val: string) { | ||
if (val === POSITION_TOP || val === POSITION_BOTTOM) { | ||
this._position = val; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's add here a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good! |
||
} | ||
|
||
/** | ||
* @output {event} Emitted when the scroll reaches | ||
* the threshold distance. From within your infinite handler, | ||
|
@@ -229,17 +245,20 @@ export class InfiniteScroll { | |
|
||
// ******** DOM READ **************** | ||
const d = this._content.getContentDimensions(); | ||
const height = d.contentHeight; | ||
|
||
let reloadY = d.contentHeight; | ||
if (this._thrPc) { | ||
reloadY += (reloadY * this._thrPc); | ||
} else { | ||
reloadY += this._thrPx; | ||
} | ||
const threshold = this._thrPc ? (height * this._thrPc) : this._thrPx; | ||
|
||
// ******** DOM READS ABOVE / DOM WRITES BELOW **************** | ||
|
||
const distanceFromInfinite = ((d.scrollHeight - infiniteHeight) - d.scrollTop) - reloadY; | ||
let distanceFromInfinite: number; | ||
|
||
if (this._position === POSITION_BOTTOM) { | ||
distanceFromInfinite = ((d.scrollHeight - infiniteHeight) - d.scrollTop) - height - threshold; | ||
} else if (this._position === POSITION_TOP) { | ||
distanceFromInfinite = d.scrollTop - infiniteHeight - threshold; | ||
} | ||
|
||
if (distanceFromInfinite < 0) { | ||
// ******** DOM WRITE **************** | ||
this._dom.write(() => { | ||
|
@@ -267,7 +286,23 @@ export class InfiniteScroll { | |
* to `enabled`. | ||
*/ | ||
complete() { | ||
if (this.state === STATE_LOADING) { | ||
if (this._position === POSITION_TOP) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you explain a little bit the algorithm used here? I think I get it, but still... you probably know better There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! I'll add a few more comments as well. New content is being added at the top, but the (Frame 1)
(Frame 2)
(Still frame 2, if I'm correct)
(Frame 3) |
||
// ******** DOM READ **************** | ||
const prevDim = this._content.getContentDimensions(); | ||
|
||
// ******** DOM READ **************** | ||
this._dom.read(() => { | ||
const newDim = this._content.getContentDimensions(); | ||
|
||
const newScrollTop = newDim.scrollHeight - (prevDim.scrollHeight - prevDim.scrollTop); | ||
|
||
// ******** DOM WRITE **************** | ||
this._dom.write(() => { | ||
this._content.scrollTop = newScrollTop; | ||
this.state = STATE_ENABLED; | ||
}); | ||
}); | ||
} else { | ||
this.state = STATE_ENABLED; | ||
} | ||
} | ||
|
@@ -319,6 +354,10 @@ export class InfiniteScroll { | |
ngAfterContentInit() { | ||
this._init = true; | ||
this._setListeners(this.state !== STATE_DISABLED); | ||
|
||
if (this._position === POSITION_TOP) { | ||
this._content.scrollDownOnLoad = true; | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -333,3 +372,6 @@ export class InfiniteScroll { | |
const STATE_ENABLED = 'enabled'; | ||
const STATE_DISABLED = 'disabled'; | ||
const STATE_LOADING = 'loading'; | ||
|
||
const POSITION_TOP = 'top'; | ||
const POSITION_BOTTOM = 'bottom'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { Component, ViewChild, NgModule } from '@angular/core'; | ||
import { Content, IonicApp, IonicModule, InfiniteScroll, NavController } from '../../../../../ionic-angular'; | ||
|
||
|
||
@Component({ | ||
templateUrl: 'main.html' | ||
}) | ||
export class E2EPage1 { | ||
@ViewChild(InfiniteScroll) infiniteScroll: InfiniteScroll; | ||
@ViewChild(Content) content: Content; | ||
items: number[] = []; | ||
enabled: boolean = true; | ||
|
||
constructor(public navCtrl: NavController) { | ||
for (var i = 0; i < 30; i++) { | ||
this.items.unshift( this.items.length ); | ||
} | ||
} | ||
|
||
doInfinite(infiniteScroll: InfiniteScroll) { | ||
console.log('Begin async operation'); | ||
|
||
getAsyncData().then(newData => { | ||
for (var i = 0; i < newData.length; i++) { | ||
this.items.unshift( this.items.length ); | ||
} | ||
|
||
console.log('Finished receiving data, async operation complete'); | ||
infiniteScroll.complete(); | ||
|
||
if (this.items.length > 90) { | ||
this.enabled = false; | ||
} | ||
}); | ||
} | ||
|
||
goToPage2() { | ||
this.navCtrl.push(E2EPage2); | ||
} | ||
|
||
toggleInfiniteScroll() { | ||
this.enabled = !this.enabled; | ||
} | ||
} | ||
|
||
|
||
@Component({ | ||
template: '<ion-content><button ion-button (click)="navCtrl.pop()">Pop</button></ion-content>' | ||
}) | ||
export class E2EPage2 { | ||
constructor(public navCtrl: NavController) {} | ||
} | ||
|
||
|
||
@Component({ | ||
template: '<ion-nav [root]="root"></ion-nav>' | ||
}) | ||
export class E2EApp { | ||
root = E2EPage1; | ||
} | ||
|
||
@NgModule({ | ||
declarations: [ | ||
E2EApp, | ||
E2EPage1, | ||
E2EPage2 | ||
], | ||
imports: [ | ||
IonicModule.forRoot(E2EApp) | ||
], | ||
bootstrap: [IonicApp], | ||
entryComponents: [ | ||
E2EApp, | ||
E2EPage1, | ||
E2EPage2 | ||
] | ||
}) | ||
export class AppModule {} | ||
|
||
|
||
function getAsyncData(): Promise<any[]> { | ||
// async return mock data | ||
return new Promise(resolve => { | ||
|
||
setTimeout(() => { | ||
let data: number[] = []; | ||
for (var i = 0; i < 30; i++) { | ||
data.unshift(i); | ||
} | ||
|
||
resolve(data); | ||
}, 2000); | ||
|
||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<ion-header> | ||
|
||
<ion-toolbar> | ||
<ion-title>Infinite Scroll</ion-title> | ||
</ion-toolbar> | ||
|
||
</ion-header> | ||
|
||
|
||
<ion-content> | ||
|
||
<ion-infinite-scroll (ionInfinite)="doInfinite($event)" position="top" [enabled]="enabled"> | ||
<ion-infinite-scroll-content> | ||
</ion-infinite-scroll-content> | ||
</ion-infinite-scroll> | ||
|
||
<ion-list> | ||
<button ion-item (click)="goToPage2()" *ngFor="let item of items"> | ||
{{ item }} | ||
</button> | ||
</ion-list> | ||
|
||
<p> | ||
InfiniteScroll is enabled: {{enabled}} | ||
</p> | ||
|
||
<button ion-button (click)="toggleInfiniteScroll()" block> | ||
Toggle InfiniteScroll Enabled | ||
</button> | ||
|
||
</ion-content> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!! is probably not needed, right? since we are using isTrueProperty() in the setter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, this can be removed if you'd like. I just copied the getter and setter from
@Input() fullscreen
.