Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions packages/ng2-qgrid/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export {
BlurDirective,
BoolEditorComponent,
BoolEditorModule,
CacheAlreadyRequestedPageStrategy,
CaptionComponent,
CaptionModule,
CellEditorComponent,
Expand All @@ -189,6 +190,12 @@ export {
CurrencyPipe,
DataManipulationComponent,
DataManipulationModule,
DataProvider,
DataProviderComponent,
DataProviderModule,
DataProviderOptions,
DataProviderServer,
DataProviderStrategy,
DateDirective,
DateMaskDirective,
DateModule,
Expand Down Expand Up @@ -247,10 +254,9 @@ export {
ReferenceComponent,
ReferenceEditorComponent,
ReferenceEditorModule,
RequestTotalCountOnceStategy,
RestComponent,
RestModule,
DataProviderComponent,
DataProviderModule,
RuleComponent,
SerializationService,
StatusBarComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<q-grid [caption]="title">
<q-grid [caption]="title" [model]="gridModel">
<q-grid-columns generation="deep">
</q-grid-columns>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { GridModel } from 'ng2-qgrid';
import { Observable } from 'rxjs';
import { map, switchMap, tap } from 'rxjs/operators';
import {
CacheAlreadyRequestedPageStrategy, DataProvider, DataProviderServer, DataProviderStrategy, Grid, GridModel, RequestTotalCountOnceStategy
} from 'ng2-qgrid';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { Atom, DataService } from '../data.service';

const EXAMPLE_TAGS = [
Expand All @@ -21,34 +23,45 @@ export class ExampleDataProviderComponent {

page$: Observable<Atom[]>;

dataProvider: DataProvider<Atom>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

initialize dataPovider right here

Copy link
Collaborator

Choose a reason for hiding this comment

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

make it private

Copy link
Collaborator

Choose a reason for hiding this comment

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

can we again try to initialize dataProvider right here?

gridModel = this.qgrid.model();

constructor(
private dataService: DataService,
) { }

onRequestRows(gridModel: GridModel): void {
private qgrid: Grid,
) {
const server = new FakeServer(this.dataService);
const pager = gridModel.pagination();

this.dataProvider = new DataProvider<Atom>(this.gridModel, [
new RequestTotalCountOnceStategy(server),
new CacheAlreadyRequestedPageStrategy(server, 2),
new ReverseDataStrategy(),
]);
}

this.page$ = server.getTotal()
.pipe(
tap(total => gridModel.pagination({ count: total })),
switchMap(() => server.getPage(pager.current, pager.size)),
);
onRequestRows(gridModel: GridModel): void {
this.page$ = this.dataProvider.getPage();
}
}

class FakeServer {
class FakeServer implements DataProviderServer<Atom> {
constructor(
Copy link
Collaborator

Choose a reason for hiding this comment

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

@DataProviderCache()
@PataProviderBackground()
getPage() {}

@DataProviderCache()
@PataProviderBackground()
getPage() {}

private dataService: DataService,
) { }

getPage(pageNumber: number, pageSize: number): Observable<Atom[]> {
getPage(number: number, pageSize: number): Observable<Atom[]> {
return this.dataService.getAtoms()
.pipe(map(atoms => atoms.splice(pageNumber * pageSize, pageSize)));
.pipe(map(atoms => atoms.splice(number * pageSize, pageSize)));
}

getTotal(): Observable<number> {
return this.dataService.getAtoms()
.pipe(map(atoms => atoms.length));
}
}

class ReverseDataStrategy<T> extends DataProviderStrategy<T> {
processData(memo: T[]): Observable<T[]> {
return of(memo.slice().reverse());
Copy link
Collaborator

Choose a reason for hiding this comment

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

why we need to do memo slice?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename it please to ExampleReverseDataStrategy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

why we need to do memo slice?

.reverse() mutates initial array

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GridModel } from '@qgrid/ngx';
Copy link
Collaborator

Choose a reason for hiding this comment

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

can u put all strategies directly to the data-provider folder? also remove please index.ts file, we don't use them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

import { Observable } from 'rxjs';

export abstract class DataProviderStrategy<T> {
protected gridModel: GridModel;

abstract processData(memo: T[]): Observable<T[]>;
Copy link
Collaborator

@klumba12 klumba12 Mar 24, 2022

Choose a reason for hiding this comment

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

make it as an interface with method

process(data: T[], context: { model: GridModel }): Observable<T[]> 

still not sure about the signature with Observable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


setGridModel(model: GridModel): DataProviderStrategy<T> {
this.gridModel = model;
return this;
}
}
28 changes: 28 additions & 0 deletions packages/qgrid-ngx-plugins/src/lib/data-provider/data-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { GridModel } from '@qgrid/ngx';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DataProviderStrategy } from './data-provider-strategy';

export class DataProvider<T> {

constructor(
private gridModel: GridModel,
private strategies: DataProviderStrategy<T>[],
) {
strategies.forEach(strategy => strategy.setGridModel(this.gridModel));
}

getPage(): Observable<T[]> {
return this.applyStrategies();
}

private applyStrategies(memo = [], index = 0): Observable<T[]> {
const strategy = this.strategies[index];
const hasNext = !!this.strategies[index + 1];
if (!strategy) {
return of(memo);
}
return strategy.processData(memo)
.pipe(switchMap(x => hasNext ? this.applyStrategies(x, index + 1) : of(x)));
}
}
13 changes: 13 additions & 0 deletions packages/qgrid-ngx-plugins/src/lib/data-provider/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GridModel } from '@qgrid/ngx';
Copy link
Collaborator

Choose a reason for hiding this comment

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

rename file to the server.ts or maybe page-server.ts and PageServer class? not sure

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed interface to DataProviderPageServer

import { Observable } from 'rxjs';

export interface DataProviderOptions<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why we need this interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

server: DataProviderServer<T>;
gridModel: GridModel,
pageSize?: number;
}

export interface DataProviderServer<T> {
getPage(page?: number, size?: number): Observable<T[]>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

why page and size are optional?

Copy link
Contributor Author

@Dalantren Dalantren Mar 25, 2022

Choose a reason for hiding this comment

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

we doesn't know how user will implement communication with server. Maybe it won't need any information about page or size

getTotal(): Observable<number>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Observable, of } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
import { DataProviderStrategy } from '../data-provider-strategy';
import { DataProviderServer } from '../models';

export class CacheAlreadyRequestedPageStrategy<T> extends DataProviderStrategy<T> {
private gridRowsCache: Map<number, T[]> = new Map();
Copy link
Collaborator

Choose a reason for hiding this comment

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

just pageCache maybe?


constructor(
private server: Pick<DataProviderServer<T>, 'getPage'>,
private pagesToLoad: number = 0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

make at as an options, we can add more features here in the future

) {
super();
}

processData(memo: T[]): Observable<T[]> {
const { current, size } = this.gridModel.pagination();

if (this.pagesToLoad) {
this.loadInBackground(this.pagesToLoad);
}

if (this.gridRowsCache.has(current)) {
return of(this.gridRowsCache.get(current));
}

const shouldRequestData = !memo?.length;
return (shouldRequestData ? this.server.getPage(current, size) : of(memo))
.pipe(tap(rows => this.gridRowsCache.set(current, rows)));
}

private loadInBackground(pagesToLoad: number): void {
const { current, size } = this.gridModel.pagination();
Copy link
Collaborator

Choose a reason for hiding this comment

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

why we just wont' do a one server call to loadd required number of pages? maybe it should be an option?

const fromPage = current + 1;
const toPage = current + pagesToLoad;
for (let page = fromPage; page <= toPage; page++) {
if (!this.gridRowsCache.has(page)){
this.server.getPage(page, size)
.pipe(filter(rows => !!rows?.length))
.subscribe(rows => this.gridRowsCache.set(page, rows));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { CacheAlreadyRequestedPageStrategy } from './cache-requested-pages';
export { RequestTotalCountOnceStategy } from './request-count-once';

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Observable, of } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { DataProviderStrategy } from '../data-provider-strategy';
import { DataProviderServer } from '../models';


export class RequestTotalCountOnceStategy<T> extends DataProviderStrategy<T> {
private totalCount: number = 0;

constructor(
private server: Pick<DataProviderServer<T>, 'getTotal'>,
) {
super();
}

processData(memo: T[]): Observable<T[]> {
if (this.totalCount > 0) {
this.setPaginationCount(this.totalCount);
return of(memo);
}
return this.server.getTotal()
Copy link
Collaborator

Choose a reason for hiding this comment

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

add new line

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

.pipe(
tap(count => {
this.totalCount = count;
this.setPaginationCount(count);
}),
switchMap(() => of(memo))
)
}

private setPaginationCount(count: number): void {
this.gridModel.pagination({ count });
Copy link
Collaborator

Choose a reason for hiding this comment

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

not sure that we need a dedicated method to just setup pagination count

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

}
}
Loading