-
-
Notifications
You must be signed in to change notification settings - Fork 204
feat(template): add DataSource support for rx-virtual-for directive #1764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
View your CI Pipeline Execution ↗ for commit 09270f9.
☁️ Nx Cloud last updated this comment at |
hey @friendlyAce thanks a lot for your contribution! Will make a review over the weekend! |
@@ -251,6 +255,21 @@ export class RxVirtualFor<T, U extends NgIterable<T> = NgIterable<T>> | |||
this.observables$.next( | |||
toObservable(potentialSignalOrObservable, { injector: this.injector }), | |||
); | |||
} else if (this.isDataSource(potentialSignalOrObservable)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't it be potentialSignalOrObservableOrDataSource
now? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll rename it from potentialSignalOrObservable
to potentialSignalOrObservableOrDataSource
@@ -34,6 +34,17 @@ export interface ListRange { | |||
end: number; | |||
} | |||
|
|||
export abstract class DataSource<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you know if it's possible to maybe have an import type { DataSource } from '@angular/cdk'
without having it to mention as peerDependency
?
That would be the absolute best case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hoebbelsB Hmm im not fully sure on that, i tried to have a bit of testing on that but i kept running into a bunch of possibly unrelated issues and stopped checking.
My idea was to use Typescripts "type only imports" e. g. import type { DataSource } from '@angular/cdk/collections
(doc)
As when compiling they should just be dropped out of the dist output files
For that i reverted the DataSource and CollectionViewer declarations which i added in
diff --git a/libs/template/experimental/virtual-scrolling/src/index.ts b/libs/template/experimental/virtual-scrolling/src/index.ts
index 86b34086..8c50f1ed 100644
--- a/libs/template/experimental/virtual-scrolling/src/index.ts
+++ b/libs/template/experimental/virtual-scrolling/src/index.ts
@@ -1,6 +1,4 @@
export {
- CollectionViewer,
- DataSource,
ListRange,
RxVirtualForViewContext,
RxVirtualScrollElement,
diff --git a/libs/template/experimental/virtual-scrolling/src/lib/model.ts b/libs/template/experimental/virtual-scrolling/src/lib/model.ts
index c6ed5c35..aacb1d3e 100644
--- a/libs/template/experimental/virtual-scrolling/src/lib/model.ts
+++ b/libs/template/experimental/virtual-scrolling/src/lib/model.ts
@@ -34,17 +34,6 @@ export interface ListRange {
end: number;
}
-export abstract class DataSource<T> {
- abstract connect(
- collectionViewer: CollectionViewer,
- ): Observable<NgIterable<T>>;
- abstract disconnect(collectionViewer: CollectionViewer): void;
-}
-
-export interface CollectionViewer {
- viewChange: Observable<ListRange>;
-}
-
/**
* @Directive RxVirtualScrollStrategy
*
diff --git a/libs/template/experimental/virtual-scrolling/src/lib/virtual-for.directive.ts b/libs/template/experimental/virtual-scrolling/src/lib/virtual-for.directive.ts
index 174faf3e..14ee2512 100644
--- a/libs/template/experimental/virtual-scrolling/src/lib/virtual-for.directive.ts
+++ b/libs/template/experimental/virtual-scrolling/src/lib/virtual-for.directive.ts
@@ -56,8 +56,6 @@ import {
tap,
} from 'rxjs/operators';
import {
- CollectionViewer,
- DataSource,
ListRange,
RxVirtualForViewContext,
RxVirtualScrollStrategy,
@@ -67,6 +65,10 @@ import {
createVirtualListTemplateManager,
RxVirtualListTemplateManager,
} from './virtual-list-template-manager';
+import type {
+ DataSource,
+ CollectionViewer
+} from '@angular/cdk/collections';
import {
DEFAULT_TEMPLATE_CACHE_SIZE,
RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS,
And instead i used the type only imports directly in virtual-for.directive.ts, e. g.
import type {
DataSource,
CollectionViewer
} from '@angular/cdk/collections';
Therefore, at least for the library build, the @angular/cdk package needs to be resolvable, which it is, as its already part of your package.json dependencies here.
After these changes i ran the build for the template library via npx nx run template:build:production
, which gave me the according dist output dist\libs\template
.
Taking a short look at the compiled .mjs file, indeed the import from @angular/cdk is NOT mentioned (as its a type import)
dist\libs\template\fesm2022\template-experimental-virtual-scrolling.mjs
But when having a look at the compiled type declaration file:
dist\libs\template\experimental\virtual-scrolling\lib\virtual-for.directive.d.ts
It still contains the @angular/cdk import...
import type { DataSource } from '@angular/cdk/collections';
Which could cause an issue for library consumers.
So i wanted to check this and therefore created a new nx angular workspace via
npx create-nx-workspace demo-workspace --preset=angular
And installed the local dist template library via
npm i ../rx-angular/dist/libs/template
package.json => "@rx-angular/template": "file:../rx-angular/dist/libs/template"
I also ensured that the @angular/cdk package is not installed in this new demo-workspace project
Then i creating a small dummy component (similar to this example), that uses the virtual for directive, the viewport etc. to see if the serve and build of that demo application would work or if i would run into some errors related to the missing angular/cdk peer dependency.
But unfortunately my serve had a bunch of unrelated errors in regards of type conflicts of rxjs
Type 'import("DEMO-WORKSPACE/node_modules/rxjs/dist/types/internal/Observable").Observable<any> | undefined' is not assignable to type 'import("rx-angular/node_modules/rxjs/dist/types/internal/Observable").Observable<any> | undefined'.
Types of property 'operator' are incompatible.
Which is a classic issue when using local packages, as the workspaces have their own node_modules directories with their own rxjs installations, which TS sees as incompatible
So instead i used npm links
npm uninstall @rx-angular/cdk @rx-angular/template
cd rx-angular/dist/libs/template
npm link
cd demo-workspace
npm link @rx-angular/template
$ npm ls -g --link=true
C:\Users...\AppData\Roaming\npm
└── @rx-angular/[email protected] -> rx-angular\dist\libs\template
alternatively, removing the rx-angular/node_modules directory also works.
But nevertheless when serving i keep getting this error.
So either something is broken with the local build of the template lib, or something else. After trying a bunch of stuff, i couldn't get this fixed and therefore couldn't properly check if this approach would work for library consumers.
But i would probably still expect, something like "Cannot find module '@angular/cdk/collections' or its corresponding type declarations" when somebody uses the rx-angular/template library, without them having the angular cdk package also installed
this._destroy$.pipe(take(1)).subscribe(() => { | ||
potentialSignalOrObservable.disconnect(collectionViewer); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not a big fan of that. We should do the disconnect
in ngOnDestroy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the connectedDataSource
and collectionViewer
properties for being able to reference the objects
I also added disconnectDataSource()
now, which does the clean up for the data source instead of doing it with the subscription to _destroy$.
disconnectDataSource
will now be invoked in the ngOnDestroy
lifecycle hook
I also added that on new input changes to rxVirtualForOf
, the previous data source gets disconnected, in case the user does not destroy the component, but re-uses it and just updates the input with a new data source implementation instead)
value !== null && | ||
value !== undefined && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't this be shortened with value != null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it can, ill fix it
- Renamed potentialSignalOrObservable to potentialSignalOrObservableOrDataSource - Move DataSource disconnect from subscription to ngOnDestroy lifecycle - Add disconnectDataSource() method for centralized cleanup logic - Ensure disconnect and cleanup of previous data source on data source input changes to prevent memory leaks
Proposal
Link to feature request: #1765
Currently, the rx virtual for directive supports rendering from signal, observable and static iterables. This proposal aims to extends the functionality by adding support for the DataSource interface that is supported in the CdkVirtualForOf of the Angular CDK. The rx virtual for directive could directly connect to and disconnect from the given DataSource when needed.
This PR introduces support for DataSource in rx-virtual-for, aligning with Angular CDK's implementation while leveraging rx-angular's powerful reactive approach.
When users want to use their existing data source implementations they will need to implement the CollectionViewer interface at the component that uses rx virtual for and link the viewRange: ListRange output of that virtual for directive to their DataSource implementation for connecting and passing the returned Observable to rxVirtualFor and handle disconnecting from that data source when needed.
Key features:
Benefits:
Implementation details:
Documentation:
In addition to the implementation details mentioned above, I have declared the necessary types such as DataSource, CollectionViewer, and the isDataSource method within the rx-angular template package itself.
This approach eliminates the need for a (peer) dependency on Angular CDK, ensuring that rx-virtual-for remains self-contained and independent, similar how it was done with the ListRange interface.
Feedback, concerns, improvements are more than welcome
BR,
Vincent