Compare commits

..

No commits in common. "master" and "chore/refactor" have entirely different histories.

99 changed files with 1788 additions and 1906 deletions

BIN
.DS_Store vendored

Binary file not shown.

32
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,32 @@
<!-- Love ngx-infinite-scroll? Please consider supporting our collective:
👉 https://opencollective.com/ngx-infinite-scroll/donate -->
Your issue may already be reported!
Please search on the [issue track](../) before creating one.
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Actual Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
### Steps To Reproduce / Demo (if applicable)
[ ] Please share a [stackblitz](https://stackblitz.com/) or [plunkr](https://plnkr.co/) demo reproducing this issue
### Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
### Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
- [ ] Version used:
- [ ] Browser Name and version:
- [ ] (Optional) Operating System and version (desktop or mobile):
- [ ] (Optional) Link to your project:

30
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,30 @@
A similar PR may already be submitted!
Please search among the [Pull request](../) before creating one.
Thanks for submitting a pull request! Please provide enough information so that others can review your pull request.
**Summary**
<!-- Summary of the PR -->
This PR fixes/implements the following **bugs/features**
- [ ] #issue1
- [ ] #issue2
- [ ] #Feature1
- [ ] #Feature2
- [ ] Breaking changes
<!-- You can skip this if you're fixing a typo or adding an app to the Showcase. -->
Explain the **motivation** for making this change. What existing problem does the pull request solve?
<!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
### Requirements
Make sure these boxes are checked:
- [ ] link to an issue
- [ ] tests are updated (added/changed/removed)
- [ ] tests run successfully (local)
- [ ] tests run successfully (TravisCI)
- [ ] please follow this [styleguide](https://gist.github.com/stephenparish/9941e89d80e2bc58a153#subject-line) for this pr title

94
.gitignore vendored
View File

@ -1,43 +1,63 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
#################
## Misc
#################
**/.DS_Store
nbproject
manifest.mf
build.xml
node_modules/*
npm-debug.log
yarn-error.log
*node_modules*
coverage
./*.js
src/*.js
angular2-infinite-scroll.js
!karma.conf.js
!karma-test-shim.js
*.map
*.d.ts
!make.js
!bundles/*.js
# IDEs and editors
.idea/
#################
## JetBrains
#################
.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
.settings
.idea/*
*.iml
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
############
## Windows
############
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
############
## Mac
############
# Mac crap
.DS_Store
.tmp
typings
.tags*
src/ngFactory
*.metadata.json
$ cat .gitignore
/node_modules
/dist
/documentation
*.log
*.tgz
npm-debug.*
package-lock.json

14
.npmignore Normal file
View File

@ -0,0 +1,14 @@
# Node generated files
node_modules
npm-debug.log
# OS generated files
Thumbs.db
.DS_Store
# Ignored files
*.ts
!*.d.ts
# ngc generated files
src/ngFactory

1
.npmrc
View File

@ -1 +0,0 @@
package-lock=false

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
sudo: required
dist: trusty
addons:
apt:
sources:
- google-chrome
packages:
- google-chrome-stable
language: node_js
node_js:
- stable
before_install:
- npm i npm@^4 -g
install:
- npm install
script:
- npm test
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 3
notifications:
email: false

View File

@ -1,4 +0,0 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

17
.vscode/launch.json vendored
View File

@ -1,20 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "pwa-chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
"name": "Test In Chrome",
"sourceMaps": true,
"webRoot": "${workspaceRoot}/tests",
"url": "http://localhost:9876/debug.html",
"runtimeArgs": ["--headless"]
}
]
}

42
.vscode/tasks.json vendored
View File

@ -1,42 +0,0 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

View File

@ -1,59 +1,3 @@
## v 13.0.0 (2022/26/03)
- [UPGRADE] - now using Angular 13
- [DEV] - includes now a demo app for development
## v 10.1.0 (2020/12/09)
- [FIX] - fixes fast scroll issues #385
## v 10.0.1 (2020/12/09)
- [FIX] - throttle behavior refined - fixed issue #198
## v 10.0.0 (2020/11/07)
- [UPGRADE] - now using Angular 10
## v 9.1.0 (2020/09/09)
- [UPGRADE] - upgrading scarf
## v 9.0.0 (2020/05/12)
- [UPGRADE] - now using Angular 9
## v 8.0.2 (2020/05/10)
- [CHORE] - add @scarf
## v 8.0.1 (2019/10/15)
- [FIX] - solves issue with open collective postinstall #321
## v 8.0.0 (2019/07/26)
- [UPGRADE] - now using Angular 8
- [BREAKING_CHANGE] - `InfiniteScrollEvent` is renamed to `IInfiniteScrollEvent`
## v 7.2.0 (2019/06/10)
- [FIX] - fixes #322 - fixing scrollDistance calculations to include it reach to definite bottom
## v 7.1.0 (2019/03/10)
- [FIX] - 'alwaysCallback' to trigger only when past distance point
- [UPGRADE] - unit tests with puppeteer
- [UPGRADE] - scorll state is now handled within a class
- [FIX] - using now opencollective-postinstall #296
## v 7.0.1 (2019/01/04)
- [FIX] - build fix adding correct version of Typescript 3
## v 7.0.0 (2018/12/30)
- [UPGRADE] - now using Angular 7
## v 6.0.1 (2018/06/15)
- [FIX] - scroll up calculations issues #282

View File

@ -1,27 +1,161 @@
# Development
# angular-library-starter
[![Build Status](https://travis-ci.org/robisim74/angular-library-starter.svg?branch=master)](https://travis-ci.org/robisim74/angular-library-starter)
>Build an Angular library compatible with AoT compilation &amp; Tree shaking.
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.1.3.
This starter allows you to create a library for **Angular 2+** apps written in _TypeScript_, _ES6_ or _ES5_.
The project is based on the official _Angular_ packages.
## Development server
Get the [Changelog](https://github.com/robisim74/angular-library-starter/blob/master/CHANGELOG.md).
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Contents
* [1 Project structure](#1)
* [2 Customizing](#2)
* [3 Unit testing](#3)
* [4 Building](#4)
* [5 Publishing](#5)
* [6 Documentation](#6)
* [7 Using the library](#7)
* [8 What it is important to know](#8)
## Code scaffolding
## <a name="1"></a>1 Project structure
- Library:
- **src** folder for the classes
- **public_api.ts** entry point for all public APIs of the package
- **package.json** _npm_ options
- **rollup.config.js** _Rollup_ configuration for building the bundles
- **tsconfig-build.json** _ngc_ compiler options for _AoT compilation_
- **build.js** building process using _ShellJS_
- Unit testing:
- **tests** folder for unit tests
- **karma.conf.js** _Karma_ configuration that uses _webpack_ to build the tests
- **spec.bundle.js** defines the files used by _webpack_
- **tsconfig.json** _TypeScript_ compiler options
- Extra:
- **tslint.json** _TypeScript_ linter rules with _Codelyzer_
- **travis.yml** _Travis CI_ configuration
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## <a name="2"></a>2 Customizing
1. Update [Node & npm](https://docs.npmjs.com/getting-started/installing-node).
## Build
2. Rename `angular-library-starter` and `angularLibraryStarter` everywhere to `my-library` and `myLibrary`.
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
3. Update in `package.json` file:
- version: [Semantic Versioning](http://semver.org/)
- description
- urls
- packages
## Running unit tests
and run `npm install`.
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
4. Create your classes in `src` folder, and export public classes in `my-library.ts`.
## Running end-to-end tests
5. You can create only one _module_ for the whole library:
I suggest you create different _modules_ for different functions,
so that the user can import only those he needs and optimize _Tree shaking_ of his app.
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
6. Update in `rollup.config.js` file `external` & `globals` libraries with those that actually you use.
## Further help
7. Create unit tests in `tests` folder.
_Karma_ is configured to use _webpack_ only for `*.ts` files: if you need to test different formats, you have to update it.
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
## <a name="3"></a>3 Unit testing
```Shell
npm test
```
## <a name="4"></a>4 Building
The following command:
```Shell
npm run build
```
- starts _TSLint_ with _Codelyzer_
- starts _AoT compilation_ using _ngc_ compiler
- creates `dist` folder with all the files of distribution
To test locally the npm package:
```Shell
npm run pack-lib
```
Then you can install it in an app to test it:
```Shell
npm install [path]my-library-[version].tgz
```
## <a name="5"></a>5 Publishing
Before publishing the first time:
- you can register your library on [Travis CI](https://travis-ci.org/): you have already configured `.travis.yml` file
- you must have a user on the _npm_ registry: [Publishing npm packages](https://docs.npmjs.com/getting-started/publishing-npm-packages)
```Shell
npm run publish-lib
```
## <a name="6"></a>6 Documentation
To generate the documentation, this starter uses [compodoc](https://github.com/compodoc/compodoc):
```Shell
npm run compodoc
npm run compodoc-serve
```
## <a name="7"></a>7 Using the library
### Installing
```Shell
npm install my-library --save
```
### Loading
#### Using SystemJS configuration
```JavaScript
System.config({
map: {
'my-library': 'node_modules/my-library/bundles/my-library.umd.js'
}
});
```
#### Angular-CLI
No need to set up anything, just import it in your code.
#### Rollup or webpack
No need to set up anything, just import it in your code.
#### Plain JavaScript
Include the `umd` bundle in your `index.html`:
```Html
<script src="node_modules/my-library/bundles/my-library.umd.js"></script>
```
and use global `ng.myLibrary` namespace.
### AoT compilation
The library is compatible with _AoT compilation_.
## <a name="8"></a>8 What it is important to know
1. `package.json`
* `"main": "./bundles/angular-library-starter.umd.js"` legacy module format
* `"module": "./bundles/angular-library-starter.es5.js"` flat _ES_ module, for using module bundlers such as _Rollup_ or _webpack_:
[package module](https://github.com/rollup/rollup/wiki/pkg.module)
* `"es2015": "./bundles/angular-library-starter.js"` _ES2015_ flat _ESM_ format, experimental _ES2015_ build
* `"peerDependencies"` the packages and their versions required by the library when it will be installed
2. `tsconfig-build.json` file used by _ngc_ compiler
* Compiler options:
* `"declaration": true` to emit _TypeScript_ declaration files
* `"module": "es2015"` & `"target": "es2015"` are used by _Rollup_ to create the _ES2015_ bundle
* Angular Compiler Options:
* `"skipTemplateCodegen": true,` skips generating _AoT_ files
* `"annotateForClosureCompiler": true` for compatibility with _Google Closure compiler_
* `"strictMetadataEmit": true` without emitting metadata files, the library will not compatible with _AoT compilation_
3. `rollup.config.js` file used by _Rollup_
* `format: 'umd'` the _Universal Module Definition_ pattern is used by _Angular_ for its bundles
* `moduleName: 'ng.angularLibraryStarter'` defines the global namespace used by _JavaScript_ apps
* `external` & `globals` declare the external packages
4. Server-side prerendering
If you want the library will be compatible with server-side prerendering:
* `window`, `document`, `navigator` and other browser types do not exist on the server
* don't manipulate the _nativeElement_ directly
## License
MIT

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Oren Farhi
Copyright (c) 2017 Roberto Simonetti
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

160
README.md
View File

@ -4,55 +4,27 @@
[![npm downloads a month](https://img.shields.io/npm/dm/ngx-infinite-scroll.svg)](https://img.shields.io/npm/dm/ngx-infinite-scroll.svg)
[![npm downloads a week](https://img.shields.io/npm/dt/ngx-infinite-scroll.svg)](https://img.shields.io/npm/dt/ngx-infinite-scroll.svg)
## [Consider Becoming a sponsor](https://opencollective.com/ngx-infinite-scroll#sponsor)
# Angular Infinite Scroll
versions now follow Angular's version to easily reflect compatibility.
Meaning, for **Angular 10**, use `ngx-infinite-scroll @ ^10.0.0`
versions now follow Angular's version to easily reflect compatibility.
Meaning, for **Angular 6**, use `ngx-infinite-scroll @ ^6.0.0`
## Angular - Older Versions Support
## Angular Support
Starting **Angular 6 and Above** - `ngx-infinite-scroll@THE_VERSION.0.0`
Now supports **Angular 6** and **rxjs 6** - `ngx-infinite-scroll@6.0.0`
For **Angular 4** and **Angular = ^5.5.6** - use version `ngx-infinite-scroll@0.8.4`
For **Angular 5.x** with **rxjs =<5.5.2** - use version `ngx-infinite-scroll@0.8.3`
For Angular version **<= 2.3.1**, you can use `npm i angular2-infinite-scroll` (latest version is 0.3.42) - please notice **the angular2-infinite-scroll** package is deprecated
## Used By
## Angular Consulting Services
- [Google](https://google.com)
- [Apple](https://apple.com)
- [Amazon](https://amazon.com)
- [Microsoft](https://microsoft.com)
- [Disney](https://disney.com)
- [Sap](https://sap.com/)
- [Cisco](https://cisco.com/)
- [Yandex](https://yandex.com)
- [Ancestry](https://www.ancestry.com/)
and much more.
> _These analytics are made available via the awesome [Scarf](https://www.npmjs.com/package/@scarf/scarf) package analytics library_
### Opt-Out Of Scarf
Scarf can be disabled by following [these directions](https://github.com/orizens/ngx-infinite-scroll/issues/352#issuecomment-742009046)
## Front End Consulting Services
I'm a Senior Front End Engineer & Consultant at [Orizens](https://orizens.com).
I'm a Senior Javascript Engineer & A Front End Consultant at [Orizens](http://orizens.com).
My services include:
- Angular/React/Javascript Consulting
- Front End Architecture Consulting
- Project Code Review
- Project Development
- consulting to companies and startups on how to approach code in their projects and keep it maintainable.
- I provide project bootstrapping and development - while afterwards, I integrate it on site and guide the team on it.
[Contact Here](http://orizens.com/contact)
<a href="https://orizens.com" target="_blank">
<img src="https://cloud.githubusercontent.com/assets/878660/23353771/d0adbd12-fcd6-11e6-96be-7a236f8819d9.png" alt="Webpack and Angular" width="20%"/>
</a>
[Contact Me Here](http://orizens.com/contact)
## Installation
@ -62,27 +34,21 @@ npm install ngx-infinite-scroll --save
## Supported API
### Properties
Currently supported attributes:
| @Input() | Type | Required | Default | Description |
| ------------------------ | -------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| infiniteScrollDistance | number | optional | 2 | the bottom percentage point of the scroll nob relatively to the infinite-scroll container (i.e, 2 (2 \* 10 = 20%) is event is triggered when 80% (100% - 20%) has been scrolled). if container.height is 900px, when the container is scrolled to or past the 720px, it will fire the scrolled event. |
| infiniteScrollUpDistance | number | optional | 1.5 | should get a number |
| infiniteScrollThrottle | number | optional | 150 | should get a number of **milliseconds** for throttle. The event will be triggered this many milliseconds after the user _stops_ scrolling. |
| scrollWindow | boolean | optional | true | listens to the window scroll instead of the actual element scroll. this allows to invoke a callback function in the scope of the element while listenning to the window scroll. |
| immediateCheck | boolean | optional | false | invokes the handler immediately to check if a scroll event has been already triggred when the page has been loaded (i.e. - when you refresh a page that has been scrolled) |
| infiniteScrollDisabled | boolean | optional | false | doesn't invoke the handler if set to true |
| horizontal | boolean | optional | false | sets the scroll to listen for horizontal events |
| alwaysCallback | boolean | optional | false | instructs the scroller to always trigger events |
| infiniteScrollContainer | string / HTMLElement | optional | null | should get a html element or css selector for a scrollable element; window or current element will be used if this attribute is empty. |
| fromRoot | boolean | optional | false | if **infiniteScrollContainer** is set, this instructs the scroller to query the container selector from the root of the **document** object. |
### Events
| @Output() | Type | Event Type | Required | Description |
| ---------- | ------------ | -------------------- | -------- | ------------------------------------------------------------------------------- |
| scrolled | EventEmitter | IInfiniteScrollEvent | optional | this will callback if the distance threshold has been reached on a scroll down. |
| scrolledUp | EventEmitter | IInfiniteScrollEvent | optional | this will callback if the distance threshold has been reached on a scroll up. |
- **infiniteScrollDistance**<_number_> - (optional, default: **2**) - the bottom percentage point of the scroll nob relatively to the infinite-scroll container (i.e, 2 (2 \* 10 = 20%) is event is triggered when 80% (100% - 20%) has been scrolled).
if container.height is 900px, when the container is scrolled to or past the 720px, it will fire the scrolled event.
- **infiniteScrollUpDistance**<_number_> - (optional, default: **1.5**) - should get a number
- **infiniteScrollThrottle**<_number_> - (optional, default: **150**) - should get a number of **milliseconds** for throttle. The event will be triggered this many milliseconds after the user _stops_ scrolling.
- **infiniteScrollContainer**<_string|HTMLElement_> - (optional, default: null) - should get a html element or css selector for a scrollable element; window or current element will be used if this attribute is empty.
- **scrolled**<_function_> - this will callback if the distance threshold has been reached on a scroll down.
- **scrolledUp**<_function_> - (event: InfiniteScrollEvent) - this will callback if the distance threshold has been reached on a scroll up.
- **scrollWindow**<_boolean_> - (optional, default: **true**) - listens to the window scroll instead of the actual element scroll. this allows to invoke a callback function in the scope of the element while listenning to the window scroll.
- **immediateCheck**<_boolean_> - (optional, default: **false**) - invokes the handler immediately to check if a scroll event has been already triggred when the page has been loaded (i.e. - when you refresh a page that has been scrolled).
- **infiniteScrollDisabled**<_boolean_> - (optional, default: **false**) - doesn't invoke the handler if set to true
- **horizontal**<_boolean_> - (optional, default: false) - sets the scroll to listen for horizontal events
- **alwaysCallback**<_boolean_> - (optional, default: false) - instructs the scroller to always trigger events
- **fromRoot**<_boolean_> - (optional, default: false) - if **infiniteScrollContainer** is set, this instructs the scroller to query the container selector from the root of the **document** object.
## Behavior
@ -110,7 +76,7 @@ import { AppComponent } from './app';
@NgModule({
imports: [BrowserModule, InfiniteScrollModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
@ -125,14 +91,13 @@ import { Component } from '@angular/core';
@Component({
selector: 'app',
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()"
></div>
`,
<div class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()">
</div>
`
})
export class AppComponent {
onScroll() {
@ -154,18 +119,17 @@ import { Component } from '@angular/core';
height: 20rem;
overflow: scroll;
}
`,
`
],
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()"
[scrollWindow]="false"
></div>
`,
<div class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()"
[scrollWindow]="false">
</div>
`
})
export class AppComponent {
onScroll() {
@ -184,16 +148,15 @@ import { InfiniteScroll } from 'ngx-infinite-scroll';
selector: 'app',
directives: [InfiniteScroll],
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollUpDistance]="1.5"
[infiniteScrollThrottle]="50"
(scrolled)="onScrollDown()"
(scrolledUp)="onScrollUp()"
></div>
`,
<div class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollUpDistance]="1.5"
[infiniteScrollThrottle]="50"
(scrolled)="onScrollDown()"
(scrolledUp)="onScrollUp()">
</div>
`
})
export class AppComponent {
onScrollDown() {
@ -219,20 +182,19 @@ import { Component } from '@angular/core';
height: 100px;
overflow-y: scroll;
}
`,
`
],
template: `
<div class="main-panel">
<div
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
[infiniteScrollContainer]="selector"
[fromRoot]="true"
(scrolled)="onScroll()"
></div>
</div>
`,
<div class="main-panel">
<div infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
[infiniteScrollContainer]="selector"
[fromRoot]="true"
(scrolled)="onScroll()">
</div>
</div>
`
})
export class AppComponent {
selector: string = '.main-panel';
@ -266,6 +228,8 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/ngx-infinite-scroll#sponsor)]
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/2/avatar.svg"></a>

View File

@ -1,137 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ngx-infinite-scroll": {
"projectType": "library",
"root": "projects/ngx-infinite-scroll",
"sourceRoot": "projects/ngx-infinite-scroll/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/ngx-infinite-scroll/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/ngx-infinite-scroll/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/ngx-infinite-scroll/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/ngx-infinite-scroll/src/test.ts",
"tsConfig": "projects/ngx-infinite-scroll/tsconfig.spec.json",
"karmaConfig": "projects/ngx-infinite-scroll/karma.conf.js"
}
}
}
},
"demo": {
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"root": "projects/demo",
"sourceRoot": "projects/demo/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/demo",
"index": "projects/demo/src/index.html",
"main": "projects/demo/src/main.ts",
"polyfills": "projects/demo/src/polyfills.ts",
"tsConfig": "projects/demo/tsconfig.app.json",
"assets": [
"projects/demo/src/favicon.ico",
"projects/demo/src/assets"
],
"styles": [
"projects/demo/src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "projects/demo/src/environments/environment.ts",
"with": "projects/demo/src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "demo:build:production"
},
"development": {
"browserTarget": "demo:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "demo:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/demo/src/test.ts",
"polyfills": "projects/demo/src/polyfills.ts",
"tsConfig": "projects/demo/tsconfig.spec.json",
"karmaConfig": "projects/demo/karma.conf.js",
"assets": [
"projects/demo/src/favicon.ico",
"projects/demo/src/assets"
],
"styles": [
"projects/demo/src/styles.css"
],
"scripts": []
}
}
}
}
},
"defaultProject": "ngx-infinite-scroll"
}

61
build.js Normal file
View File

@ -0,0 +1,61 @@
"use strict";
require('shelljs/global');
const chalk = require('chalk');
const PACKAGE = `ngx-infinite-scroll`;
const NPM_DIR = `dist`;
const MODULES_DIR = `${NPM_DIR}/modules`;
const BUNDLES_DIR = `${NPM_DIR}/bundles`;
echo('Start building...');
rm(`-Rf`, `${NPM_DIR}/*`);
mkdir(`-p`, `./${MODULES_DIR}`);
mkdir(`-p`, `./${BUNDLES_DIR}`);
/* TSLint with Codelyzer */
// https://github.com/palantir/tslint/blob/master/src/configs/recommended.ts
// https://github.com/mgechev/codelyzer
echo(`Start TSLint`);
exec(`tslint --project ./tsconfig.json --type-check ./src/**/*.ts`);
echo(chalk.green(`TSLint completed`));
/* Aot compilation: ES2015 sources */
echo(`Start AoT compilation`);
exec(`ngc -p tsconfig-build.json`);
echo(chalk.green(`AoT compilation completed`));
/* Creates bundles: ESM/ES5 and UMD bundles */
echo(`Start bundling`);
echo(`Rollup package`);
exec(`rollup -i ${NPM_DIR}/${PACKAGE}.js -o ${MODULES_DIR}/${PACKAGE}.js --sourcemap`, {silent: true});
exec(`node scripts/map-sources -f ${MODULES_DIR}/${PACKAGE}.js`);
echo(`Downleveling ES2015 to ESM/ES5`);
cp(`${MODULES_DIR}/${PACKAGE}.js`, `${MODULES_DIR}/${PACKAGE}.es5.ts`);
exec(`tsc ${MODULES_DIR}/${PACKAGE}.es5.ts --target es5 --module es2015 --noLib --sourceMap`, {silent: true});
exec(`node scripts/map-sources -f ${MODULES_DIR}/${PACKAGE}.es5.js`);
rm(`-f`, `${MODULES_DIR}/${PACKAGE}.es5.ts`);
echo(`Run Rollup conversion on package`);
exec(`rollup -c rollup.config.js --sourcemap`, {silent: true});
exec(`node scripts/map-sources -f ${BUNDLES_DIR}/${PACKAGE}.umd.js`);
echo(`Minifying`);
cd(`${BUNDLES_DIR}`);
exec(`uglifyjs -c --screw-ie8 --comments -o ${PACKAGE}.umd.min.js --source-map ${PACKAGE}.umd.min.js.map --source-map-include-sources ${PACKAGE}.umd.js`, {silent: true});
exec(`node ../../scripts/map-sources -f ${PACKAGE}.umd.min.js`);
cd(`..`);
cd(`..`);
echo(chalk.green(`Bundling completed`));
rm(`-Rf`, `${NPM_DIR}/*.js`);
rm(`-Rf`, `${NPM_DIR}/*.js.map`);
rm(`-Rf`, `${NPM_DIR}/src/**/*.js`);
rm(`-Rf`, `${NPM_DIR}/src/**/*.js.map`);
cp(`-Rf`, [`package.json`, `LICENSE`, `README.md`], `${NPM_DIR}`);
echo(chalk.green(`End building`));

View File

@ -1,4 +1,4 @@
# Editor configuration, see https://editorconfig.org
# Editor configuration, see http://editorconfig.org
root = true
[*]
@ -8,9 +8,6 @@ indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

42
examples/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db

27
examples/README.md Normal file
View File

@ -0,0 +1,27 @@
# NgxExamples
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.1.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

132
examples/angular.json Normal file
View File

@ -0,0 +1,132 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ngx-examples": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
"src/favicon.ico"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ngx-examples:build"
},
"configurations": {
"production": {
"browserTarget": "ngx-examples:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "ngx-examples:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"karmaConfig": "./karma.conf.js",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"scripts": [],
"styles": [
"src/styles.css"
],
"assets": [
"src/assets",
"src/favicon.ico"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"ngx-examples-e2e": {
"root": "",
"sourceRoot": "",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "./protractor.conf.js",
"devServerTarget": "ngx-examples:serve"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "ngx-examples",
"schematics": {
"@schematics/angular:component": {
"prefix": "app",
"styleext": "css"
},
"@schematics/angular:directive": {
"prefix": "app"
}
}
}

View File

@ -0,0 +1,14 @@
// import { AppPage } from './app.po';
// describe('ngx-examples App', () => {
// let page: AppPage;
// beforeEach(() => {
// page = new AppPage();
// });
// it('should display welcome message', () => {
// page.navigateTo();
// expect(page.getParagraphText()).toEqual('Welcome to app!');
// });
// });

11
examples/e2e/app.po.ts Normal file
View File

@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

@ -0,0 +1,14 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@ -9,28 +9,18 @@ module.exports = function (config) {
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
coverageIstanbulReporter: {
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
coverageReporter: {
dir: require('path').join(__dirname, '../../coverage/demo'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
@ -38,7 +28,6 @@ module.exports = function (config) {
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
singleRun: false
});
};

51
examples/package.json Normal file
View File

@ -0,0 +1,51 @@
{
"name": "ngx-examples",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^6.0.2",
"@angular/common": "^6.0.2",
"@angular/compiler": "^6.0.2",
"@angular/core": "^6.0.2",
"@angular/forms": "^6.0.2",
"@angular/http": "^6.0.2",
"@angular/platform-browser": "^6.0.2",
"@angular/platform-browser-dynamic": "^6.0.2",
"@angular/router": "^6.0.2",
"core-js": "^2.4.1",
"rxjs": "6.1.0",
"rxjs-compat": "^6.0.0-rc.0",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@angular/cli": "6.0.3",
"@angular/compiler-cli": "^6.0.2",
"@angular/language-service": "^6.0.2",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.7.0",
"typescript": "~2.7.2",
"@angular-devkit/build-angular": "~0.6.3"
}
}

View File

@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@ -0,0 +1,74 @@
.search-results {
height: 100%;
}
.title {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
color: white;
width: 100%;
}
.title small {
color: #eaeaea;
}
.fixed {
height: 300px;
width: 200px;
overflow: scroll;
display: block;
position: fixed;
transition: width 0.3s ease-out;
}
.fixed:hover {
width: 350px;
}
.fixed .info {
position: fixed;
}
.first {
top: 0;
right: 20px;
background-color: tomato;
}
.second {
bottom: 0;
right: 0px;
background-color: lime;
}
.dummy {
bottom: 0;
right: 200px;
background-color: crimson;
}
.third {
bottom: 0;
right: 400px;
background-color: darkslategrey;
}
.with-error {
top: 0;
right: 220px;
background-color: gray;
}
.inner {
bottom: 0;
right: 600px;
background-color: goldenrod;
}
.test1 {
height: 300px;
overflow: auto;
width: 500px;
}
/* .test2 .content {
display: flex;
} */
.modal-body {
/* max-height: 200px; */
height: 200px;
width: 300px;
overflow: auto;
}

View File

@ -0,0 +1,3 @@
<!--The content below is only a placeholder and can be replaced.-->
<test-inner className="fixed inner" [scrollWindow]="false" [selector]="'.content'" [fromRoot]="false" [info]="'selector inside: .content'">
</test-inner>

View File

@ -0,0 +1,27 @@
// import { TestBed, async } from '@angular/core/testing';
// import { AppComponent } from './app.component';
// describe('AppComponent', () => {
// beforeEach(async(() => {
// TestBed.configureTestingModule({
// declarations: [
// AppComponent
// ],
// }).compileComponents();
// }));
// it('should create the app', async(() => {
// const fixture = TestBed.createComponent(AppComponent);
// const app = fixture.debugElement.componentInstance;
// expect(app).toBeTruthy();
// }));
// it(`should have as title 'app'`, async(() => {
// const fixture = TestBed.createComponent(AppComponent);
// const app = fixture.debugElement.componentInstance;
// expect(app.title).toEqual('app');
// }));
// it('should render title in a h1 tag', async(() => {
// const fixture = TestBed.createComponent(AppComponent);
// fixture.detectChanges();
// const compiled = fixture.debugElement.nativeElement;
// expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
// }));
// });

View File

@ -1,56 +1,58 @@
import { Component, Output, EventEmitter } from '@angular/core';
import { Component } from "@angular/core";
import { ListService } from "./list.service";
import { ViewEncapsulation } from "@angular/core";
@Component({
selector: 'modal',
templateUrl: './modal.html',
selector: "app-root",
encapsulation: ViewEncapsulation.None,
providers: [ListService],
// templateUrl: './app.component.html',
// <test-inner className="inner test1"
// [scrollWindow]="false"
// [fromRoot]="false"
// >
// </test-inner>
// <test-inner
// [scrollWindow]="false"
// className="inner test1"
// ></test-inner>
template: `
<test-inner
className="inner test1"
[scrollWindow]="false"
></test-inner>
`,
styleUrls: ["./app.component.css"]
})
export class ModalComponent {
@Output() onClose = new EventEmitter();
array: number[] = [];
sum = 100;
modalIsOpen = '';
modalTitle = 'scroll to update';
modalBody = modalText;
export class AppComponent {
title = "app";
modalScrollDistance = 2;
modalScrollDistanceUp = 3;
modalScrollThrottle = 50;
modalBody = [modalText];
selector = null;
constructor() {
for (let i = 0; i < this.sum; ++i) {
this.array.push(i);
}
this.open();
}
onScrollDown() {
console.log('scrolled!!');
// add another 20 items
const start = this.sum;
this.sum += 20;
for (let i = start; i < this.sum; ++i) {
this.array.push(i);
}
}
txt = modalText + modalText;
array = [];
onModalScrollDown() {
this.modalTitle = 'updated on ' + new Date().toString();
this.modalBody += modalText;
}
open() {
this.modalIsOpen = 'in modal-open';
console.log("-> DOWN");
this.modalBody = this.modalBody.concat(modalText);
}
close() {
this.modalIsOpen = '';
this.modalBody = modalText;
this.onClose.emit();
onScrollDown(ev) {
this.array.push(modalText[0]);
}
onScrollUp(ev) {
console.log("=> UP");
this.modalBody = [].concat(modalText, this.modalBody.concat());
}
}
var modalText = `Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
const modalText = `Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.

View File

@ -0,0 +1,24 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { InfiniteScrollModule } from '../../../src/ngx-infinite-scroll';
import { AppComponent } from './app.component';
import { TestInnerComponent } from './test.inner';
@NgModule({
declarations: [
AppComponent,
TestInnerComponent
],
imports: [
BrowserModule,
FormsModule,
InfiniteScrollModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,56 @@
import { Injectable } from "@angular/core";
@Injectable()
export class ListService {
array = [];
sum = 40;
direction = "";
constructor() {
this.appendItems(0, this.sum);
}
addItems(startIndex, endIndex, arrMethod) {
// this._array = this._array.concat()
// [;...Array(this.sum);].map((el, i) => {
// this._array[arrMethod]([i, ' ', this.generateWord()].join(''));
// });
// this._array = this._array.slice();
}
appendItems(startIndex, endIndex) {
this.array = this.array.concat(
Array(endIndex)
.fill(0)
.map((el, i) => `${i} -> ${this.generateWord()}`)
);
// this.addItems(startIndex, endIndex, 'push');
}
prependItems(startIndex, endIndex) {
this.array = Array(endIndex)
.fill(0)
.map((el, i) => `${i} -> ${this.generateWord()}`)
.concat(this.array.concat());
// this.addItems(startIndex, endIndex, 'unshift');
}
setDirectionDown() {
const start = this.sum;
this.sum += 10;
this.appendItems(start, this.sum);
this.direction = "down";
}
setDirectionUp() {
const start = this.sum;
this.sum += 10;
this.prependItems(start, this.sum);
this.direction = "up";
}
generateWord() {
return window["chance"].word();
}
}

View File

@ -0,0 +1,62 @@
import { Component, Input } from "@angular/core";
import { ListService } from "./list.service";
// our root app component
@Component({
selector: "test-inner",
providers: [ListService],
template: `
<div class="{{className}}"
[scrollWindow]="scrollWindow"
infiniteScroll
[infiniteScrollContainer]="selector"
[fromRoot]="fromRoot"
[infiniteScrollDistance]="scrollDistance"
[infiniteScrollUpDistance]="scrollUpDistance"
[infiniteScrollThrottle]="throttle"
(scrolled)="onScrollDown()"
(scrolledUp)="onUp()"
>
<section class="content">
<div *ngFor="let i of array()">
{{ i }}
</div>
</section>
</div>
`
})
export class TestInnerComponent {
@Input() scrollWindow = true;
@Input() className = "";
@Input() selector = null;
@Input() fromRoot = false;
@Input() info = "";
throttle = 300;
scrollDistance = 2;
scrollUpDistance = 2;
constructor(public listMaker: ListService) {}
array() {
return this.listMaker.array;
}
onScrollDown(ev) {
// setTimeout(() => {
console.log(`scrolled down, from ${this.className} ${this.info}`);
this.listMaker.setDirectionDown();
// }, 3000);
}
onUp(ev) {
// setTimeout(() => {
console.log(`scrolled up, from ${this.className} ${this.info}`);
this.listMaker.setDirectionUp();
// }, 3000);
}
generateWord() {
return window["chance"].word();
}
}

View File

@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false
};

BIN
examples/src/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -1,13 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Demo</title>
<title>NgxExamples</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.0.4/chance.min.js"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
</html>

View File

@ -9,4 +9,4 @@ if (environment.production) {
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
.catch(err => console.log(err));

66
examples/src/polyfills.ts Normal file
View File

@ -0,0 +1,66 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';
/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@ -1,27 +1,32 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js';
import 'zone.js/testing';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
<T>(id: string): T;
keys(): string[];
};
};
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare const __karma__: any;
declare const require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();

View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,12 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": ["jasmine", "node"]
},
"files": ["test.ts", "polyfills.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}

19
examples/tsconfig.json Normal file
View File

@ -0,0 +1,19 @@
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}

143
examples/tslint.json Normal file
View File

@ -0,0 +1,143 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": true,
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}

82
karma.conf.js Normal file
View File

@ -0,0 +1,82 @@
// Karma configuration for Unit testing
module.exports = function(config) {
var configuration = {
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-webpack'),
require('karma-sourcemap-loader'),
require('karma-spec-reporter')
],
// list of files / patterns to load in the browser
files: [{ pattern: 'spec.bundle.js', watched: false }],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'spec.bundle.js': ['webpack']
},
// webpack
webpack: {
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts/,
loaders: ['ts-loader'],
exclude: /node_modules/
}
],
exprContextCritical: false
},
performance: { hints: false }
},
webpackServer: {
noInfo: true
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['spec'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
};
config.set(configuration);
};

1
ngx-infinite-scroll.ts Normal file
View File

@ -0,0 +1 @@
export * from './public_api';

View File

@ -1,44 +1,85 @@
{
"name": "orizens-ng",
"version": "0.0.0",
"license": "MIT",
"name": "ngx-infinite-scroll",
"version": "6.9.0",
"description": "An infinite scroll directive for Angular compatible with AoT compilation and Tree shaking",
"main": "./bundles/ngx-infinite-scroll.umd.js",
"module": "./modules/ngx-infinite-scroll.es5.js",
"es2015": "./modules/ngx-infinite-scroll.js",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"publish-lib": "npm publish --tag latest ./dist/ngx-infinite-scroll",
"publish:beta": "npm publish --tag next ./dist/ngx-infinite-scroll"
"build": "node build.js",
"test": "karma start",
"test:watch": "karma start --single-run=false",
"pack-lib": "npm pack ./dist",
"publish-lib": "npm publish ./dist",
"publish:beta": "npm publish --tag next ./dist",
"compodoc": "compodoc -p tsconfig.json",
"compodoc-serve": "compodoc -s",
"transpile": "ngc -p ./tsconfig.json",
"serve:prod": "npm run build && lite-server -c ./example/bs-config.json",
"postinstall": "opencollective postinstall"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.1.0",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
"@scarf/scarf": "^1.1.1",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
"typings": "./ngx-infinite-scroll.d.ts",
"author": "Oren Farhi (orizens.com)",
"repository": {
"type": "git",
"url": "https://github.com/orizens/ngx-infinite-scroll.git"
},
"bugs": {
"url": "https://github.com/orizens/ngx-infinite-scroll/issues"
},
"homepage": "https://github.com/orizens/ngx-infinite-scroll",
"keywords": [
"angular",
"javascript",
"typescript"
],
"license": "MIT",
"peerDependencies": {
"@angular/common": ">= 6.0.0",
"@angular/core": ">= 6.0.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~13.1.3",
"@angular/cli": "~13.1.3",
"@angular/compiler-cli": "~13.1.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~3.10.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"ng-packagr": "^13.0.0",
"typescript": "~4.5.2"
"@angular/animations": "^6.0.0",
"@angular/common": "^6.0.0",
"@angular/compiler": "^6.0.0",
"@angular/compiler-cli": "^6.0.0",
"@angular/core": "^6.0.0",
"@angular/platform-browser": "^6.0.0",
"@angular/platform-browser-dynamic": "^6.0.0",
"@angular/platform-server": "^6.0.0",
"@compodoc/compodoc": "^1.1.2",
"@types/jasmine": "2.8.8",
"@types/node": "7.0.10",
"chalk": "1.1.3",
"codelyzer": "^4.3.0",
"core-js": "2.4.1",
"jasmine-core": "2.5.2",
"karma": "1.5.0",
"karma-chrome-launcher": "2.0.0",
"karma-jasmine": "1.1.0",
"karma-sourcemap-loader": "0.3.7",
"karma-spec-reporter": "0.0.30",
"karma-webpack": "2.0.3",
"reflect-metadata": "0.1.10",
"rollup": "0.41.6",
"rxjs": "^6.1.0",
"shelljs": "0.7.7",
"sorcery": "0.10.0",
"ts-helpers": "1.1.2",
"ts-loader": "2.0.3",
"tslint": "4.5.1",
"typescript": "2.7.2",
"uglify-js": "^2.8.15",
"webpack": "2.3.1",
"yargs": "7.0.2",
"zone.js": "^0.8.26"
},
"dependencies": {
"opencollective": "^1.0.3"
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/ngx-infinite-scroll",
"logo": "https://opencollective.com/ngx-infinite-scroll/logo.txt"
}
}

View File

@ -1,16 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

View File

@ -1,347 +0,0 @@
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * Delete the template below * * * * * * * * * * -->
<!-- * * * * * * * to get started with your project! * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<style>
:host {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 14px;
color: #333;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 8px 0;
}
p {
margin: 0;
}
.spacer {
flex: 1;
}
.toolbar {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60px;
display: flex;
align-items: center;
background-color: #1976d2;
color: white;
font-weight: 600;
}
.toolbar img {
margin: 0 16px;
}
.toolbar #twitter-logo {
height: 40px;
margin: 0 8px;
}
.toolbar #youtube-logo {
height: 40px;
margin: 0 16px;
}
.toolbar #twitter-logo:hover,
.toolbar #youtube-logo:hover {
opacity: 0.8;
}
.content {
display: flex;
margin: 82px auto 32px;
padding: 0 16px;
max-width: 960px;
flex-direction: column;
align-items: center;
}
svg.material-icons {
height: 24px;
width: auto;
}
svg.material-icons:not(:last-child) {
margin-right: 8px;
}
.card svg.material-icons path {
fill: #888;
}
.card-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 16px;
}
.card {
all: unset;
border-radius: 4px;
border: 1px solid #eee;
background-color: #fafafa;
height: 40px;
width: 200px;
margin: 0 8px 16px;
padding: 16px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
transition: all 0.2s ease-in-out;
line-height: 24px;
}
.card-container .card:not(:last-child) {
margin-right: 0;
}
.card.card-small {
height: 16px;
width: 168px;
}
.card-container .card:not(.highlight-card) {
cursor: pointer;
}
.card-container .card:not(.highlight-card):hover {
transform: translateY(-3px);
box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35);
}
.card-container .card:not(.highlight-card):hover .material-icons path {
fill: rgb(105, 103, 103);
}
.card.highlight-card {
background-color: #1976d2;
color: white;
font-weight: 600;
border: none;
width: auto;
min-width: 30%;
position: relative;
}
.card.card.highlight-card span {
margin-left: 60px;
}
svg#rocket {
width: 80px;
position: absolute;
left: -10px;
top: -24px;
}
svg#rocket-smoke {
height: calc(100vh - 95px);
position: absolute;
top: 10px;
right: 180px;
z-index: -10;
}
a,
a:visited,
a:hover {
color: #1976d2;
text-decoration: none;
}
a:hover {
color: #125699;
}
.terminal {
position: relative;
width: 80%;
max-width: 600px;
border-radius: 6px;
padding-top: 45px;
margin-top: 8px;
overflow: hidden;
background-color: rgb(15, 15, 16);
}
.terminal::before {
content: "\2022 \2022 \2022";
position: absolute;
top: 0;
left: 0;
height: 4px;
background: rgb(58, 58, 58);
color: #c2c3c4;
width: 100%;
font-size: 2rem;
line-height: 0;
padding: 14px 0;
text-indent: 4px;
}
.terminal pre {
font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
color: white;
padding: 0 1rem 1rem;
margin: 0;
}
.circle-link {
height: 40px;
width: 40px;
border-radius: 40px;
margin: 8px;
background-color: white;
border: 1px solid #eeeeee;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
transition: 1s ease-out;
}
.circle-link:hover {
transform: translateY(-0.25rem);
box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2);
}
footer {
margin-top: 8px;
display: flex;
align-items: center;
line-height: 20px;
}
footer a {
display: flex;
align-items: center;
}
.github-star-badge {
color: #24292e;
display: flex;
align-items: center;
font-size: 12px;
padding: 3px 10px;
border: 1px solid rgba(27,31,35,.2);
border-radius: 3px;
background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%);
margin-left: 4px;
font-weight: 600;
}
.github-star-badge:hover {
background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%);
border-color: rgba(27,31,35,.35);
background-position: -.5em;
}
.github-star-badge .material-icons {
height: 16px;
width: 16px;
margin-right: 4px;
}
svg#clouds {
position: fixed;
bottom: -160px;
left: -230px;
z-index: -10;
width: 1920px;
}
/* Responsive Styles */
@media screen and (max-width: 767px) {
.card-container > *:not(.circle-link) ,
.terminal {
width: 100%;
}
.card:not(.highlight-card) {
height: 16px;
margin: 8px 0;
}
.card.highlight-card span {
margin-left: 72px;
}
svg#rocket-smoke {
right: 120px;
transform: rotate(-5deg);
}
}
@media screen and (max-width: 575px) {
svg#rocket-smoke {
display: none;
visibility: hidden;
}
}
</style>
<!-- Toolbar -->
<div class="toolbar" role="banner">
<img
width="40"
alt="Angular Logo"
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
/>
<span>Welcome To ngx-infinite-scroll</span>
</div>
<div class="content" role="main">
<!-- Highlight Card -->
<div class="card highlight-card card-small">
</div>
<h1 class="title well">
ngx-infinite-scroll
<section>
<small>items: {{sum}}, now triggering scroll: {{direction}}</small>
</section>
<section>
<button class="btn btn-info" (click)="toggleModal()">Open Infinite Scroll in Modal</button>
</section>
</h1>
<modal *ngIf="modalOpen" (onClose)="toggleModal()"></modal>
<div class="search-results"
infinite-scroll
[infiniteScrollDistance]="scrollDistance"
[infiniteScrollUpDistance]="scrollUpDistance"
[infiniteScrollThrottle]="throttle"
(scrolled)="onScrollDown()"
(scrolledUp)="onUp()">
<p *ngFor="let i of array">
{{ i }}
</p>
</div>
</div>

