Skip to content
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

feat(module:table): handle CDK DataSource for virtual scroll #3766

Closed
wants to merge 4 commits into from

Conversation

lppedd
Copy link
Contributor

@lppedd lppedd commented Jul 10, 2019

Opening this PR for discussion only at the moment.
This is the minimal implementation to support the use of a DataSource.
I need this functionality for a product I'm developing and this would be sufficient at the moment.
I'm especially worried about the problem described in this comment.

What is missing

  • Skeleton while loading data.
    Example:
    Peek 11-07-2019 16-34
  • Warning when using incompatible inputs (e.g. DataSource and non-virtual scroll)

As a next step, I'd like to leverage the DataSource itself, to produce a uniform implementation.
This means if a user passes in [nzData]="[...]", I'll wrap it around an ArrayDataSource.
This would mean an overall cleaner implementation, maybe delegating some functionalities to a common, base DataSource.

Closes #3571

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[X] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Application (the showcase website) / infrastructure changes
[ ] Other... Please describe:

Does this PR introduce a breaking change?

[ ] Yes
[X] No

@codecov
Copy link

codecov bot commented Jul 11, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@b758572). Click here to learn what that means.
The diff coverage is 81.6%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #3766   +/-   ##
=========================================
  Coverage          ?   95.15%           
=========================================
  Files             ?      730           
  Lines             ?    14744           
  Branches          ?     1921           
=========================================
  Hits              ?    14030           
  Misses            ?      267           
  Partials          ?      447
Impacted Files Coverage Δ
components/table/public-api.ts 100% <100%> (ø)
components/table/nz-data-source.ts 71.42% <71.42%> (ø)
components/table/nz-table.component.ts 90.96% <79.31%> (ø)
components/table/nz-empty-data-source.ts 80% <80%> (ø)
components/table/nz-array-data-source.ts 83.33% <83.33%> (ø)
components/table/nz-detached-data-source.ts 86.36% <86.36%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b758572...8a4d9f8. Read the comment docs.

@lppedd
Copy link
Contributor Author

lppedd commented Jul 11, 2019

As of now builds fail because in other sources you're accessing the table data field directly, e.g.

data.length > 0

This won't work because DataSource doesn't, obviously, have that field.
I'll create a new abstract class NzDataSource, which mimic the length field.
This will also mean abstracting ourself from the CDK one, and it means we can introduce new code without breaking changes in the future.

Copy link
Member

@vthinkxie vthinkxie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments, thanks for your PR!

@lppedd
Copy link
Contributor Author

lppedd commented Jul 15, 2019

@vthinkxie Could you give a look at the NzTableComponent implementation?
Specifically at the handleDataChange method and the used classes. What do you think? This is temporary but it is a "road" a like.
The way NzDataSource is built means it is compatible with the old usages, where users would take the data field from the table instance to produce tr s.
Also, now we can have both virtual & normal, with both a DataSource and an array.
So basically an user can do whatever he/she wants.

Also now you can check the result in the preview! 😎 I'm happy


Edit: this problem can be solved by incrementing nzVirtualMinBufferPx.

I've also noticed an issue, which was already there, when using virtual scroll with front-end pagination.
table-cdk

It seems the bigger the view is, the most time it occurs.
table-cdk-2

@netlify
Copy link

netlify bot commented Jul 15, 2019

Deploy preview for ng-zorro-master ready!

Built with commit 7b5b12f

https://deploy-preview-3766--ng-zorro-master.netlify.com

@netlify
Copy link

netlify bot commented Jul 15, 2019

Deploy preview for ng-zorro-master ready!

Built with commit 8a4d9f8

https://deploy-preview-3766--ng-zorro-master.netlify.com

@lppedd lppedd force-pushed the master branch 4 times, most recently from 703ef69 to a2d09d7 Compare July 17, 2019 16:36
@lppedd
Copy link
Contributor Author

lppedd commented Jul 17, 2019

A quick update.
I have tried many different ways to maintain backward-compatibility without going crazy, but this seems to be the only reasonable one (if you want look at my table-manager branch).
I have re-organized/separated files so it's more clear what I have done.

@lppedd lppedd force-pushed the master branch 2 times, most recently from 0320865 to b4ab3bf Compare July 17, 2019 19:41
@vthinkxie
Copy link
Member

vthinkxie commented Jul 27, 2019

everything looks good to me, @wendzhue @hsuanxyz plz take a look at this
thanks a lot to @lppedd you did a great job!

@lppedd
Copy link
Contributor Author

lppedd commented Jul 27, 2019

Thanks!

@vthinkxie @wendzhue @hsuanxyz
I think we need to come up with an idea to better solve the following use-case:

  • DataSource
  • front pagination
  • non-virtual

Which means

<nz-table #table [nzData]="dataSource" [nzFrontPagination]="true" [nzShowPagination]="true">
   ...
   <tr *ngFor="let data of table.data; index as i">
      ...
   </tr>

This is particularly tricky.

The ideal workflow would be:

  1. user asks for a page, let's say page 2.
  2. DataSource is notified, does an HTTP calls, update the internal array
  3. change detection runs and calls [Symbol.iterator]
  4. the table view is updated

However what actually happens is

  1. user asks for a page, let's say page 2.
  2. following the button click, change detection runs (thanks Zone.js!) and calls [Symbol.iterator]
  3. table view is updated
  4. DataSource is notified, does an HTTP calls, update the internal array

