Skip to content

Commit

Permalink
Merge pull request #352 from dhilt/issue-351-pause-resume-methods
Browse files Browse the repository at this point in the history
Pause/resume methods
  • Loading branch information
dhilt committed Mar 3, 2024
2 parents 1cc73f3 + a3e91d4 commit adf6beb
Show file tree
Hide file tree
Showing 23 changed files with 232 additions and 32 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 Denis Hilt (https://github.com/dhilt)
Copyright (c) 2024 Denis Hilt (https://github.com/dhilt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,18 @@ Below is the list of read-only properties of the Adapter API with descriptions a
|[firstVisible$](https://dhilt.github.io/ngx-ui-scroll/#adapter#first-last-visible-items)|BehaviorSubject<br>&lt;ItemAdapter&lt;MyItem&gt;&gt;|An observable version of "firstVisible" property. |
|[lastVisible](https://dhilt.github.io/ngx-ui-scroll/#adapter#first-last-visible-items)|ItemAdapter&lt;MyItem&gt; {<br>&nbsp;&nbsp;$index:&nbsp;number;<br>&nbsp;&nbsp;data:&nbsp;MyItem;<br>&nbsp;&nbsp;element?:&nbsp;HTMLElement;<br>}|Object of ItemAdapter type containing information about last visible item. |
|[lastVisible$](https://dhilt.github.io/ngx-ui-scroll/#adapter#first-last-visible-items)|BehaviorSubject<br>&lt;ItemAdapter&lt;MyItem&gt;&gt;|An observable version of "lastVisible" property. |
|[paused](https://dhilt.github.io/ngx-ui-scroll/#adapter#pause-resume)|boolean|Indicates whether the Scroller is paused ot not. |
|[paused$](https://dhilt.github.io/ngx-ui-scroll/#adapter#pause-resume)|Subject&lt;boolean&gt;|An Observable version of "paused" property. |

Below is the list of invocable methods of the Adapter API with description and links to demos.

|Name|Parameters|Description|
|:--|:----|:----------|
|[relax](https://dhilt.github.io/ngx-ui-scroll/#adapter#relax)|(callback?: Function)|Resolves asynchronously when there are no pending processes. If the _callback_ is set, it will be executed right before resolving. Basically, it needs to protect with the _relax_ every piece of the App logic, that might be sensitive to the internal processes of the Scroller, to avoid interference and race conditions. |
|[relax](https://dhilt.github.io/ngx-ui-scroll/#adapter#relax)|(callback?: Function)|Resolves asynchronously when there are no pending processes. If the _callback_ is set, it will be executed right before resolving. Basically, it needs to protect with the _relax_ every piece of the App logic, that might be sensitive to the internal processes of the Scroller, to avoid interference and race conditions. Also, every Adapter method returns the same promise as the _relax_ method, so for example, explicitly waiting for the async result of the _append_ method is equivalent to waiting for the async result of the _relax_ method right after synchronous calling the _append_ method. |
|[reload](https://dhilt.github.io/ngx-ui-scroll/#adapter#reload)|(startIndex?:&nbsp;number)|Resets the items buffer, resets the viewport params and starts fetching items from _startIndex_ (if set). |
|[reset](https://dhilt.github.io/ngx-ui-scroll/#adapter#reset)|(datasource?: IDatasource)|Performs hard reset of the Scroller's internal state by re-instantiating all its entities (instead of reusing them when _reload_). If _datasource_ argument is passed, it will be treated as new Datasource. All props of the _datasource_ are optional and the result Datasource will be a combination (merge) of the original one and the one passed as an argument. |
|[pause](https://dhilt.github.io/ngx-ui-scroll/#adapter#pause-resume)| |Pauses the Scroller, so the scroll events are not processed by the engine. Also, when paused, the Adapter methods do nothing but resolve immediately without affecting UI (except Adapter.resume and Adapter.reset). |
|[resume](https://dhilt.github.io/ngx-ui-scroll/#adapter#pause-resume)| |Resumes the Scroller if it was paused. |
|[check](https://dhilt.github.io/ngx-ui-scroll/#adapter#check-size)| |Checks if any of current items changed it's size and runs a procedure to provide internal consistency and new items fetching if needed. |
|[clip](https://dhilt.github.io/ngx-ui-scroll/#adapter#clip)|(options: {<br>&nbsp;&nbsp;forwardOnly?:&nbsp;boolean,<br>&nbsp;&nbsp;backwardOnly?:&nbsp;boolean<br>})|Removes out-of-viewport items on demand. The direction in which invisible items should be clipped can be specified by passing an options object. If no options is passed (or both properties are set to _true_), clipping will occur in both directions. |
|[append](https://dhilt.github.io/ngx-ui-scroll/#adapter#append-prepend)|(options: {<br>&nbsp;&nbsp;items:&nbsp;MyItem[],<br>&nbsp;&nbsp;eof?:&nbsp;boolean<br>&nbsp;&nbsp;decrease?:&nbsp;boolean<br>})|Adds _items_ to the end of the Scroller's buffer/dataset. If _eof_ flag is not set, items will be inserted right after the last buffered item and rendered immediately. If _eof_ is _true_, rendering will occur only if the right border of the buffer matches the right border of the dataset (end-of-file is reached); otherwise, items will be virtualized as appended to the end of the dataset. Indexes increase by default. If _decrease_ is set to true, indexes are decremented. See also [bof/eof](https://dhilt.github.io/ngx-ui-scroll/#adapter#bof-eof). |
Expand Down Expand Up @@ -283,4 +287,4 @@ Any support and participation are welcome, so feel free to <a href="https://gith

__________

2023 &copy; dhilt, [Hill30 Inc](http://www.hill30.com/)
2024 &copy; dhilt
2 changes: 2 additions & 0 deletions demo/app/demos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { DemoRemoveComponent } from './samples/adapter/remove.component';
import { DemoReplaceComponent } from './samples/adapter/replace.component';
import { DemoClipComponent } from './samples/adapter/clip.component';
import { DemoUpdateComponent } from './samples/adapter/update.component';
import { DemoPauseResumeComponent } from './samples/adapter/pause-resume.component';

import { DemoViewportElementSettingComponent } from './samples/experimental/viewportElement-setting.component';
import { DemoInverseSettingComponent } from './samples/experimental/inverse-setting.component';
Expand Down Expand Up @@ -75,6 +76,7 @@ const adapter = [
DemoAdapterReturnValueComponent,
DemoResetComponent,
DemoReloadComponent,
DemoPauseResumeComponent,
DemoInitComponent,
DemoIsLoadingComponent,
DemoPackageInfoComponent,
Expand Down
5 changes: 5 additions & 0 deletions demo/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ const adapterMethodsScope = {
name: 'Reset',
scope: globalScope.adapter.id
},
pauseResume: {
id: 'pause-resume',
name: 'Pause / resume',
scope: globalScope.adapterMethods.id
},
check: {
id: 'check-size',
name: 'Check size',
Expand Down
10 changes: 2 additions & 8 deletions demo/app/samples/adapter.component.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
<h1>Angular UI Scroll Adapter Demos</h1>

<p>
<em>Adapter</em> is&nbsp;a&nbsp;special object to&nbsp;assess and manipulate
the Scroller. The API it&nbsp;provides is&nbsp; discussed on&nbsp;this page.
In order to get an access to the <em>Adapter</em> API, the
<em>Datasource</em> has to be instantiated via operator <em>new</em>:
</p>

<pre>{{ datasourceSample }}</pre>

<p>
For better typings it is recommended to provide also data item type argument:
</p>

<pre>{{ datasourceTypedSample }}</pre>

<p>
The constructor argument is&nbsp;an&nbsp;object of&nbsp;<em>IDatasource</em>
type which must include <em>get</em> method property and may include
Expand All @@ -24,7 +19,6 @@ <h1>Angular UI Scroll Adapter Demos</h1>
we&nbsp;may access <em>this.datasource.adapter</em> property object with its
API methods and properties.
</p>

<app-demo-init></app-demo-init>
<app-demo-package-info></app-demo-package-info>
<app-demo-is-loading></app-demo-is-loading>
Expand All @@ -33,16 +27,16 @@ <h1>Angular UI Scroll Adapter Demos</h1>
<app-demo-buffer-info></app-demo-buffer-info>
<app-demo-bof-eof></app-demo-bof-eof>
<app-demo-first-last-visible-items></app-demo-first-last-visible-items>

<app-demo-adapter-return-value></app-demo-adapter-return-value>
<app-adapter-relax></app-adapter-relax>
<app-demo-reload></app-demo-reload>
<app-demo-reset></app-demo-reset>
<app-demo-pause-resume></app-demo-pause-resume>
<app-demo-check-size></app-demo-check-size>
<app-demo-clip></app-demo-clip>
<app-demo-append-prepend></app-demo-append-prepend>
<app-demo-append-prepend-sync></app-demo-append-prepend-sync>
<app-demo-insert></app-demo-insert>
<app-demo-remove></app-demo-remove>
<app-demo-replace></app-demo-replace>
<app-demo-update></app-demo-update>
<app-demo-update></app-demo-update>
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/adapter-relax.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</p>
<p>
The purpose of the <em>Adapter.relax</em> method is to make sure that the
<em>uiScroll</em> relaxes and there are no pending internal tasks running
Scroller relaxes and there are no pending internal tasks running
on the Scroller's end. The first tab "Relax" demonstrates how the desired
sequence can be implemented with the <em>Adapter.relax</em> method. This
method returns a promise which becomes resolved when the Scroller stops.
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/init.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>
<p>
The second tab (OnPush) implements <em>OnPush</em> strategy with an
additional <em>changeDetector</em> call, whish is required to update the
additional <em>changeDetector</em> call, which is required to update the
view, because initialization is an asynchronous process. If we remove
<em>changeDetector</em> call, we see 3 dots, the initial value.
</p>
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/is-loading-extended.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ constructor() {
{
active: true,
name: DemoSourceType.Template,
text: `The uiScroll is
text: `The Scroller is
{{datasource.adapter.isLoading ? 'loading': 'relaxing'}},
counter {{loadingCounter}}
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/is-loading.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<app-demo [datasource]="datasource" [context]="demoContext" [sources]="sources">
<div actions>
The uiScroll is {{ datasource.adapter.isLoading ? 'loading' : 'relaxing' }}.
The Scroller is {{ datasource.adapter.isLoading ? 'loading' : 'relaxing' }}.
<br />
The value of isLoading counter has been changed for
{{ isLoadingCounter }} times.
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/is-loading.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ constructor() {
{
active: true,
name: DemoSourceType.Template,
text: `The uiScroll is
text: `The Scroller is
{{datasource.adapter.isLoading ? 'loading': 'relaxing'}}.
<br>
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/items-count.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<app-demo [datasource]="datasource" [context]="demoContext" [sources]="sources">
<div actions>The Buffer has {{ datasource.adapter.itemsCount }} items.</div>
<div actions>The Scroller's buffer has {{ datasource.adapter.itemsCount }} items.</div>
<div description>
<p>
We may use <em>Adapter.itemsCount</em> read-only property to see how many
Expand Down
2 changes: 1 addition & 1 deletion demo/app/samples/adapter/items-count.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class DemoItemsCountComponent {
{
active: true,
name: DemoSourceType.Template,
text: `The uiScroll buffer has
text: `The Scroller's buffer has
{{datasource.adapter.itemsCount}} items.
<div class="viewport">
Expand Down
23 changes: 23 additions & 0 deletions demo/app/samples/adapter/pause-resume.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<app-demo [datasource]="datasource" [context]="demoContext" [sources]="sources">
<div actions>
<button (click)="datasource.adapter.pause()">Pause</button>
<button (click)="datasource.adapter.resume()">Resume</button>
Scroller is {{ datasource.adapter.paused ? 'paused' : 'not paused' }}
</div>
<div description>
<p>
The <em>Adapter.pause</em> method is to stop the Scroller.
When paused, it doesn't receive the scroll events from the viewport,
so the scroll events are ignored. Also, all the Adapter methods
(except <em>Adapter.resume</em> and <em>Adapter.reset</em>) don't do anything.
The <em>Adapter.resume</em> method is to make the Scroller live again.
</p>
<p>
In addition to the <em>pause</em>/<em>resume</em> methods, there is
a read-only property, <em>Adapter.paused</em>, that reports whether
the Scroller is paused or not.
Along with the scalar property, there is also a reactive one:
<em>Adapter.paused$</em>.
</p>
</div>
</app-demo>
66 changes: 66 additions & 0 deletions demo/app/samples/adapter/pause-resume.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Component } from '@angular/core';

import { demos } from '../../routes';
import { DemoSources, DemoSourceType, MyItem } from '../../shared/interfaces';
import { doLog } from '../../shared/datasource-get';

import { Datasource } from 'ngx-ui-scroll';

@Component({
selector: 'app-demo-pause-resume',
templateUrl: './pause-resume.component.html'
})
export class DemoPauseResumeComponent {
demoContext = {
config: demos.adapterMethods.map.pauseResume,
viewportId: 'pause-resume-viewport',
count: 0,
log: ''
};

datasource = new Datasource({
get: (index, count, success) => {
const data: MyItem[] = [];
for (let i = index; i <= index + count - 1; i++) {
data.push({ id: i, text: 'item #' + i });
}
doLog(this.demoContext, index, count, data.length);
success(data);
}
});

sources: DemoSources = [
{
active: true,
name: DemoSourceType.Template,
text: `<button (click)="datasource.adapter.pause()">Pause</button>
<button (click)="datasource.adapter.resume()">Resume</button>
Scroller is {{ datasource.adapter.paused ? 'paused' : 'not paused' }}
<div class="viewport">
<div *uiScroll="let item of datasource">
<div class="item">{{item.text}}</div>
</div>
</div>`
},
{
name: DemoSourceType.Datasource,
text: `datasource = new Datasource({
get: (index, count, success) => {
const data = [];
for (let i = index; i <= index + count - 1; i++) {
data.push({ id: i, text: 'item #' + i });
}
success(data);
}
}
})`
}
];

argumentDescription = ` onBeforeClip: (items: {
$index: number,
data: any,
element?: HTMLElement
}[]) => void`;
}
5 changes: 3 additions & 2 deletions demo/app/samples/datasource.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ <h1>Angular UI Scroll Datasource Demos</h1>
to&nbsp;the&nbsp;use of&nbsp;<em>*ngFor</em> directive in&nbsp;the simplest
case, but as&nbsp;it&nbsp;follows from the documentation, a&nbsp;special
<em>Datasource</em> object needs to&nbsp;be&nbsp;passed instead of Angular
<em>Iterable</em>. <em>Datasource</em> is&nbsp;an&nbsp;entry point to&nbsp;the
<em>uiScroll</em>, that provides data flow from the host App to the Scroller.
<em>Iterable</em>. <em>Datasource</em> is&nbsp;an&nbsp;entry point
to&nbsp;the&nbsp;virtual scroll engine, that provides data flow
from the&nbsp;host App to&nbsp;the&nbsp;Scroller.
There are two common ways of&nbsp;how the <em>Datasource</em> could
be&nbsp;defined:
</p>
Expand Down
3 changes: 1 addition & 2 deletions demo/app/shared/nav.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@
</div>
<br />
<span class="copyrights">
2023&nbsp;&copy;&nbsp;<a href="https://github.com/dhilt">dhilt</a>,
<a href="http://www.hill30.com/">Hill30&nbsp;Inc</a>
2024&nbsp;&copy;&nbsp;<a href="https://github.com/dhilt">dhilt</a>
<br />
<a
href="https://github.com/dhilt/ngx-ui-scroll?sponsor=1"
Expand Down
12 changes: 6 additions & 6 deletions scroller/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions scroller/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ngx-ui-scroll",
"description": "Virtual scrolling library for Angular applications",
"version": "3.2.0-beta",
"version": "3.2.0",
"license": "MIT",
"author": "Denis Hilt <dhilt.public@gmail.com>",
"homepage": "https://github.com/dhilt/ngx-ui-scroll",
Expand All @@ -18,7 +18,7 @@
"peerDependencies": {
"@angular/common": ">=12.0.0",
"@angular/core": ">=12.0.0",
"vscroll": "1.6.0-beta.3"
"vscroll": "1.6.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^12.0.0",
Expand Down
1 change: 1 addition & 0 deletions scroller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface IReactiveOverride<Item = unknown> {
lastVisible$: BehaviorSubject<IAdapterItem<Item>>;
bof$: Subject<boolean>;
eof$: Subject<boolean>;
paused$: Subject<boolean>;
}

type _Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
Expand Down
3 changes: 2 additions & 1 deletion scroller/src/ui-scroll.datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ const getAdapterConfig = (): IAdapterConfig => ({
[AdapterPropName.firstVisible$]: getItemBehaviorSubjectPropConfig(),
[AdapterPropName.lastVisible$]: getItemBehaviorSubjectPropConfig(),
[AdapterPropName.bof$]: getBooleanSubjectPropConfig(),
[AdapterPropName.eof$]: getBooleanSubjectPropConfig()
[AdapterPropName.eof$]: getBooleanSubjectPropConfig(),
[AdapterPropName.paused$]: getBooleanSubjectPropConfig()
}
});

Expand Down
2 changes: 1 addition & 1 deletion scroller/src/ui-scroll.version.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default {
name: 'ngx-ui-scroll',
version: '3.2.0-beta'
version: '3.2.0'
};
1 change: 1 addition & 0 deletions tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './specs/adapter.append-prepend.spec';
import './specs/adapter.check.spec';
import './specs/adapter.clip.spec';
import './specs/adapter.insert.spec';
import './specs/adapter.pause.spec';
import './specs/adapter.prepend.spec';
import './specs/adapter.reload.spec';
import './specs/adapter.remove.spec';
Expand Down
Loading

0 comments on commit adf6beb

Please sign in to comment.