View File

@ -1,31 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'demo'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('demo');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('demo app is running!');
});
});

View File

@ -1,70 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'demo';
array: string[] = [];
sum = 100;
throttle = 300;
scrollDistance = 1;
scrollUpDistance = 2;
direction = '';
modalOpen = false;
// nisVersion = nisPackage.dependencies["ngx-infinite-scroll"];
constructor() {
this.appendItems(0, this.sum);
}
addItems(startIndex: number, endIndex: number, _method: 'push' | 'unshift') {
for (let i = 0; i < this.sum; ++i) {
const value = [i, ' ', this.generateWord()].join('');
if (_method === 'push') {
this.array.push(value);
} else {
this.array.unshift(value);
}
}
}
appendItems(startIndex: number, endIndex: number) {
this.addItems(startIndex, endIndex, 'push');
}
prependItems(startIndex: number, endIndex: number) {
this.addItems(startIndex, endIndex, 'unshift');
}
onScrollDown() {
// console.log('scrolled down!!', ev);
// add another 20 items
const start = this.sum;
this.sum += 20;
this.appendItems(start, this.sum);
this.direction = 'down';
}
onUp() {
// console.log('scrolled up!', ev);
const start = this.sum;
this.sum += 20;
this.prependItems(start, this.sum);
this.direction = 'up';
}
generateWord() {
return Math.random() * 3342411313;
// return chance.word();
}
toggleModal() {
this.modalOpen = !this.modalOpen;
}
}