You can clearly see there is a problem, the table is "behind" of an HTTP call, and the data displayed is wrong.

Possible solutions:

  1. User must use nzCurrentPageDataChange | async instead of data
 <tr *ngFor="let data of table.nzCurrentPageDataChange | async; index as i">

This plays awesome with this piece of code

private handleDataChange(nzData: NzDataSource<T> | T[]): void {
  ...
  if (this.nzFrontPagination) {
    this.data = new NzDetachedDataSource(this, this.data);
    this.data.connect(this).subscribe({
      next: data => this.nzCurrentPageDataChange.emit(data as T[]) // Here data is emitted
    });
  }
}
  1. User inject ChangeDetectorRef inside its own NzDataSource
private fetchRange(range: ListRange): void {
   this.http
       .get(`...`)
       .subscribe(result => {
         this.data = result;
         this.cdr.detectChanges(); // Here
       });
}

Two change detection cycles are run then.

  1. We wrap the pagination button click in a non-Zone.js area, and somehow we invoke change detection.

  2. We simly say "you cannot do that as of now"

  3. Any other idea? 😄


Here the major issue is backward campatibility. While I like the code I've written, I think it still has limitations.

The thing is getting data using this technique

<tr *ngFor="let data of table.data; index as i">

while pretty neat, require accessing the internal data field. If we wouldn't have had this behavior, I think we could have come up with something better.
But that's just my opinion.

Sorry for the long message, but I prefer having a clear overview of what doesn't work as expected

@lppedd lppedd force-pushed the master branch 2 times, most recently from ba541b0 to cfdd93c Compare July 27, 2019 12:24
if (this.nzFrontPagination) {
this.nzTotal = data.length;
this.nzTotal = this.data.length;
Copy link
Contributor Author

@lppedd lppedd Jul 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not ideal, as the NzDataSource instance might not have the value available at this point. I need to refactor this, somehow, into an "asynchronous" process

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, let's do this :)

@vthinkxie
Copy link
Member

vthinkxie commented Aug 9, 2019

Hi @lppedd
sorry for the late reply
I'm a little confused about the http calls with [nzFrontPagination]="true"

When the nzFrontPagination is true, there should no http calls I think, because all data are loaded at the very beginning, and the pagination split the data into pieces, and display them in the let data of table.data

@lppedd
Copy link
Contributor Author

lppedd commented Aug 9, 2019

@vthinkxie but how do you enforce the user to provide a DataSource which simply contains an Array? I mean, as far as I understood, the difference between frontPagination=true and ...=false, is that when true, the NzTableComponent handle the data splitting, while with false, events signaling pages and sizes are emitted, and the user must handle them himself.

The same applies with the DataSource, but it still can have HTTP calls.
Anyway, wouldn't it be the same with a DataSource containing only an Array? It's still asynchronous (sort of) by using Observables (see NzArrayDataSource).

But maybe I misunderstood what you're trying to say.

@vthinkxie
Copy link
Member

@lppedd
I mean if the user set frontPagination = true, why he still needs to send http calls when clicking pagination?

@lppedd
Copy link
Contributor Author

lppedd commented Aug 9, 2019

@lppedd well the user isn't forced to do HTTP calls, but it still is an option. We don't have control over the implementation of the inputted DataSource.
What I do when frontPagination = true, is signal page changes to the DataSource with a ListRange event.

@vthinkxie
Copy link
Member

@lppedd
yes, frontPagination = true should work with virtual scroll if user wants to send http calls, right?
if so I think we can add a note in the document, to tell the user not using frontPagination = true with non-virtual-scroll and I think most users would not use it in most scenarios

@lppedd
Copy link
Contributor Author

lppedd commented Aug 9, 2019

@vthinkxie yes absolutely. DataSource + frontPagination = true + virtual scroll, works nicely always.

Just a question: as I had written in the long message above, why not deprecating the use of the internal field data in favor of an event, such as nzCurrentPageDataChange.
This doesn't solve the problem, but at least is a step forward.

Anyway, I'll review the code again, and report back if I find something else worth discussing (I don't think so). Then I'll write some tests.
There is #3766 (comment) left off.

@vthinkxie
Copy link
Member

vthinkxie commented Aug 9, 2019

@lppedd
yes, we should move a step forward, but I think most current user works fine with Array input, let's talk about the breaking change when 9.0 comes.

@lppedd
Copy link
Contributor Author

lppedd commented Aug 9, 2019

@vthinkxie sure, agree. I'll keep you updated also on #3766 (comment), which needs some more thinking. If you want to throw ideas of any kind, they're very welcome.

@lppedd
Copy link
Contributor Author

lppedd commented Sep 9, 2019

@vthinkxie Sorry I've been pretty busy with other work. Just wanted to let you know I haven't forgotten.

@vthinkxie
Copy link
Member

Hi @lppedd
the table component are refactored in v9 now, and all data process are moved to table-data.service.ts now, it should be much clearer than before
feel free to ping me if you need any help

@vthinkxie
Copy link
Member

Hi
This Pull Request is going to be closed since no update for a long time, feel free to open a new PR if any new update.

@vthinkxie vthinkxie closed this Jun 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NzTableComponent should support CDK Datasource
2 participants