diff --git a/demo/app/samples/test.component.html b/demo/app/samples/test.component.html
index b4b0a82d..29dc3bd2 100644
--- a/demo/app/samples/test.component.html
+++ b/demo/app/samples/test.component.html
@@ -22,7 +22,7 @@
- ngx-ui-scroll version: {{datasource.adapter.version}}
+ ngx-ui-scroll version: {{datasource.adapter.packageInfo.consumer.version}}
isLoading:
{{datasource.adapter.isLoading}}
@@ -47,14 +47,9 @@
-
-
+
{{item.text}}
@@ -63,4 +58,4 @@
-
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index bbf19b23..7d33f964 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,7 +21,7 @@
"ngx-bootstrap": "^8.0.0-RC.5",
"rxjs": "~7.5.1",
"tslib": "^2.3.1",
- "vscroll": "^1.5.4",
+ "vscroll": "^1.5.5",
"zone.js": "~0.11.4"
},
"devDependencies": {
@@ -12846,9 +12846,9 @@
}
},
"node_modules/vscroll": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/vscroll/-/vscroll-1.5.4.tgz",
- "integrity": "sha512-DPXeIJ9PN5SapeasmmYCTGpGNh1Uwjxr3f00zS2pbG1YbXcvKFyTJj4/7PP1b/ihzhqABA+GG+qPAdCA703Grw==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/vscroll/-/vscroll-1.5.5.tgz",
+ "integrity": "sha512-zm7YbxLYH3sp8WXzH0VIiTsu79N3XnYhLCFjAlkslEGxMfKUGI7b7CKMGM4CDbM251qFMqfXSSr82X8U9rqcoA==",
"dependencies": {
"tslib": "^2.3.1"
}
@@ -22743,9 +22743,9 @@
"dev": true
},
"vscroll": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/vscroll/-/vscroll-1.5.4.tgz",
- "integrity": "sha512-DPXeIJ9PN5SapeasmmYCTGpGNh1Uwjxr3f00zS2pbG1YbXcvKFyTJj4/7PP1b/ihzhqABA+GG+qPAdCA703Grw==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/vscroll/-/vscroll-1.5.5.tgz",
+ "integrity": "sha512-zm7YbxLYH3sp8WXzH0VIiTsu79N3XnYhLCFjAlkslEGxMfKUGI7b7CKMGM4CDbM251qFMqfXSSr82X8U9rqcoA==",
"requires": {
"tslib": "^2.3.1"
}
diff --git a/package.json b/package.json
index 17d78552..fe3daa25 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
"ngx-bootstrap": "^8.0.0-RC.5",
"rxjs": "~7.5.1",
"tslib": "^2.3.1",
- "vscroll": "^1.5.4",
+ "vscroll": "^1.5.5",
"zone.js": "~0.11.4"
},
"devDependencies": {
@@ -56,4 +56,4 @@
"puppeteer": "^13.0.1",
"typescript": "~4.5.4"
}
-}
+}
\ No newline at end of file
diff --git a/scroller/package.json b/scroller/package.json
index caa8eb0c..c50052bb 100644
--- a/scroller/package.json
+++ b/scroller/package.json
@@ -1,13 +1,10 @@
{
"name": "ngx-ui-scroll",
- "version": "3.0.2",
+ "version": "3.1.0",
"license": "MIT",
"peerDependencies": {
"@angular/common": ">=12.0.0",
"@angular/core": ">=12.0.0",
- "vscroll": "^1.5.4"
- },
- "dependencies": {
- "tslib": "^2.3.1"
+ "vscroll": "^1.5.5"
}
}
\ No newline at end of file
diff --git a/scroller/src/ui-scroll.component.ts b/scroller/src/ui-scroll.component.ts
index a613b75f..b1350cea 100644
--- a/scroller/src/ui-scroll.component.ts
+++ b/scroller/src/ui-scroll.component.ts
@@ -1,7 +1,7 @@
import {
Component, OnInit, OnDestroy,
TemplateRef, ElementRef,
- ChangeDetectionStrategy, ChangeDetectorRef
+ ChangeDetectionStrategy, ChangeDetectorRef, NgZone
} from '@angular/core';
import { IDatasource, Workflow, Item } from './vscroll';
@@ -43,25 +43,43 @@ export class UiScrollComponent implements OnInit, OnDestroy {
public workflow!: Workflow;
constructor(
- public changeDetector: ChangeDetectorRef,
- public elementRef: ElementRef) { }
+ private changeDetector: ChangeDetectorRef,
+ private elementRef: ElementRef,
+ private ngZone: NgZone
+ ) {}
ngOnInit(): void {
- this.workflow = new Workflow({
- consumer,
- element: this.elementRef.nativeElement,
- datasource: this.datasource as IDatasource,
- run: (items: Item[]) => {
- if (!items.length && !this.items.length) {
- return;
- }
- this.items = items;
- this.changeDetector.detectChanges();
- }
- });
+ // The workflow should be created outside of the Angular zone because it's causing many
+ // change detection cycles. It runs its `init()` function in a `setTimeout` task, which
+ // then sets up the `scroll` listener. The `scroll` event listener would force Angular to
+ // run `tick()` any time the `scroll` task is invoked. We don't care about `scroll` events
+ // since they're handled internally by `vscroll`. We still run change detection manually
+ // tho when the `run` function is invoked.
+ // `scroll` events may be also unpatched through zone.js flags:
+ // `(window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll']`.
+ // Having `runOutsideAngular` guarantees we're responsible for running change detection
+ // only when it's "required" (when `items` are updated and the template should be updated too).
+ this.workflow = this.ngZone.runOutsideAngular(
+ () =>
+ new Workflow({
+ consumer,
+ element: this.elementRef.nativeElement,
+ datasource: this.datasource as IDatasource,
+ run: (items: Item[]) => {
+ if (!items.length && !this.items.length) {
+ return;
+ }
+ // Re-enter the Angular zone only when items are set and when we have to run the local change detection.
+ this.ngZone.run(() => {
+ this.items = items;
+ this.changeDetector.detectChanges();
+ });
+ },
+ })
+ );
}
ngOnDestroy(): void {
- this.workflow && this.workflow.dispose();
+ this.workflow?.dispose();
}
}
diff --git a/scroller/src/ui-scroll.directive.ts b/scroller/src/ui-scroll.directive.ts
index 1c504fcd..dce23db0 100644
--- a/scroller/src/ui-scroll.directive.ts
+++ b/scroller/src/ui-scroll.directive.ts
@@ -1,4 +1,10 @@
-import { Directive, Input, TemplateRef, ViewContainerRef, ComponentFactoryResolver, OnInit } from '@angular/core';
+import {
+ Directive,
+ Input,
+ TemplateRef,
+ ViewContainerRef,
+ OnInit,
+} from '@angular/core';
import { UiScrollComponent } from './ui-scroll.component';
import { IDatasource } from './ui-scroll.datasource';
@@ -9,20 +15,15 @@ export class UiScrollDirective implements OnInit {
constructor(
private templateRef: TemplateRef,
- private viewContainer: ViewContainerRef,
- private resolver: ComponentFactoryResolver
- ) {
- }
+ private viewContainer: ViewContainerRef
+ ) {}
@Input() set uiScrollOf(datasource: IDatasource) {
this.datasource = datasource;
}
ngOnInit(): void {
- const compFactory = this.resolver.resolveComponentFactory(UiScrollComponent);
- const componentRef = this.viewContainer.createComponent(
- compFactory, void 0, this.viewContainer.injector
- );
+ const componentRef = this.viewContainer.createComponent(UiScrollComponent);
componentRef.instance.datasource = this.datasource as IDatasource;
componentRef.instance.template = this.templateRef;
}
diff --git a/scroller/src/ui-scroll.module.ts b/scroller/src/ui-scroll.module.ts
index 094d0185..a72f80fb 100644
--- a/scroller/src/ui-scroll.module.ts
+++ b/scroller/src/ui-scroll.module.ts
@@ -12,6 +12,5 @@ import { UiScrollDirective } from './ui-scroll.directive';
imports: [CommonModule],
entryComponents: [UiScrollComponent],
exports: [UiScrollDirective],
- providers: []
})
export class UiScrollModule { }
diff --git a/scroller/src/ui-scroll.version.ts b/scroller/src/ui-scroll.version.ts
index 497fa0b4..c20c9123 100644
--- a/scroller/src/ui-scroll.version.ts
+++ b/scroller/src/ui-scroll.version.ts
@@ -1,4 +1,4 @@
export default {
name: 'ngx-ui-scroll',
- version: '3.0.2'
+ version: '3.1.0'
};
diff --git a/tests/recreation.spec.ts b/tests/recreation.spec.ts
index bc35ed89..a3e8e8fb 100644
--- a/tests/recreation.spec.ts
+++ b/tests/recreation.spec.ts
@@ -38,18 +38,25 @@ describe('Recreation Spec', () => {
adapterId = misc.adapter.id;
});
- const init = (flag: boolean): Promise =>
- firstValueFrom(
- misc.testComponent.datasource.adapter.init$.pipe(
- filter(v => flag ? v : !v), take(1)
- ));
+ const init = (flag: boolean): boolean | Promise =>
+ (flag !== misc.testComponent.datasource.adapter.init) ?
+ firstValueFrom(
+ misc.testComponent.datasource.adapter.init$.pipe(
+ filter(v => flag ? v : !v), take(1)
+ ))
+ : Promise.resolve(flag);
const ngIfReload = async (onBeforeHide?: () => void): Promise => {
await init(true);
await misc.adapter.relax();
+
+ // hide test component
onBeforeHide && onBeforeHide();
misc.testComponent.show = false;
+ misc.fixture.changeDetectorRef.detectChanges();
await init(false);
+
+ // show test component
misc.testComponent.show = true;
misc.fixture.changeDetectorRef.detectChanges();
await init(true);