-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
(suggestion)md-table with http example #5670
Comments
Meanwhile the documentation is updated, I can provide you my own implementation with an HTTP REST API. Here, I retrieve some Conventions from my API and send them to the table.
Here's an example without my logic :
|
@egavard even connect() wasn't called
with no error |
Maybe it's because your connect and disconnect methods don't match the needed signature with CollectionViewer ? Could you try ? EDIT: That's not causing trouble. |
@egavard |
@egavard |
@egavard |
@alanpurple It's just a matter of preferences. |
@andrewseguin We should have an example http-based data source in the docs. |
I think in much of http cases, BehaviorSubject is not required
this is enough |
Did you try to navigate between another component and the one using the table ? That was the reason I used the BehaviorSubject. It allowed me to mark the subject complete on disconnect, to prevent multiple calls to my API. |
@egavard |
Here's an example we will put up on the docs site soon: https://plnkr.co/edit/mjQbufh7cUynD6qhF5Ap?p=preview |
How can i fix the header when scroll? Anyone? |
Very hard to apply pagination, sort and filter |
Can someone show how to apply http pagination in the table? |
Hey @lemang Here is my code. 👨💻 // my http service for data source
getClaims(param?: { page?: number, pageSize?: number }): Observable<MyDtoModel> {
// just creating params
let params = this.url.paramsWithValue(param);
return this.http
.get(`${this.api}/Get`, this.url.requestOptions(null, params)) // my custom header options.
.map(this.dataHelper.extractData)
.catch(this.dataHelper.handleErrors);
}
// component.ts
displayedColumns = ['col1', 'col2', 'col3', 'col4', 'col5'];
dataSource: DataSource<IClaimResources>;
@ViewChild(MdPaginator) paginator: MdPaginator;
@ViewChild(MdSort) sort: MdSort;
constructor( private ClaimService: ClaimService) { }
ngOnInit() {
// refactor is welcome.
this.dataSource = new DelegateClaimsDatasource(this.ClaimService, this.paginator, this.sort);
}
// datasource delegate class
export class DelegateClaimsDatasource extends DataSource<IClaimResources> {
subject: BehaviorSubject<IClaimResources[]>;
pager: IPager; //my server dto models
constructor(private claimService: ClaimService, private paginator: MdPaginator, private sort: MdSort) {
super();
}
private getData(p: MdPaginator, claimService: ClaimService) {
claimService.getClaims({ page: p.pageIndex, pageSize: p.pageSize })
.map((res: IHttpApiMessage) => <DtoModel>res.contentBody)
.do((dto: DtoModel) => this.subject.next(dto.content))
.subscribe((dto: DtoModel) => this.pager = dto.pager, (error: any) => Observable.throw(error));
}
// refactoring is welcome.
connect(): Observable<IClaimResources[]> {
const displayedChanges = [
this.sort.mdSortChange,
this.paginator.page,
];
// on changes
Observable.merge(...displayedChanges).subscribe((d) => {
// if it is sorting, reset page index to 0;
if (d['active'] && d['direction']) this.paginator.pageIndex = 0;
this.getData(this.paginator, this.claimService, this.sort);
});
// init
if (!this.subject.isStopped)
this.getData(this.paginator, this.claimService, this.sort, );
return Observable.merge(this.subject);
}
disconnect(): void {
this.subject.complete();
this.subject.observers = [];
}
}
// component.html
<md-table [dataSource]="dataSource" mdSort >
// md-row.... same as angular docs.
<md-table>
// paginator... My paging calculation is dynamic.
<md-paginator [pageSizeOptions]="[5, 10, 15, 35, 50, 100, 200]"
[length]="dataSource?.pager?.totalItems" [pageIndex]="dataSource?.pager?.currentPage" [pageSize]="dataSource?.pager?.pageSize">
</md-paginator> |
@irowbin hi how did you make the checkbox work for each row. When i select a checkbox it selects all the checkboxes. |
I am getting this error ERROR in SelectionModel is not an NgModule even though I have imported SelectionModel from angular material. I am already using md-table from the material. So I know it is installed. Please advise.
From: Robin Regmi [mailto:notifications@github.com]
Sent: Monday, July 31, 2017 9:31 PM
To: angular/material2 <material2@noreply.github.com>
Cc: Nisha Narayanan <nnarayanan@casestack.com>; Mention <mention@noreply.github.com>
Subject: Re: [angular/material2] (suggestion)md-table with http example (#5670)
@nnarayanancs<https://github.com/nnarayanancs> Here https://plnkr.co/edit/EU3BBlViWpPf2NJW4PXx?p=preview
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#5670 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/AcyOlWx-_XeOn_MdADCSHnoYrJE9vMJAks5sTqoOgaJpZM4OTzD_>.
|
@irowbin Why are you importing the "startWith" rx operator? It's not used anywhere in the code? |
Could you please focus on the original subject here, the http datasource example ? |
@DavidTheProgrammer That wasn't my code. I just post here to help for checkbox selection. @egavard Yeah you're right. Focus the actual Subject. |
Can any one has working plunker for server side pagination,sorting,filtering? CategoryService which will provide paged data. @irowbin : I looked into your plunker but I did not find service file over there as you have , please guide me in that. Thanks, |
I made an small and runnable example project where the backend is remote, the state manager ist ngrx and sort and pagination just triggers the request actions. Even filtering can be implemented this way. https://github.com/Braincompiler/ngrx-material-remote-data-table Hope this helps someone :) |
Is there something special that needs to be done for sorting? My table shows up fine initially, but after trying to sort with a mat-sort-header column, I get the following error: Uncaught Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed |
@sneckelmann Looks like your data source offered an object to the table through the |
Thanks for the feedback @andrewseguin . I am returning an Observable of an object array. It works the first time for initial load but sorting causes the mentioned error. I'll keep trying to hunt down an answer though but seems I may end up on SO. Thanks again. |
@sneckelmann My assumption is that you merged several streams together and the result is assumed to be your data. E.g. you merged If that's not it, for sure post the data source on StackOverflow, there's a great community there that has been answering a lot of similar questions. Observables are awesome but they have a steeper learning curve. |
@andrewseguin - thanks for this. Would you be able to add sorting, filtering, and pagination on this example, too? I think there's a few of us, myself included, that are facing issues with this. |
A working http example would be very helpful for me as well. Tried to run the plunkr above and got:
|
I am working diligently on an example with http, sorting, pagination - I'm almost there but was getting errors where the sort, paginator components were trying to render before dataSource.filteredData was available. I tried moving everything to ngAfterViewInit to no success as well. I'll update shortly! |
@pevans360 @iamwhitebox is my example not helpful? :) https://github.com/Braincompiler/ngrx-material-remote-data-table Do you miss something? |
I started with angular few weeks ago (I have 0 .js experience in general) and this is how it looks so far. Add and Edit are working using mat dialogs. Implementing Delete shouldn't be a problem aswell. Few issues tho:
When I sort this issues I can upload entire project or if someone can help I can post it now. PS: Sorry for Croatian on image but u get an idea. Oh and pagination works aswell. |
After trying for days to make this work, I'm ripping it out in favour of a static template displaying the information coming back. Is there an option in Angular Material, maybe, to implement a table which just loads from static data? If we could load a strongly typed result set into a table and have that displayed, that would be awesome. Maybe rename the existing mat-table to mat-table-dynamic (or add a dynamic operator to the tag or something, I don't know). For simple/most workloads, that would suffice. The existing mat-table implementation is extremely confusing and needlessly so. But I love Angular Material and thank you all for the hard work you do and continue to do on this amazing framework! |
Okay I'm almost done, but still stuck with the first thing. Here's an Stackoverflow question if someone more experienced could take a look: |
I understand that the topic is already closed, but I would like to share a missing "feature": Server-side Filtering. I will share my full src (Angular 4) based on the @irowbin code (thanks). tuple.ts model export interface ITuple<T> {
value: T;
text: any;
}
export class Tuple<T> implements ITuple<T> {
constructor(
public value: T,
public text: any
) { }
} component.html <div class="example-header">
<mat-form-field>
<input matInput #inputFilterValue placeholder="Filter">
</mat-form-field>
</div>
<mat-table class="app-nna-table" #table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="productName">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.productName || 'No available'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="description">
<mat-header-cell *matHeaderCellDef mat-sort-header> Description </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.description || 'No available'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="productTypeName">
<mat-header-cell *matHeaderCellDef mat-sort-header> Category </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.productTypeName}} </mat-cell>
</ng-container>
<ng-container matColumnDef="validFromDate">
<mat-header-cell *matHeaderCellDef mat-sort-header> Start </mat-header-cell>
<mat-cell *matCellDef="let element"> {{(element.validFromDate | date) || 'No available'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="validToDate">
<mat-header-cell *matHeaderCellDef mat-sort-header> End </mat-header-cell>
<mat-cell *matCellDef="let element"> {{(element.validToDate | date) || 'No available'}} </mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef mat-sort-header> Actions </mat-header-cell>
<mat-cell *matCellDef="let element">
<div class="app-tablet-actions">
<a href="">
<mat-icon title="Add Product">add_circle</mat-icon>
</a>
<a href="">
<mat-icon>mode_edit</mat-icon>
</a>
<a href="">
<mat-icon>delete</mat-icon>
</a>
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
<mat-paginator #paginator [length]="dataSource?.pager?.totalCount" [pageIndex]="dataSource?.pager?.requestedPage" [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 50, 100]">
</mat-paginator> data-source.ts export class MatTableDataSource<T> extends DataSource<any[]> {
//#region properties
public pager: any[];
//#endregion
constructor(
public resource: RESTfulangular<T>,
public subject: BehaviorSubject<any[]>,
public paginator: MatPaginator,
public sort: MatSort,
public filters: ITuple<any>
) {
super();
}
public connect(): Observable<any[]> {
//#region properties
const displayedChanges = [
this.sort.sortChange,
this.paginator.page,
this.filters.text
];
//#endregion
//#region logic
// on changes
Observable.merge(...displayedChanges).subscribe((d: {}|Element) => {
// if it's sorting, reset page index to 0;
if ((d as any)["active"] && (d as any)["direction"]) {
this.paginator.pageIndex = 0;
}
this.getData(this.resource, this.paginator, this.sort, ((d instanceof KeyboardEvent) ? (d.target as HTMLInputElement).value : null));
});
// init
if (!this.subject.isStopped) {
this.getData(this.resource, this.paginator, this.sort, null);
}
//#endregion
return Observable.merge(this.subject);
}
public disconnect(): void {
this.subject.complete();
this.subject.observers = [];
}
// RESTfulangular is a custom model for ngx-restangular
private getData(resource: RESTfulangular<T>, paginator: MatPaginator, sort: MatSort, filterValue?: string) {
const callbackRequest = (params?: any): void => {
resource.customGET(null, params)
.map((metadata: any) => metadata)
.do((elements: any) => this.subject.next(elements.items))
.subscribe((dto: IProduct[]) => {
this.pager = dto;
}, (err: any) => Observable.throw(err));
};
const urlParams: IUrlParams = {
page: paginator.pageIndex || 1,
count: paginator.pageSize || 10,
orderBy: sort.active,
descending: (sort.direction === "desc") ? true : false,
} as IUrlParams;
const filterParams: ITuple<any> = {} as ITuple<any>;
// can be improved (refactoring accepted)
if (filterValue && this.filters && this.filters.value && this.filters.value.length) {
this.filters.value.forEach((column: string) => {
(filterParams as any)[column] = filterValue;
});
}
callbackRequest((filterParams) ? Object.assign(urlParams, filterParams) : urlParams);
}
} -- component.ts export class ProductsComponent implements OnInit, AfterViewInit {
//#region properties
// public dataSource = new MatTableDataSource<Element>(null); => NgMaterial 5
public displayedColumns = ["productName", "description", "productTypeName", "validFromDate", "validToDate", "actions"];
public dataSource: MatTableDataSource<IProduct[]>;
public dataSubject = new BehaviorSubject<any[]>([]);
public dataFilterValueChange: Observable<string> = new Observable<string>();
@ViewChild("inputFilterValue") public inputFilterValue: ElementRef;
@ViewChild(MatPaginator) public paginator: MatPaginator;
@ViewChild(MatSort) public sort: MatSort;
//#endregion
constructor(
@Inject(NOTIFICATION_SERVICE_TOKEN) public toastService: INotificationService,
@Inject(PIM_DATA_SERVICE_TOKEN) public pimDataService: IPimDataService,
) {
//
}
public ngOnInit() {
this.dataFilterValueChange = Observable.fromEvent(this.inputFilterValue.nativeElement, "keyup");
this.refresh();
}
/**
* Set the paginator after the view init since this component will
* be able to query its view for the initialized paginator.
*/
public ngAfterViewInit() {
this.setupTable();
}
public refresh(): void {
const filters: ITuple<any> = { value: ["name"], text: this.dataFilterValueChange };
this.dataSource = new MatTableDataSource(this.pimDataService.getProductsResource(), this.dataSubject, this.paginator, this.sort, filters);
}
private setupTable(): void {
if (this.dataSource) {
(this.dataSource as any).paginator = this.paginator;
(this.dataSource as any).sort = this.sort;
}
}
} In filters (this.filters) from component.ts, it's decided how many columns will be filtered in the input value. I hope I can help you. Best regards. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Bug, feature request, or proposal:
proposal
What is the expected behavior?
something intuitive
What is the current behavior?
no idea how to
It will be very thankful if you provide an example of md-table with http service, not some mock database class
The text was updated successfully, but these errors were encountered: