All Projects → dhilt → Ngx Ui Scroll

dhilt / Ngx Ui Scroll

Licence: other
Infinite/virtual scroll for Angular

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Ngx Ui Scroll

Infinitescroll
Infinite Scroll (Endless Scrolling) for RecyclerView in Android
Stars: ✭ 183 (+26.21%)
Mutual labels:  scroll, scrolling, infinite-scroll
Android scroll endless
Scroll endless for Android recyclerview
Stars: ✭ 12 (-91.72%)
Mutual labels:  scroll, scrolling
Fuckmyscroll.js
🔮 Animated scrolling to certain point or anchor
Stars: ✭ 10 (-93.1%)
Mutual labels:  scroll, scrolling
Ngx Infinite Scroll
Infinite Scroll Directive for Angular
Stars: ✭ 1,024 (+606.21%)
Mutual labels:  scroll, infinite-scroll
Txscrolllabelview
🌭TXScrollLabelView, the best way to show & display information such as adverts / boardcast / onsale e.g. with a customView.
Stars: ✭ 714 (+392.41%)
Mutual labels:  scroll, scrolling
Infinite Ajax Scroll
Turn your existing pagination into infinite scrolling pages with ease
Stars: ✭ 804 (+454.48%)
Mutual labels:  scroll, infinite-scroll
Dragscroll
micro library for drag-n-drop scrolling style
Stars: ✭ 989 (+582.07%)
Mutual labels:  scroll, scrolling
React Scrolllock
🔒 Prevent scroll on the <body />
Stars: ✭ 393 (+171.03%)
Mutual labels:  scroll, scrolling
Vue List Scroller
Simple and easy to use Vue.js component for efficient rendering large lists
Stars: ✭ 65 (-55.17%)
Mutual labels:  scroll, infinite-scroll
Django Infinite Scroll Pagination
🌀 Pagination based on the seek method / keyset paging / offset-less pagination
Stars: ✭ 90 (-37.93%)
Mutual labels:  scrolling, infinite-scroll
Pd Select
vue components ,like ios 3D picker style,vue 3d 选择器组件,3D滚轮
Stars: ✭ 101 (-30.34%)
Mutual labels:  scroll, scrolling
Scrolldir
0 dependency JS plugin to leverage scroll direction with CSS ⬆⬇ 🔌💉
Stars: ✭ 679 (+368.28%)
Mutual labels:  scroll, scrolling
Recyclerview Fastscroller
A fully customizable Fast Scroller for the RecyclerView in Android, written in Kotlin
Stars: ✭ 585 (+303.45%)
Mutual labels:  scroll, scrolling
Rsdayflow
iOS 7+ Calendar (Date Picker) with Infinite Scrolling.
Stars: ✭ 843 (+481.38%)
Mutual labels:  scroll, infinite-scroll
Vue Mugen Scroll
Infinite scroll component for Vue.js 2
Stars: ✭ 532 (+266.9%)
Mutual labels:  scroll, infinite-scroll
Viewprt
A tiny, dependency-free, high performance viewport position & intersection observation tool
Stars: ✭ 36 (-75.17%)
Mutual labels:  scrolling, infinite-scroll
Prognroll
A tiny, lightweight jQuery plugin that creates scroll progress bar on the page.
Stars: ✭ 108 (-25.52%)
Mutual labels:  scroll, scrolling
Jump.js
A modern smooth scrolling library.
Stars: ✭ 3,459 (+2285.52%)
Mutual labels:  scroll, scrolling
Mac Mouse Fix
Mac Mouse Fix - A simple way to make your mouse better.
Stars: ✭ 362 (+149.66%)
Mutual labels:  scroll, scrolling
Jscroll
An infinite scrolling plugin for jQuery.
Stars: ✭ 1,084 (+647.59%)
Mutual labels:  scrolling, infinite-scroll

Build Status npm version

NgxUiScroll

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. Since v2.0.0, the core of the ngx-ui-scroll library lives and develops as a separate zero-dependency npm package vscroll.

can donate? go here 👉
make open-source world better


Motivation

Scrolling large datasets may cause performance issues. Many DOM elements, many data-bindings, many event listeners... The common way to improve the performance is to render only a small portion of the dataset visible to a user. Other dataset elements that are not visible to a user are virtualized with upward and downward empty padding elements which should provide a consistent viewport with consistent scrollbar parameters.

The *uiScroll is a 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 dataset 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 a 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.

Features

  • unlimited bidirectional virtual scroll
  • lots of virtualization settings
  • super easy templating
  • infinite mode, demo
  • horizontal mode, demo
  • entire window scrollable, demo
  • items with non-constant heights, demo
  • API Adapter object to manipulate and assess the Scroller, demos

Getting

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 { }

Usage

Basic usage template may look like

<div class="viewport">
  <div *uiScroll="let item of datasource">
    <b>{{item.text}}</b>
  </div>
</div>

where the viewport is a scrollable area of finite height:

.viewport {
    height: 300px;
    overflow-y: auto;
}

If the height of the viewport is not constrained, it will pull the entire content of the datasource and no scrollbar will appear.

*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. The directive calls Datasource.get method each time a user scrolls to the edge of visible element list. That's the API provided by the *uiScroll directive.

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 method must provide an array of count data-items started from index position. If there are no items within given range [index; index + count - 1], an empty array has to be passed. Empty result (or result which length is less than count) is being treated as the edge of the dataset (eof/bof), and no further requests for preceding/tailing items will be issued.

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.

Settings

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 Scroller initialization and have an impact on how the Scroller 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 dataset. The datasource left boundary.
maxIndex number,
integer
+Infinity Fixes absolute maximal index of the dataset. 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 scrollable" mode, when the entire window becomes the scrollable viewport.

Adapter API

The Scroller has API to assess its parameters and provide some manipulations at runtime. This API is available via special Adapter object. The datasource needs to be instantiated via operator "new" for the Adapter object to be added to it:

import { Datasource } from 'ngx-ui-scroll';
...
  datasource = new Datasource({
    get: ... ,
    settings: { ... }
  });

Then this.datasource.adapter.packageInfo, this.datasource.adapter.reload() and other Adapter expressions become available. For better typing, it is recommended to specify the Adapter type as follows:

import { Datasource, IAdapter } from 'ngx-ui-scroll';
...
  datasource = new Datasource<IAdapter<MyItem>>({
    get: ... ,
    settings: { ... }
  });

MyItem should reflect the structure of items that the Datasource will deal with. It is "unknown" by default, and if not set, for example, this.datasource.adapter.firstVisible.data.id expression will produce typescript error: Object is of type 'unknown'. There are some Adapter props and methods dealing with MyItem, and if used, MyItem should be specified.

Below is the list of read-only properties of the Adapter API with descriptions and links to demos.

Name Type Description
packageInfo IPackages {
  core: IPackage;
  consumer: IPackage;
}

IPackage {
  name: string;
  version: string
}
Information about versions of the library ant its core. For example: "ngx-ui-scroll" v2.0.0 (consumer), "vscroll" v1.0.0 (core).
init boolean Indicates whether the Scroller is initialized ot not.
init$ Subject<boolean> An Observable version of "init" property.
isLoading boolean Indicates whether the Scroller is working ot not.
isLoading$ Subject<boolean> An Observable version of "isLoading" property.
itemsCount number A number of items that are rendered in the viewport at a moment.
bufferInfo IBufferInfo {
  firstIndex: number;
  lastIndex: number;
  minIndex: number;
  maxIndex: number;
  absMinIndex: number;
  absMaxIndex: number;
}
firstIndex & lastIndex are the first and the last indexes in the current Buffer.minIndex & maxIndex are min and max indexes that were present in the Buffer.absMinIndex & absMaxIndex are min and max indexes that can be present in the Buffer.
bof boolean Indicates whether the beginning of the dataset is reached or not.
bof$ Subject<boolean> An Observable version of "bof" property.
eof boolean Indicates whether the end of the dataset is reached or not.
eof$ Subject<boolean> An Observable version of "eof" property.
firstVisible ItemAdapter {
  $index: number;
  data: MyItem;
  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 passed via Datasource, "element" is a link to DOM element which is relevant to the item.
firstVisible$ BehaviorSubject
<ItemAdapter>
An observable version of "firstVisible" property.
lastVisible ItemAdapter {
  $index: number;
  data: MyItem;
  element?: HTMLElement;
}
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 with description and links to demos.

Name Parameters Description
relax (callback?: Function) Resolves asynchronously when there are no pending processes. If the callback is set, it will be executed right before resolving. Basically, it needs to protect with the relax every piece of the App logic, that might be sensitive to the internal processes of the Scroller, to avoid interference and race conditions.
reload (startIndex?: number) Resets the items buffer, resets the viewport params and starts fetching items from startIndex (if set).
reset (datasource?: IDatasource) Performs hard reset of the Scroller's internal state by re-instantiating all its entities (instead of reusing them when reload). If datasource argument is passed, it will be treated as new Datasource. All props of the datasource are optional and the result Datasource will be a combination (merge) of the original one and the one passed as an argument.
check Checks if any of current items changed it's size and runs a procedure to provide internal consistency and new items fetching if needed.
clip (options: {
  forwardOnly?: boolean,
  backwardOnly?: boolean
})
Removes out-of-viewport items on demand. The direction in which invisible items should be clipped can be specified by passing an options object. If no options is passed (or both properties are set to true), clipping will occur in both directions.
append (options: {
  items: MyItem[],
  eof?: boolean
})

(items: MyItem | MyItem[], eof?: boolean) *
* old signature, deprecated
Adds items to the end of the Scroller's dataset. If eof parameter is not set, items will be added and rendered immediately, they will be placed right after the last item in the Scroller's buffer. If eof is set to true, items will be added and rendered only if the end of the dataset is reached; otherwise, these items will be virtualized. See also bof/eof demo.
prepend (options: {
  items: MyItem[],
  bof?: boolean
})

(items: MyItem | MyItem[], bof?: boolean) *
* old signature, deprecated
Adds items to the beginning of the Scroller's dataset. If bof parameter is not set, items will be added and rendered immediately, they will be placed right before the first item in the Scroller's buffer. If bof is set to true, items will be added and rendered only if the beginning of the dataset is reached; otherwise, these items will be virtualized. See also bof/eof demo.
remove (options: {
  predicate?: ItemsPredicate,
  indexes?: number[],
  increase?: boolean
})

(func: ItemsPredicate) *
* old signature, deprecated

type ItemsPredicate =
  (item: ItemAdapter) =>
    boolean
Removes items form buffer and/or virtually. Predicate is a function to be applied to every item presently in the buffer. Predicate must return a boolean value. If predicate's return value is true, the item will be removed. Only a continuous series of items can be removed at a time using predicate. Alternatively, if indexes array is passed, the items whose indexes match the list will be removed. Only one of the predicate and indexes options is allowed. In case of indexes, the deletion is performed also virtually. By default, indexes of the items following the deleted ones are decremented. Instead, if increase is set to true, indexes of the items before the removed ones will be increased.
insert (options: {
  items: MyItem[],
  before?: ItemsPredicate,
  after?: ItemsPredicate,
  decrease?: boolean
})
Inserts items before or after the one that presents in the buffer and satisfies the predicate condition. Only one of the before and after options is allowed. Indexes increase by default. Decreasing strategy can be enabled via decrease option.
replace (options: {
  predicate: ItemsPredicate,
  items: MyItem[],
  fixRight?: boolean
})
Replaces items that continuously match the predicate with an array of new items. Indexes are maintained on the assumption that the left border of the dataset is fixed. To release the left border and fix the right one the fixRight option should be set to true.

Along with the documented API there are some undocumented features that can be treated as experimental. They are not tested enough and might change over time. Some of them can be found on the experimental tab of the demo app.

All of the Adapter methods are asynchronous, because they work with DOM and may take time to complete. For this purpose the Adapter methods return a Promise resolving at the moment when the Scroller terminates its internal processes triggered by the invocation of the correspondent Adapter method. It is called Adapter Return API. This promise has exactly the same nature as the promise of the relax method. Both "Relax" and "Return API" are the instruments of the App-Scroller processes normalization. It might be quite important to run some logic after the Scroller finishes its job and relaxes. Below is an example of how an explicit sequence of the Adapter methods can be safely implemented:

const { adapter } = this.datasource;
const predicate = ({ $index }) => $index === indexToReplace;
await adapter.relax();
await adapter.remove({ predicate });
await adapter.insert({ items: [itemToReplace], before: predicate });
console.log('Replacement done');

For more information, see Adapter demo page.

Development

There are some npm scripts available from package.json:

  • npm start to run demo App on port 4200
  • npm test to run Karma tests
  • npm run build to build the ngx-ui-scroll module into the ./dist folder
  • npm run pack:install to build tar-gzipped version of package and install it locally into ./node_modules
  • npm run build-app to build demo App into the ./dist-app folder

Along 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,
      ...
    }
  });

The development settings are not documented. Information about them can be obtained directly from the source code. The Scroller 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.

Any participation is welcome, so feel free to submit new Issues and open Pull Requests.


2021 © dhilt, Hill30 Inc

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].