Unlimited bidirectional scrolling over limited viewport. A directive for Angular framework. Built with angular-library-starter. Inspired by angular-ui-scroll (AngularJS, since 2013). Demo is available at dhilt.github.io/ngx-ui-scroll.
Scrolling large date sets may cause performance issues. Many DOM elements, many data-bindings, many event listeners… The common way to improve this case is to render only a small portion of the data set visible to the user. Other data set elements that are not visible to the user are virtualized with upward and downward empty padding elements which should give us a consistent viewport with consistent scrollbar parameters.
The *uiScroll is structural directive that works like *ngFor and renders a templated element once per item from a collection. By requesting the external Datasource (the implementation of which is a developer responsibility) the *uiScroll directive fetches necessary portion of the data set and renders corresponded elements until the visible part of the viewport is filled out. It starts to retrieve new data to render new elements again if the user scrolls to the edge of visible element list. It dynamically destroys elements as they become invisible and recreates them if they become visible again.
The *uiScroll directive is a part of UiScrollModule which is available via npm –
npm install ngx-ui-scroll
The UiScrollModule has to be imported in the App/feature module where it is going to be used.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UiScrollModule } from 'ngx-ui-scroll';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
UiScrollModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
Basic usage template may look like
<div class="viewport">
<div *uiScroll="let item of datasource">
<b></b>
</div>
</div>
where the viewport is a scrollable area of finite height.
.viewport {
height: 300px;
overflow-y: auto;
overflow-anchor: none;
}
*uiScroll acts like *ngFor, but the datasource is an object of special type (IDatasource). It implements method get to be used by the *uiScroll directive to access the data by index and count parameters.
import { IDatasource } from 'ngx-ui-scroll';
export class AppComponent {
datasource: IDatasource = {
get: (index, count, success) => {
const data = [];
for (let i = index; i <= index + count - 1; i++) {
data.push({ text: 'item #' + i });
}
success(data);
}
};
}
Datasource.get must provide an array of count data-items started from index position. Datasource.get has 3 signatures: callback based, Promise based and Observable based. So, if we want some remote API to be a source of our data, basically it may look like
datasource: IDatasource = {
get: (index, count) =>
this.http.get(`${myApiUrl}?index=${index}&count=${count}`)
};
More details could be found on the Datasource demo page.
Datasource implementation along with get method property may include settings object property:
datasource: IDatasource = {
get: ...,
settings: {
minIndex: 0,
startIndex: 0,
...
}
};
Settings are being applied during the uiScroll initialization and have an impact on how the uiScroll behaves. Below is the list of available settings with descriptions, defaults, types and demos.
Name | Type | Default | Description |
---|---|---|---|
bufferSize | number, integer |
5 | Fixes minimal size of the pack of the datasource items to be requested per single Datasource.get call. Can’t be less than 1. |
padding | number, float |
0.5 | Determines viewport outlets relative to the viewport’s size that need to be filled. For example, 0.5 means that we’ll have as many items at a moment as needed to fill out 100% of the visible part of the viewport, + 50% of the viewport size in backward direction and + 50% in forward direction. The value can’t be less than 0.01. |
startIndex | number, integer |
1 | Specifies item index to be requested/rendered first. Can be any, but real datasource boundaries should be taken into account. |
minIndex | number, integer |
-Infinity | Fixes absolute minimal index of the data set. The datasource left boundary. |
maxIndex | number, integer |
+Infinity | Fixes absolute maximal index of the data set. The datasource right boundary. |
infinite | boolean | false | Allows to run “infinite” mode, when items rendered once are never removed. |
horizontal | boolean | false | Allows to run “horizontal” mode, when the viewport’s orientation is horizontal. |
windowViewport | boolean | false | Allows to run “entire window scrollabe” mode, when the entire window becomes the scrollable viewport. |
The uiScroll has API to assess its parameters and provide some manipulations run-time. This API is available via special Adapter object. The datasource needs to be instantiated via operator “new” fot the Adapter object to be added to it:
import { Datasource } from 'ngx-ui-scroll';
...
datasource = new Datasource({
get: ... ,
settings: { ... }
});
Then this.datasource.adapter.version
, this.datasource.adapter.reload()
and other Adapter expressions become legal. Below is the list of read-only properties of the Adapter API.
Name | Type | Description |
---|---|---|
version | string | Current version of ngx-ui-scroll library |
isLoading | boolean | Indicates whether the uiScroll is working ot not. |
isLoading$ | BehaviorSubject <boolean> |
An Observable version of “isLoading” property. |
itemsCount | number | A number of items that are rendered in the viewport at a moment. |
firstVisible | ItemAdapter { $index?: number; data?: any; element?: HTMLElement; } |
Object of ItemAdapter type containing information about first visible item, where “$index” corresponds to the datasource item index value, “data” is exactly the item’s content, “element” is a link to DOM element which is relevant to the item. |
firstVisible$ | BehaviorSubject <ItemAdapter> |
An observable version of “firstVisible” property. |
lastVisible | ItemAdapter | Object of ItemAdapter type containing information about last visible item. |
lastVisible$ | BehaviorSubject <ItemAdapter> |
An observable version of “lastVisible” property. |
Below is the list of invocable methods of the Adapter API.
Name | Parameters | Description |
---|---|---|
reload | (startIndex?: number) | Resets the items buffer, resets the viewport params and starts fetching items from “startIndex” (if set). |
There are some npm scripts available from package.json:
npm start
to run demo App on port 4200npm test
to run Karma testsnpm run build
to build the ngx-ui-scroll module into the ./dist foldernpm run pack:install
to build tar-gzipped version of package and install it locally into ./node_modulesAlong with settings object the datasource implementation may include also devSettings object:
import { Datasource } from 'ngx-ui-scroll';
...
datasource = new Datasource({
get: ... ,
settings: { ... },
devSettings: {
debug: true,
immediateLog: true,
...
}
});
We are not going to discuss development settings here, information about it can be obtained directly from the source code, but the uiScroll has “debug” mode with powerful logging which can be enabled via devSettings.debug = true
. Also, with devSettings.immediateLog = false
the console logging will be postponed until the undocumented Adapter method showLog
is called (datasource.adapter.showLog()
). This case could be important from the performance view: there might be too many logs and pushing them to the console output immediately could slow down the App.
The work has just begun. We have great plans and any participation is welcome! So, feel free to submit new issues and open Pull Requests.
2018 © dhilt, Hill30 Inc