View File

@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { ModalComponent } from './modal/modal.component';
@NgModule({
declarations: [AppComponent, ModalComponent],
imports: [BrowserModule, InfiniteScrollModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

View File

@ -1,24 +0,0 @@
<div class="modal fade {{ modalIsOpen }}" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="close()"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">{{ modalTitle }}</h4>
</div>
<div class="modal-body"
infinite-scroll
[infiniteScrollDistance]="modalScrollDistance"
[infiniteScrollThrottle]="modalScrollThrottle"
[scrollWindow]="false"
(scrolled)="onModalScrollDown()"
>
<p>
{{ modalBody }}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" (click)="close()">Close</button>
</div>
</div>
</div>
</div>

View File

@ -1,16 +0,0 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

View File

@ -1,53 +0,0 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes recent versions of Safari, Chrome (including
* Opera), Edge on the desktop, and iOS and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@ -1,26 +0,0 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): {
<T>(id: string): T;
keys(): string[];
};
};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -1,17 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/app",
"types": [],
"noImplicitAny": false,
"strict": false,
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}

View File

@ -1,18 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

View File

@ -1,16 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

View File

@ -1,67 +0,0 @@
# Contribute
## Introduction
First, thank you for considering contributing to ngx-infinite-scroll! It's people like you that make the open source community such a great community! 😊
We welcome any type of contribution, not only code. You can help with
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
- **Marketing**: writing blog posts, howto's, printing stickers, ...
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/ngx-infinite-scroll).
## Your First Contribution
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
## Submitting code
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
## Code review process
The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
## Financial contributions
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/ngx-infinite-scroll).
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
## Questions
If you have any questions, create an [issue](issue) (protip: do a quick search first to see if someone else didn't ask the same question before!).
You can also reach us at hello@ngx-infinite-scroll.opencollective.com.
## Credits
### Contributors
Thank you to all the people who have already contributed to ngx-infinite-scroll!
<a href="graphs/contributors"><img src="https://opencollective.com/ngx-infinite-scroll/contributors.svg?width=890" /></a>
### Backers
Thank you to all our backers! [[Become a backer](https://opencollective.com/ngx-infinite-scroll#backer)]
<a href="https://opencollective.com/ngx-infinite-scroll#backers" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/backers.svg?width=890"></a>
### Sponsors
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/ngx-infinite-scroll#sponsor))
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/9/avatar.svg"></a>
<!-- This `CONTRIBUTING.md` is based on @nayafia's template https://github.com/nayafia/contributing-template -->

View File

@ -1,25 +0,0 @@
# NgxInfiniteScroll
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.1.0.
## Code scaffolding
Run `ng generate component component-name --project ngx-infinite-scroll` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-infinite-scroll`.
> Note: Don't forget to add `--project ngx-infinite-scroll` or else it will be added to the default project in your `angular.json` file.
## Build
Run `ng build ngx-infinite-scroll` to build the project. The build artifacts will be stored in the `dist/` directory.
## Publishing
After building your library with `ng build ngx-infinite-scroll`, go to the dist folder `cd dist/ngx-infinite-scroll` and run `npm publish`.
## Running unit tests
Run `ng test ngx-infinite-scroll` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.

View File

@ -1,278 +0,0 @@
[![Build Status](https://travis-ci.org/orizens/ngx-infinite-scroll.svg?branch=master)](https://travis-ci.org/orizens/ngx-infinite-scroll) [![Backers on Open Collective](https://opencollective.com/ngx-infinite-scroll/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/ngx-infinite-scroll/sponsors/badge.svg)](#sponsors)
[![npm version](https://badge.fury.io/js/ngx-infinite-scroll.svg)](https://badge.fury.io/js/ngx-infinite-scroll)
[![npm version](https://badge.fury.io/js/ngx-infinite-scroll.svg)](https://badge.fury.io/js/ngx-infinite-scroll)
[![npm downloads a month](https://img.shields.io/npm/dm/ngx-infinite-scroll.svg)](https://img.shields.io/npm/dm/ngx-infinite-scroll.svg)
[![npm downloads a week](https://img.shields.io/npm/dt/ngx-infinite-scroll.svg)](https://img.shields.io/npm/dt/ngx-infinite-scroll.svg)
## [Consider Becoming a sponsor](https://opencollective.com/ngx-infinite-scroll#sponsor)
# Angular Infinite Scroll
versions now follow Angular's version to easily reflect compatibility.
Meaning, for **Angular 10**, use `ngx-infinite-scroll @ ^10.0.0`
## Angular - Older Versions Support
Starting **Angular 6 and Above** - `ngx-infinite-scroll@THE_VERSION.0.0`
For **Angular 4** and **Angular = ^5.5.6** - use version `ngx-infinite-scroll@0.8.4`
For **Angular 5.x** with **rxjs =<5.5.2** - use version `ngx-infinite-scroll@0.8.3`
For Angular version **<= 2.3.1**, you can use `npm i angular2-infinite-scroll` (latest version is 0.3.42) - please notice **the angular2-infinite-scroll** package is deprecated
## Used By
- [Google](https://google.com)
- [Apple](https://apple.com)
- [Amazon](https://amazon.com)
- [Microsoft](https://microsoft.com)
- [Disney](https://disney.com)
- [Sap](https://sap.com/)
- [Cisco](https://cisco.com/)
- [Yandex](https://yandex.com)
- [Ancestry](https://www.ancestry.com/)
and much more.
> _These analytics are made available via the awesome [Scarf](https://www.npmjs.com/package/@scarf/scarf) package analytics library_
### Opt-Out Of Scarf
Scarf can be disabled by following [these directions](https://github.com/orizens/ngx-infinite-scroll/issues/352#issuecomment-742009046)
## Front End Consulting Services
I'm a Senior Front End Engineer & Consultant at [Orizens](https://orizens.com).
My services include:
- Angular/React/Javascript Consulting
- Front End Architecture Consulting
- Project Code Review
- Project Development
[Contact Here](http://orizens.com/contact)
<a href="https://orizens.com" target="_blank">
<img src="https://cloud.githubusercontent.com/assets/878660/23353771/d0adbd12-fcd6-11e6-96be-7a236f8819d9.png" alt="Webpack and Angular" width="20%"/>
</a>
## Installation
```
npm install ngx-infinite-scroll --save
```
## Supported API
### Properties
| @Input() | Type | Required | Default | Description |
| ------------------------ | -------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| infiniteScrollDistance | number | optional | 2 | the bottom percentage point of the scroll nob relatively to the infinite-scroll container (i.e, 2 (2 \* 10 = 20%) is event is triggered when 80% (100% - 20%) has been scrolled). if container.height is 900px, when the container is scrolled to or past the 720px, it will fire the scrolled event. |
| infiniteScrollUpDistance | number | optional | 1.5 | should get a number |
| infiniteScrollThrottle | number | optional | 150 | should get a number of **milliseconds** for throttle. The event will be triggered this many milliseconds after the user _stops_ scrolling. |
| scrollWindow | boolean | optional | true | listens to the window scroll instead of the actual element scroll. this allows to invoke a callback function in the scope of the element while listenning to the window scroll. |
| immediateCheck | boolean | optional | false | invokes the handler immediately to check if a scroll event has been already triggred when the page has been loaded (i.e. - when you refresh a page that has been scrolled) |
| infiniteScrollDisabled | boolean | optional | false | doesn't invoke the handler if set to true |
| horizontal | boolean | optional | false | sets the scroll to listen for horizontal events |
| alwaysCallback | boolean | optional | false | instructs the scroller to always trigger events |
| infiniteScrollContainer | string / HTMLElement | optional | null | should get a html element or css selector for a scrollable element; window or current element will be used if this attribute is empty. |
| fromRoot | boolean | optional | false | if **infiniteScrollContainer** is set, this instructs the scroller to query the container selector from the root of the **document** object. |
### Events
| @Output() | Type | Event Type | Required | Description |
| ---------- | ------------ | -------------------- | -------- | ------------------------------------------------------------------------------- |
| scrolled | EventEmitter | IInfiniteScrollEvent | optional | this will callback if the distance threshold has been reached on a scroll down. |
| scrolledUp | EventEmitter | IInfiniteScrollEvent | optional | this will callback if the distance threshold has been reached on a scroll up. |
## Behavior
By default, the directive listens to the **window scroll** event and invoked the callback.
**To trigger the callback when the actual element is scrolled**, these settings should be configured:
- [scrollWindow]="false"
- set an explict css "height" value to the element
## DEMO
[Try the Demo in StackBlitz](https://stackblitz.com/edit/ngx-infinite-scroll)
## Usage
First, import the InfiniteScrollModule to your module:
```typescript
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { InfiniteScrollModule } from "ngx-infinite-scroll";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppComponent } from "./app";
@NgModule({
imports: [BrowserModule, InfiniteScrollModule],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule);
```
In this example, the **onScroll** callback will be invoked when the window is scrolled down:
```typescript
import { Component } from "@angular/core";
@Component({
selector: "app",
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()"
></div>
`,
})
export class AppComponent {
onScroll() {
console.log("scrolled!!");
}
}
```
in this example, whenever the "search-results" is scrolled, the callback will be invoked:
```typescript
import { Component } from "@angular/core";
@Component({
selector: "app",
styles: [
`
.search-results {
height: 20rem;
overflow: scroll;
}
`,
],
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
(scrolled)="onScroll()"
[scrollWindow]="false"
></div>
`,
})
export class AppComponent {
onScroll() {
console.log("scrolled!!");
}
}
```
In this example, the **onScrollDown** callback will be invoked when the window is scrolled down and the **onScrollUp** callback will be invoked when the window is scrolled up:
```typescript
import { Component } from "@angular/core";
import { InfiniteScroll } from "ngx-infinite-scroll";
@Component({
selector: "app",
directives: [InfiniteScroll],
template: `
<div
class="search-results"
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollUpDistance]="1.5"
[infiniteScrollThrottle]="50"
(scrolled)="onScrollDown()"
(scrolledUp)="onScrollUp()"
></div>
`,
})
export class AppComponent {
onScrollDown() {
console.log("scrolled down!!");
}
onScrollUp() {
console.log("scrolled up!!");
}
}
```
In this example, the **infiniteScrollContainer** attribute is used to point directive to the scrollable container using a css selector. **fromRoot** is used to determine whether the scroll container has to be searched within the whole document (`[fromRoot]="true"`) or just inside the **infiniteScroll** directive (`[fromRoot]="false"`, default option).
```typescript
import { Component } from "@angular/core";
@Component({
selector: "app",
styles: [
`
.main-panel {
height: 100px;
overflow-y: scroll;
}
`,
],
template: `
<div class="main-panel">
<div
infiniteScroll
[infiniteScrollDistance]="2"
[infiniteScrollThrottle]="50"
[infiniteScrollContainer]="selector"
[fromRoot]="true"
(scrolled)="onScroll()"
></div>
</div>
`,
})
export class AppComponent {
selector: string = ".main-panel";
onScroll() {
console.log("scrolled!!");
}
}
```
It is also possible to use **infiniteScrollContainer** without additional variable by using single quotes inside double quotes:
```
[infiniteScrollContainer]="'.main-panel'"
```
# Showcase Examples
- [Echoes Player - Developed with Angular, angular-cli and ngrx](http://orizens.github.io/echoes-player) ([github repo for echoes player](http://github.com/orizens/echoes-player))
## Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="graphs/contributors"><img src="https://opencollective.com/ngx-infinite-scroll/contributors.svg?width=890" /></a>
## Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/ngx-infinite-scroll#backer)]
<a href="https://opencollective.com/ngx-infinite-scroll#backers" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/backers.svg?width=890"></a>
## Sponsors
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/ngx-infinite-scroll/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ngx-infinite-scroll/sponsor/9/avatar.svg"></a>

View File

@ -1,44 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, '../../coverage/ngx-infinite-scroll'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};

View File

@ -1,8 +0,0 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ngx-infinite-scroll",
"lib": {
"entryFile": "src/public-api.ts"
},
"allowedNonPeerDependencies": ["@scarf/@scarf"]
}

View File

@ -1,19 +0,0 @@
{
"name": "ngx-infinite-scroll",
"version": "13.0.1",
"scripts": {
"postinstall": "opencollective-postinstall || exit 0"
},
"peerDependencies": {
"@angular/common": "^13.1.0",
"@angular/core": "^13.1.0"
},
"dependencies": {
"tslib": "^2.3.0"
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/ngx-infinite-scroll",
"logo": "https://opencollective.com/ngx-infinite-scroll/logo.txt"
}
}

View File

@ -1,16 +0,0 @@
import { TestBed } from '@angular/core/testing';
import { NgxInfiniteScrollService } from './ngx-infinite-scroll.service';
describe('NgxInfiniteScrollService', () => {
let service: NgxInfiniteScrollService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(NgxInfiniteScrollService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -1,9 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class NgxInfiniteScrollService {
constructor() { }
}

View File

@ -1,45 +0,0 @@
import { IScrollState, IScrollerDistance } from '../../models';
export class ScrollState implements IScrollState {
lastScrollPosition = 0;
lastTotalToScroll = 0;
totalToScroll = 0;
triggered: IScrollerDistance = {
down: 0,
up: 0,
};
constructor({ totalToScroll }) {
this.totalToScroll = totalToScroll;
}
updateScrollPosition(position: number) {
return (this.lastScrollPosition = position);
}
updateTotalToScroll(totalToScroll: number) {
if (this.lastTotalToScroll !== totalToScroll) {
this.lastTotalToScroll = this.totalToScroll;
this.totalToScroll = totalToScroll;
}
}
updateScroll(scrolledUntilNow: number, totalToScroll: number) {
this.updateScrollPosition(scrolledUntilNow);
this.updateTotalToScroll(totalToScroll);
}
updateTriggeredFlag(scroll, isScrollingDown: boolean) {
if (isScrollingDown) {
this.triggered.down = scroll;
} else {
this.triggered.up = scroll;
}
}
isTriggeredScroll(totalToScroll, isScrollingDown: boolean) {
return isScrollingDown
? this.triggered.down === totalToScroll
: this.triggered.up === totalToScroll;
}
}

View File

@ -1,14 +0,0 @@
/*
* Public API Surface of ngx-infinite-scroll
*/
export * from './lib/ngx-infinite-scroll.service';
export { InfiniteScrollDirective } from './lib/ngx-infinite-scroll.directive';
export { InfiniteScrollModule } from './lib/ngx-infinite-scroll.module';
export {
ContainerRef,
IInfiniteScrollEvent,
IPositionElements,
IPositionStats,
IResolver,
} from './models';

View File

@ -1,16 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": [],
"noImplicitAny": false,
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}

View File

@ -1,10 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.lib.json",
"compilerOptions": {
"declarationMap": false
},
"angularCompilerOptions": {
"compilationMode": "partial"
}
}

View File

@ -1,17 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine"
]
},
"files": [
"src/test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

13
public_api.ts Normal file
View File

@ -0,0 +1,13 @@
/**
* Angular library starter.
* Build an Angular library compatible with AoT compilation & Tree shaking.
* Written by Roberto Simonetti.
* MIT license.
* https://github.com/robisim74/angular-library-starter
*/
/**
* Entry point for all public APIs of the package.
*/
export * from './src/ngx-infinite-scroll';

20
rollup.config.js Normal file
View File

@ -0,0 +1,20 @@
export default {
entry: './dist/modules/ngx-infinite-scroll.es5.js',
dest: './dist/bundles/ngx-infinite-scroll.umd.js',
format: 'umd',
exports: 'named',
moduleName: 'ng.ngxInfiniteScroll',
external: [
'@angular/core',
'@angular/common',
'rxjs/Observable',
'rxjs/Observer'
],
globals: {
'@angular/core': 'ng.core',
'@angular/common': 'ng.common',
'rxjs/Observable': 'Rx',
'rxjs/Observer': 'Rx'
},
onwarn: () => { return }
}

9
scripts/map-sources.js Normal file
View File

@ -0,0 +1,9 @@
const sorcery = require('sorcery');
var argv = require('yargs')
.alias('f', 'file')
.argv;
sorcery.load(argv.file).then(function(chain) {
chain.write();
});

28
spec.bundle.js Normal file
View File

@ -0,0 +1,28 @@
Error.stackTraceLimit = Infinity;
require('core-js');
require('ts-helpers');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('rxjs');
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(
browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting()
);
var testContext = require.context('./tests', true, /\.spec\.ts/);
function requireAll(requireContext) {
return requireContext.keys().map(requireContext);
}
var modules = requireAll(testContext);

View File

@ -2,7 +2,7 @@ import { ElementRef } from '@angular/core';
export type ContainerRef = Window | ElementRef | any;
export interface IInfiniteScrollEvent {
export interface InfiniteScrollEvent {
currentScrollPosition: number;
}
@ -15,7 +15,6 @@ export interface IPositionStats {
height: number;
scrolled: number;
totalToScroll: number;
isWindow?: boolean;
}
export interface IScrollerDistance {
down?: number;
@ -25,7 +24,10 @@ export interface IScrollerDistance {
export interface IScrollState {
lastTotalToScroll: number;
totalToScroll: number;
triggered: IScrollerDistance;
triggered: {
down: number;
up: number;
};
lastScrollPosition: number;
}
@ -61,5 +63,5 @@ export interface IScrollParams {
export interface IInfiniteScrollAction {
type: string;
payload: IInfiniteScrollEvent;
payload: InfiniteScrollEvent;
}

View File

@ -8,25 +8,21 @@ import {
OnChanges,
OnDestroy,
Output,
SimpleChanges,
SimpleChanges
} from '@angular/core';
import { Subscription } from 'rxjs';
import {Subscription} from 'rxjs';
import { IInfiniteScrollEvent, IInfiniteScrollAction } from '../models';
import { hasWindowDefined, inputPropChanged } from './services/ngx-ins-utils';
import {
createScroller,
InfiniteScrollActions,
} from './services/scroll-register';
import { InfiniteScrollEvent, IInfiniteScrollAction } from '../models';
import { hasWindowDefined, inputPropChanged } from '../services/ngx-ins-utils';
import { createScroller, InfiniteScrollActions } from '../services/scroll-register';
@Directive({
selector: '[infiniteScroll], [infinite-scroll], [data-infinite-scroll]',
selector: '[infiniteScroll], [infinite-scroll], [data-infinite-scroll]'
})
export class InfiniteScrollDirective
implements OnDestroy, OnChanges, AfterViewInit
{
@Output() scrolled = new EventEmitter<IInfiniteScrollEvent>();
@Output() scrolledUp = new EventEmitter<IInfiniteScrollEvent>();
implements OnDestroy, OnChanges, AfterViewInit {
@Output() scrolled = new EventEmitter<InfiniteScrollEvent>();
@Output() scrolledUp = new EventEmitter<InfiniteScrollEvent>();
@Input() infiniteScrollDistance: number = 2;
@Input() infiniteScrollUpDistance: number = 1.5;
@ -39,9 +35,9 @@ export class InfiniteScrollDirective
@Input() alwaysCallback: boolean = false;
@Input() fromRoot: boolean = false;
private disposeScroller: Subscription | any;
private disposeScroller: Subscription;
constructor(private element: ElementRef, private zone: NgZone) {}
constructor(private element: ElementRef, private zone: NgZone) { }
ngAfterViewInit() {
if (!this.infiniteScrollDisabled) {
@ -49,18 +45,12 @@ export class InfiniteScrollDirective
}
}
ngOnChanges({
infiniteScrollContainer,
infiniteScrollDisabled,
infiniteScrollDistance,
}: SimpleChanges) {
ngOnChanges({ infiniteScrollContainer, infiniteScrollDisabled, infiniteScrollDistance }: SimpleChanges) {
const containerChanged = inputPropChanged(infiniteScrollContainer);
const disabledChanged = inputPropChanged(infiniteScrollDisabled);
const distanceChanged = inputPropChanged(infiniteScrollDistance);
const shouldSetup =
(!disabledChanged && !this.infiniteScrollDisabled) ||
(disabledChanged && !infiniteScrollDisabled.currentValue) ||
distanceChanged;
const shouldSetup = (!disabledChanged && !this.infiniteScrollDisabled) ||
(disabledChanged && !infiniteScrollDisabled.currentValue) || distanceChanged;
if (containerChanged || disabledChanged || distanceChanged) {
this.destroyScroller();
@ -83,10 +73,8 @@ export class InfiniteScrollDirective
scrollContainer: this.infiniteScrollContainer,
scrollWindow: this.scrollWindow,
throttle: this.infiniteScrollThrottle,
upDistance: this.infiniteScrollUpDistance,
}).subscribe((payload: any) =>
this.zone.run(() => this.handleOnScroll(payload))
);
upDistance: this.infiniteScrollUpDistance
}).subscribe((payload: any) => this.zone.run(() => this.handleOnScroll(payload)));
});
}
}

View File

@ -1,11 +1,11 @@
import { NgModule } from '@angular/core';
import { InfiniteScrollDirective } from './ngx-infinite-scroll.directive';
import { InfiniteScrollDirective } from './infinite-scroll.directive';
@NgModule({
declarations: [InfiniteScrollDirective],
exports: [InfiniteScrollDirective],
imports: [],
providers: [],
providers: []
})
export class InfiniteScrollModule {}
export class InfiniteScrollModule { }

View File

@ -0,0 +1,11 @@
// Public classes.
export {
ContainerRef,
InfiniteScrollEvent,
IPositionElements,
IPositionStats,
IResolver
} from './models';
export { InfiniteScrollDirective } from './modules/infinite-scroll.directive';
export { InfiniteScrollModule } from './modules/ngx-infinite-scroll.module';

View File

@ -1,7 +1,9 @@
import { IInfiniteScrollEvent, IPositionStats } from '../../models';
import { InfiniteScrollEvent, IPositionStats } from '../models';
export interface IScrollerProps extends IDistanceRange {
export interface IScrollerProps {
container: IPositionStats;
down: number;
up: number;
alwaysCallback: boolean;
disabled: boolean;
}
@ -24,13 +26,6 @@ export interface IScrollConfig {
export function shouldTriggerEvents(
alwaysCallback: boolean,
shouldFireScrollEvent: boolean,
isTriggeredCurrentTotal: boolean
) {
if (alwaysCallback && shouldFireScrollEvent) {
return true;
}
if (!isTriggeredCurrentTotal && shouldFireScrollEvent) {
return true;
}
return false;
isTriggeredCurrentTotal: boolean) {
return (alwaysCallback || shouldFireScrollEvent) && !isTriggeredCurrentTotal;
}

View File

@ -1,16 +1,11 @@
import { ElementRef } from '@angular/core';
import {
ContainerRef,
IPositionElements,
IPositionStats,
IResolver,
} from '../../models';
import { ContainerRef, IPositionElements, IPositionStats, IResolver } from '../models';
import { AxisResolver } from './axis-resolver';
export function createResolver({
windowElement,
axis,
axis
}: IPositionElements): IResolver {
return createResolverWithContainer(
{ axis, isWindow: isElementWindow(windowElement) },
@ -19,7 +14,7 @@ export function createResolver({
}
export function createResolverWithContainer(
resolver: any,
resolver,
windowElement: ContainerRef
) {
const container =
@ -36,10 +31,7 @@ export function isElementWindow(windowElement: ContainerRef): boolean {
return isWindow;
}
export function getDocumentElement(
isContainerWindow: boolean,
windowElement: any
) {
export function getDocumentElement(isContainerWindow: boolean, windowElement) {
return isContainerWindow ? windowElement.document.documentElement : null;
}
@ -75,7 +67,7 @@ export function calculatePointsForWindow(
const totalToScroll =
getElementOffsetTop(element.nativeElement, axis, isWindow) +
nativeElementHeight;
return { height, scrolled, totalToScroll, isWindow };
return { height, scrolled, totalToScroll };
}
export function calculatePointsForElement(
@ -87,20 +79,20 @@ export function calculatePointsForElement(
// perhaps use container.offsetTop instead of 'scrollTop'
const scrolled = container[axis.scrollTopKey()];
const totalToScroll = container[axis.scrollHeightKey()];
return { height, scrolled, totalToScroll, isWindow: false };
return { height, scrolled, totalToScroll };
}
export function extractHeightPropKeys(axis: AxisResolver) {
return {
offsetHeightKey: axis.offsetHeightKey(),
clientHeightKey: axis.clientHeightKey(),
clientHeightKey: axis.clientHeightKey()
};
}
export function extractHeightForElement({
container,
isWindow,
axis,
axis
}: IResolver) {
const { offsetHeightKey, clientHeightKey } = extractHeightPropKeys(axis);
return getElementHeight(
@ -150,7 +142,7 @@ export function getElementPageYOffset(
const scrollTop = axis.scrollTopKey();
const offsetTop = axis.offsetTopKey();
if (isNaN(window.pageYOffset)) {
if (isNaN(window[pageYOffset])) {
return getDocumentElement(isWindow, elem)[scrollTop];
} else if (elem.ownerDocument) {
return elem.ownerDocument.defaultView[pageYOffset];

View File

@ -1,14 +1,25 @@
import { Observable, of, fromEvent } from 'rxjs';
import { map, mergeMap, tap, throttleTime, filter } from 'rxjs/operators';
import {
map,
mergeMap,
tap,
sampleTime,
filter,
pairwise
} from 'rxjs/operators';
import * as Models from '../../models';
import * as Models from '../models';
import { AxisResolver } from './axis-resolver';
import { shouldTriggerEvents } from './event-trigger';
import { shouldTriggerEvents, IScrollConfig } from './event-trigger';
import { resolveContainerElement } from './ngx-ins-utils';
import { calculatePoints, createResolver } from './position-resolver';
import * as ScrollResolver from './scroll-resolver';
import { ScrollState } from './scroll-state';
export interface IScrollEvent {
contentHeight: number;
scrolledFromTop: number;
viewportHeight: number;
}
export function createScroller(config: Models.IScroller) {
const { scrollContainer, scrollWindow, element, fromRoot } = config;
const resolver = createResolver({
@ -18,21 +29,35 @@ export function createScroller(config: Models.IScroller) {
scrollWindow,
element,
fromRoot
),
});
const scrollState = new ScrollState({
totalToScroll: calculatePoints(element, resolver),
)
});
const { totalToScroll: startWithTotal } = calculatePoints(element, resolver);
const scrollState: Models.IScrollState = {
lastScrollPosition: 0,
lastTotalToScroll: 0,
totalToScroll: startWithTotal,
triggered: {
down: 0,
up: 0
}
};
const options: Models.IScrollRegisterConfig = {
container: resolver.container,
throttle: config.throttle,
throttle: config.throttle
};
const distance = {
up: config.upDistance,
down: config.downDistance,
down: config.downDistance
};
return attachScrollEvent(options).pipe(
mergeMap(() => of(calculatePoints(element, resolver))),
map(({ target }: { target: HTMLElement }) => ({
contentHeight: target.scrollHeight,
scrolledFromTop: target.scrollTop,
viewportHeight: target.clientHeight
})),
pairwise(),
tap(ev => console.log(ev)),
mergeMap((ev: any) => of(calculatePoints(element, resolver))),
map((positionStats: Models.IPositionStats) =>
toInfiniteScrollParams(
scrollState.lastScrollPosition,
@ -40,19 +65,32 @@ export function createScroller(config: Models.IScroller) {
distance
)
),
tap(({ stats }: Models.IScrollParams) =>
scrollState.updateScroll(stats.scrolled, stats.totalToScroll)
tap(({ stats, scrollDown }: Models.IScrollParams) =>
ScrollResolver.updateScrollState(
scrollState,
stats.scrolled,
stats.totalToScroll
)
),
filter(
({ fire, scrollDown, stats: { totalToScroll } }: Models.IScrollParams) =>
shouldTriggerEvents(
config.alwaysCallback,
fire,
scrollState.isTriggeredScroll(totalToScroll, scrollDown)
ScrollResolver.isTriggeredScroll(
totalToScroll,
scrollState,
scrollDown
)
)
),
tap(({ scrollDown, stats: { totalToScroll } }: Models.IScrollParams) => {
scrollState.updateTriggeredFlag(totalToScroll, scrollDown);
ScrollResolver.updateTriggeredFlag(
totalToScroll,
scrollState,
true,
scrollDown
);
}),
map(toInfiniteScrollAction)
);
@ -64,17 +102,11 @@ export function attachScrollEvent(
let obs = fromEvent(options.container, 'scroll');
// For an unknown reason calling `sampleTime()` causes trouble for many users, even with `options.throttle = 0`.
// Let's avoid calling the function unless needed.
// Replacing with throttleTime seems to solve the problem
// See https://github.com/orizens/ngx-infinite-scroll/issues/198
if (options.throttle) {
obs = obs.pipe(
throttleTime(options.throttle, undefined, {
leading: true,
trailing: true,
})
);
obs = obs.pipe(sampleTime(options.throttle));
}
return obs as any;
return obs;
}
export function toInfiniteScrollParams(
@ -90,13 +122,13 @@ export function toInfiniteScrollParams(
return {
scrollDown,
fire,
stats,
stats
};
}
export const InfiniteScrollActions = {
DOWN: '[NGX_ISE] DOWN',
UP: '[NGX_ISE] UP',
UP: '[NGX_ISE] UP'
};
export function toInfiniteScrollAction(
@ -104,12 +136,12 @@ export function toInfiniteScrollAction(
): Models.IInfiniteScrollAction {
const {
scrollDown,
stats: { scrolled: currentScrollPosition },
stats: { scrolled: currentScrollPosition }
} = response;
return {
type: scrollDown ? InfiniteScrollActions.DOWN : InfiniteScrollActions.UP,
payload: {
currentScrollPosition,
},
currentScrollPosition
}
};
}

View File

@ -1,8 +1,8 @@
import { IPositionStats, IScrollState, IScrollerDistance } from '../../models';
import { IPositionStats, IScrollState, IScrollerDistance } from '../models';
export function shouldFireScrollEvent(
container: IPositionStats,
distance: IScrollerDistance = { down: 0, up: 0 },
distance: IScrollerDistance,
scrollingDown: boolean
) {
let remaining: number;
@ -10,21 +10,16 @@ export function shouldFireScrollEvent(
if (container.totalToScroll <= 0) {
return false;
}
const scrolledUntilNow = container.isWindow
? container.scrolled
: container.height + container.scrolled;
const scrolledUntilNow = container.height + container.scrolled;
if (scrollingDown) {
remaining =
(container.totalToScroll - scrolledUntilNow) / container.totalToScroll;
const distanceDown = distance?.down ? distance.down : 0;
containerBreakpoint = distanceDown / 10;
containerBreakpoint = distance.down / 10;
} else {
const totalHiddenContentHeight =
container.scrolled + (container.totalToScroll - scrolledUntilNow);
remaining = container.scrolled / totalHiddenContentHeight;
const distanceUp = distance?.up ? distance.up : 0;
containerBreakpoint = distanceUp / 10;
containerBreakpoint = distance.up / 10;
}
const shouldFireEvent: boolean = remaining <= containerBreakpoint;
@ -46,7 +41,7 @@ export function getScrollStats(
const scrollDown = isScrollingDownwards(lastScrollPosition, container);
return {
fire: shouldFireScrollEvent(container, distance, scrollDown),
scrollDown,
scrollDown
};
}
@ -72,7 +67,7 @@ export function isSameTotalToScroll(scrollState: IScrollState) {
}
export function updateTriggeredFlag(
scroll: number,
scroll,
scrollState: IScrollState,
triggered: boolean,
isScrollingDown: boolean
@ -85,7 +80,7 @@ export function updateTriggeredFlag(
}
export function isTriggeredScroll(
totalToScroll: number,
totalToScroll,
scrollState: IScrollState,
isScrollingDown: boolean
) {

View File

@ -1,7 +1,4 @@
import {
IScrollerProps,
shouldTriggerEvents
} from '../../src/services/event-trigger';
import { IScrollerProps, shouldTriggerEvents } from '../../src/services/event-trigger';
const props = {
alwaysCallback: true,
@ -13,6 +10,24 @@ const props = {
describe('EventTrigger', () => {
[
{
it: 'should return TRUE when alwaysCallback',
params: {
alwaysCallback: true,
shouldFireScrollEvent: false,
isTriggeredTotal: false
},
expected: true
},
{
it: 'should return FALSE when alwaysCallback, isTriggeredTotal',
params: {
alwaysCallback: true,
shouldFireScrollEvent: false,
isTriggeredTotal: true
},
expected: false
},
{
it: 'should return TRUE when alwaysCallback, shouldFireScrollEvent',
params: {
@ -23,32 +38,13 @@ describe('EventTrigger', () => {
expected: true
},
{
it: 'should return FALSE when alwaysCallback, NOT shouldFireScrollEvent',
params: {
alwaysCallback: true,
shouldFireScrollEvent: false,
isTriggeredTotal: true
},
expected: false
},
{
it: 'should return FALSE when alwaysCallback',
params: {
alwaysCallback: true,
shouldFireScrollEvent: false,
isTriggeredTotal: false
},
expected: false
},
{
it:
'should return TRUE when alwaysCallback, shouldFireScrollEvent, isTriggeredTotal',
it: 'should return FALSE when alwaysCallback, shouldFireScrollEvent, isTriggeredTotal',
params: {
alwaysCallback: true,
shouldFireScrollEvent: true,
isTriggeredTotal: true
},
expected: true
expected: false
},
{
it: 'should return TRUE when shouldFireScrollEvent ONLY',
@ -69,8 +65,7 @@ describe('EventTrigger', () => {
expected: false
},
{
it:
'should return FALSE when not alwaysCallback, shouldFireScrollEvent is false',
it: 'should return FALSE when not alwaysCallback, shouldFireScrollEvent is false',
params: {
alwaysCallback: false,
shouldFireScrollEvent: false,
@ -87,18 +82,10 @@ describe('EventTrigger', () => {
},
expected: false
}
].forEach(spec => {
].forEach((spec) => {
it(spec.it, () => {
const {
isTriggeredTotal,
alwaysCallback,
shouldFireScrollEvent
} = spec.params;
const actual = shouldTriggerEvents(
alwaysCallback,
shouldFireScrollEvent,
isTriggeredTotal
);
const { isTriggeredTotal, alwaysCallback, shouldFireScrollEvent } = spec.params;
const actual = shouldTriggerEvents(alwaysCallback, shouldFireScrollEvent, isTriggeredTotal);
expect(actual).toBe(spec.expected);
});
});

25
tsconfig-build.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"experimentalDecorators": true,
"module": "es2015",
"moduleResolution": "node",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"inlineSources": false,
"target": "es2015",
"skipLibCheck": true,
"lib": ["es2015", "dom"]
},
"exclude": ["node_modules", "examples", "dist"],
"files": ["public_api.ts"],
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"annotateForClosureCompiler": true,
"strictMetadataEmit": true,
"flatModuleOutFile": "ngx-infinite-scroll.js",
"flatModuleId": "ngx-infinite-scroll"
}
}

View File

@ -1,38 +1,30 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"paths": {
"ngx-infinite-scroll": [
"dist/ngx-infinite-scroll/ngx-infinite-scroll",
"dist/ngx-infinite-scroll"
]
"compilerOptions": {
"baseUrl": ".",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": false,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"rootDir": ".",
"inlineSources": true,
"lib": [
"es6",
"dom"
],
"target": "es5",
"skipLibCheck": true,
"types": [
"jasmine",
"node"
]
},
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2017",
"module": "es2020",
"lib": [
"es2020",
"dom"
"exclude": [
"node_modules",
"example",
"examples",
"dist"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
}

25
tslint.json Normal file
View File

@ -0,0 +1,25 @@
{
"extends": "tslint:recommended",
"rulesDirectory": ["node_modules/codelyzer"],
"rules": {
"directive-selector": [true, "attribute", "camelCase"],
"component-selector": [true, "element", "kebab-case"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-attribute-parameter-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"no-forward-ref": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"no-unused-expression": true,
"component-class-suffix": [true, "Component"],
"directive-class-suffix": [true, "Directive"],
"object-literal-sort-keys": false,
"ordered-imports": [false],
"quotemark": [false],
"trailing-comma": [false],
"member-access": [false, "check-accessor"]
}
}