Closed tyler2cr closed 3 years ago
Sounds good to me, I'll make an example that includes adding/removing/editing rows.
I hope I can add to this request without creating a new Issue, I've been looking at the example code provided in both the angular material docs and the cdk guide and I'm struggling to understand how to just send my data (a simple array of objects) to the table. Do I need my data to be a BehaviorSubject ? Do I need the typescript get too ?
The example generates data with loops and is quite confusing to me.
A simpler example with just a small simple array would really help ! I'll create a new Issue if needed.
hello @andrewseguin It would be nice if you add collapsible row too.
Hi @andrewseguin, alos would be nice to have example with server data, to get server data is OK, but how to triger on new http.get request on paging, sorting and filtering? (i'm stuck with that).
@Lakston IMO your request deserves a separate issue. While the ExampleDatabase is great as a supplier of 100 rows of random data, it convolutes the Basic Example, and I think the docs could benefit from an even simpler example with maybe a single emission of a hardcoded array of data with Observable.of
.
@ilmars luckily an example with an HTTP request just got merged yesterday and will be available on the docs site soon https://github.com/angular/material2/pull/5766
@Lakston what I did to accomplish that was to setup a service to provide the data array to the ExampleDatabase
and then looped over each item in the array and fed them into the addUser
method from the example, after changing it to match my object. So you can just replace what is being iterated over in the for loop from the example by creating a service to call for that data
for anyone interested in an unpublished example:
https://github.com/angular/material2/pull/5093/files
https://github.com/angular/material2/tree/master/src/demo-app/table
Some help on this would be greatly appreciated :)
https://stackoverflow.com/questions/45382599/angular-2-table-invoke-connect-function
Agreed. I wept for joy when this component arrived. But after about six hours of fiddling with this thing, I still can't get it to work with a meaningful, real-world example. I expected to just point it at an array, and I'd be off and running. But having to create a datasource and a database is especially cumbersome. If the grid is supposed to be truly unopinionated, imo it shouldn't be coupled to observables. I should be able to just point it at an array of data and an array of column definitions (like most other analogous components).
@etovian You don't need to create a database. That's just used in the example because the example needs to generate a lot of random data to display.
You barely even have to use Observables. They're used in the examples because they massively simplify manipulating the data in response to user events and are generally very powerful and flexible. If you just want to render an array once, you can use Observable.of(myArrayOfValues)
and you don't have to touch rxjs again. If you want to render it more than once,
// component
_dataSubject = new BehaviorSubject<any[]>([])
constructor() {
this.dataSource = new MyDataSource(this._dataSubject)
}
updateValues(myArray: any[]) {
this._dataSubject.next(myArray)
}
// MyDataSource
constructor(private _data: BehaviorSubject<any[]>) { }
connect() {
return this._data.asObservable()
}
@willshowell Thanks for the tip! I sort of got this working:
export class MyDataSource extends DataSource<any[]> {
data = [
{ firstName: 'Mike' },
{ firstName: 'Amy' },
{ firstName: 'Jillian' },
{ firstName: 'Juliette' }
];
constructor() {
super();
}
connect (): Observable<any[]> {
return Observable.of(this.data);
}
disconnect ( ): void {
}
}
The only problem is that the data doesn't load when the component using the dataSource initializes. Oddly, if I click elsewhere on the page (not even inside the component), then table displays the data. Here's all of the code:
import { Component, OnInit, ViewChild } from '@angular/core';
import { CdkTable, DataSource } from '@angular/cdk';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/observable/fromEvent';
import { InvitationService } from "../services/invitation.service";
@Component ( {
selector: 'app-sandbox',
templateUrl: './sandbox.component.html',
styleUrls: [ './sandbox.component.css' ]
} )
export class SandboxComponent implements OnInit {
dataSource: MyDataSource | null;
displayedColumns = ['firstName'];
@ViewChild('table')
table: CdkTable<any>;
constructor(private invitationService: InvitationService) {
}
ngOnInit() {
this.dataSource = new MyDataSource();
//this.dataSource.connect();
}
}
export class MyDataSource extends DataSource<any[]> {
data = [
{ firstName: 'Mike' },
{ firstName: 'Amy' },
{ firstName: 'Jillian' },
{ firstName: 'Juliette' }
];
constructor() {
super();
}
connect (): Observable<any[]> {
return Observable.of(this.data);
}
disconnect ( ): void {
}
}
And the template:
<md-table
#table
[dataSource]="dataSource">
<ng-container cdkColumnDef="firstName">
<md-header-cell *cdkHeaderCellDef> First Name </md-header-cell>
<md-cell *cdkCellDef="let row"> {{row.firstName}} </md-cell>
</ng-container>
<md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
<md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>
</md-table>
@willshowell Oddly, this is working exactly as expected:
import { Component, OnInit } from '@angular/core';
import { DataSource } from '@angular/cdk';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/observable/fromEvent';
import { InvitationService } from "../services/invitation.service";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
@Component ( {
selector: 'app-sandbox',
templateUrl: './sandbox.component.html',
styleUrls: [ './sandbox.component.css' ]
} )
export class SandboxComponent implements OnInit {
dataSource: MyDataSource | null;
dataSubject = new BehaviorSubject<any[]>([]);
displayedColumns = ['firstName'];
constructor(private invitationService: InvitationService) {
this.invitationService.getInvitations().subscribe({
next: value => this.dataSubject.next(value)
});
}
ngOnInit() {
this.dataSource = new MyDataSource(this.dataSubject);
}
}
export class MyDataSource extends DataSource<any[]> {
constructor(private subject: BehaviorSubject<any[]>) {
super ();
}
connect (): Observable<any[]> {
return this.subject.asObservable();
}
disconnect ( ): void {
}
}
Since this much better represents how I'd do things in production, I'm not necessarily concerned with why the code from my previous post isn't working. Thanks again for your help! You definitely saved me some continued hair-pulling.
I can certainly get by with this, but I think that the option to work directly with an array would help folks get up and running much more quickly, even if the DataSource is a more performant solution.
Thanks to all the devs for their hard work!
@etovian your first issue looks like https://github.com/angular/material2/issues/6199 which is resolved and will be a part of the next release.
Also an array-based data source that is plug-and-play is in the works https://github.com/angular/material2/pull/6182, though it's not clear which direction that PR will take
@willshowell What does your getInvitations() method look like in your InvitationService service?
constructor ( private http: Http ) { }
getInvitations (): Observable<Invitation[]> {
return this.http.get ( this.invitationUrl ).map ( response => response.json () );
}
I am not getting any error but the data from web API is not rendering in datatable. Only columns are displayed.
Below is my code:
` import { Component, OnInit, ViewChild } from '@angular/core'; import { UserService } from '../Service/user.service'; import { IUser } from '../Model/user'; import { DBOperation } from '../Shared/enum'; import { Observable } from 'rxjs/Rx'; import { Global } from '../Shared/global'; import { ManageUser } from './manageuser.component'; import { MdDialog, MdDialogRef } from '@angular/material'; import { UserFilterPipe } from '../filter/user.pipe'; import { DataSource } from "@angular/cdk/collections";
@Component({ templateUrl: 'app/Components/userlist.component.html' })
export class UserListComponent implements OnInit {
users: IUser[];
user: IUser;
dataSource: userDataSource;
displayedColumns = ['FirstName', 'LastName'];
constructor(private _userService: UserService) { }
ngOnInit(): void {
this.LoadUsers();
}
LoadUsers(): void {
this._userService.get(Global.BASE_USER_ENDPOINT)
.subscribe(users => { this.users = users }
);
this.dataSource = new userDataSource(this.users);
}
}
export class userDataSource extends DataSource
constructor(private _users: IUser[]) {
super();
}
connect(): Observable<IUser[]> {
return Observable.of(this._users);
}
disconnect() { }
} `
Below is my html
`
`
Not getting where exactly the issue is.
@etovian Can you provide an example of filtering such table?
EXPLAIN ME please, HOW does it work? When I add new item to data source's array – table doesn't show it immediately. It shows no changes until I click on header for sorting or paginator and only after that table will re-render.
@Shrralis I think the key in this line - https://github.com/angular/material2/blob/master/src/material-examples/table-filtering/table-filtering-example.ts#L68
@shalugin for my sorry unfortunately no. I already have something like that:
public addManufacturer(manufacturer: Manufacturer): void {
let newManufacturers: Manufacturer[] = [];
this.data.subscribe((manufacturers: Manufacturer[]) => newManufacturers = manufacturers);
newManufacturers.push(manufacturer);
this.manufacturerDataSubject.next(newManufacturers);
}
I know the code looks strange but this is because of my experiments on this to make it work. I can make plnkr with my code.
Hmmm..
It shows no changes until I click on header for sorting or paginator and only after that table will re-render.
Maybe this indicating a problem. Try insert ChangeDetectorRef into contructor and trigger changes manually.
constructor(private _cdr: ChangeDetectorRef) {
}
.....
this.manufacturerDataSubject.next(newManufacturers);
this._cdr.detectChanges();
.....
Try insert ChangeDetectorRef into contructor and trigger changes manually.
I'm trying with ApplicationRef (tick() method) because of I'm using a service. But there is no effect.
public addManufacturer(manufacturer: Manufacturer): void {
let newManufacturers: Manufacturer[] = [];
this.data.subscribe((manufacturers: Manufacturer[]) => newManufacturers = manufacturers);
newManufacturers.push(manufacturer);
this.manufacturerDataSubject.next(newManufacturers);
this._ar.tick();
}
public getManufacturers(): Observable<Manufacturer[] | Error> {
console.log('getManufacturers started!');
return this.lookupService.getAllManufacturers();
}
public submitManufacturers(manufacturers: Observable<Manufacturer[]>): void {
manufacturers.forEach((m: Manufacturer[]) => {
console.log('submitManufacturers started! manufacturers: ' + JSON.stringify(m));
});
manufacturers.subscribe((m: Manufacturer[]) => this.manufacturerDataSubject.next(m));
this._ar.tick();
console.log('submitManufacturers finished!');
}
@Shrralis Can you create a plunker or stackblitz with your code?
@shalugin here it is: https://stackblitz.com/edit/angular-h3ckjw
@Shrralis
Just change code:
const displayDataChanges = [
this._filterChange,
this._sort.sortChange,
this._paginator.page,
];
to
const displayDataChanges = [
this._filterChange,
this._sort.sortChange,
this._paginator.page,
this.manufacturersLocalService.data,
];
You don't need to use ApplicationRef
(tick() method).
If I understood you right, then you only need some BehaviorSubject
that will trigger changes for DataSource
.
@tyler2cr , I have created a package that extends angular cdk DataSource
implementing row addition, edition and deletion. You can check it here.
It only adds structure to operate with rows, and manage datasource logic to update elements.
This is the npm package.
@shairez
Just change code
You're right, it worked! Thank you so much
I have a similar issue. My Angular 4 app has a service pulling data from a Laravel backend thats connected to a MySQL DataBase.
I am able to display the data through ngFor with a Bootstrap 4 table so I know it works.
My question is.. how in the world do I do this with the Material table??
If anyone could provide some guidance i would truly appreciate it.
@heri-g You can use example from https://github.com/angular/material2/issues/5917#issuecomment-337899837
@willshowell Is it possible to get that short example added to the material.angular.io docs?. It's really good and easy to follow. All the other examples are complex and muddy the water with techniques that make it hard to get the basics. Your example showed me what I need to know in 10 minutes, the other just confused me for the last 10 hours, grrr if only I'd found this sooner 👍
https://github.com/angular/material2/tree/master/src/demo-app/table
What is MatTableDataSource
here? Stackblitz gives me error about that.
Your plunker code is not really working would you please check on your dependencies @irossimoline
@rima-smart , I have updated the dependencies.
Here is what worked for me. Stackblitz url :https://stackblitz.com/edit/angular-5zu7px Below is the code to add new element to array without using behaviorSubject.
addRow() {
alert('adding row');
this.dataSource.data.push({
position: 1,
name: "Hydrogen",
weight: 1.0079,
symbol: "H"
});
this.dataSource.filter = "";
}
Is there something less hacky than using
this.dataSource.filter = "";
after pushing data, to get a re-render?
Also, I add new data, and new rows are added, but the cells in the new row are empty...even though the new data is good.
If I open "Dev Tools" and click around and inspect, then the table will render the cells. So I know something is wrong with this lib.
You can use the method called _updateChangeSubscription()
. This method will update subscription to changes that should trigger an update to the table's rendered rows. When the changes occur it processes the current state of the filter, sort, and pagination along with the base data and sends it to the table for rendering.
Took me some time but I finally got everything working. So, here's my CRUD implementation if anyone gets in trouble with this: https://github.com/marinantonio/angular-mat-table-crud
Screenshot:
Or you can test it on gist: https://marinantonio.github.io/angular-mat-table-crud/
@marinantonio cool, how did you create that GIF?
@armansujoyan
I tried this:
self.dataSource.data.push(m as any);
self.dataSource._updateChangeSubscription();
unfortunately didn't work...my table renders new rows, but the rows are empty - the cells don't get rendered. This is all very unfortunate. What kind of library is this? I can't add rows to a table? FML.
@ORESoftware For recording used free software ScreenToGif, and after that uploaded .gif to Imgur.
@andrewseguin I want to create mat table with dynamic columns and I have array of object in which each object has fields which i want to show it vertically.
In above image I have object where all column fields are in one object and I want to show columns of every object in array. If anyone could provide some guidance i would truly appreciate it.
@marinantonio how to post it permanently you are just pushing it temporary how to post it using post method in angular2
@chethan1095 What do you mean? You push post method from DataService.ts and then depending on result (successful or not) you push front-end update to a mat-table.
I need some help, in rendering the value in the data table when the datasource has multiple json array. below is the service json response { "_index": "com_reprocess", "_type": "reprocessor", "_id": "com-payment-intake-62fc632e-5ac3-40d8-a35a-0yment-intake-paypalclosure-q2", "_score": 1, "_source": { "applicationName": "com-payment-intake-paypalclosure-q2", "topic": "COMPayment-PaypalClosure-q2", "retryInterval": 0, "maxRetryCount": 3, "isAutoRetryable": "false", "cassandraTTL": 3000000, "reprocessId": "aafde69c-7379-4bca-ac6e-c2e30bd4be11", "sequenceNo": "1521827002607", "key": "com-payment-intake-62fc632e-5ac3-40d8-a35a-0b2cbd9facf1_WA11121773", "errorCode": "-104", "createTimeStamp": "2018-03-23T17:43:22", "currentRetryCount": 0, "createProgId": "com-payment-intake-paypalclosure-q2_CONSUMER1_fcf59940-37c3-4478-becc-3798e0e0c4a2", "state": "initial", "groupforSameKey": false, "nextRetryTime": "2018-03-23T17:44:22", "clientHeaders": [ {"key": "com-acf1_WA11121773", "value" :"FAILED"} ], "hostIP": "10.255.220.35", "hostName": "dbb6f7b4-4909-479c-79c3-1e95", "isESRecordLocked": false, "modifyTimeStamp": "2018-03-23T17:43:22" } },
where i'm trying to iterate the response and bind them to material datatable. It is all good but i can't access the attributes inside the clientHeaders array.
here is my material table html statements and it is not returning any value.
<ng-container matColumnDef="value" style="column-width:500px">
<mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]="'value'"> fail_rsn </mat-header-cell>
<mat-cell *matCellDef="let element" [ngClass]="'value'"> {{element._source.clientHeaders.key}} </mat-cell>
</ng-container> Can any one help on this ? stuck with 2 days on this
@andrewseguin Great job man! Can you please share a link to the repository for the updates you made that includes adding/removing/editing rows and if possible, editing individual cells. Thank you.
Are the examples still coming to the documentation?
Vielen Dank für Ihre Nachricht.
Ich bin vom 25. Juni bis 1. Juli im Urlaub. Ab Montag, dem 2. Juli bin ich wieder gerne für Sie erreichbar.
Ihre E-Mail wird an info@bynary.de weitergeleitet. In dringenden Fällen wenden Sie sich bitte an Sebastian Homeier (E-Mail: s.homeier@bynary.de, Tel.: +49 (0) 941 462 971 30).
Danke für Ihr Verständnis!
Viele Grüße Johannes Homeier
@andrewseguin This is really important! Is an example coming out soon?
Bug, feature request, or proposal:
cdk table API docs need instructions and/or an example of updating the dataSource in the table connecting the table to a data source
What is the expected behavior?
seeing implementation instructions and/or an example of how to send the updated dataSource to the table so that the connect function is called
What is the current behavior?
The docs only cover rendering data on initial load of the component, but if a service updates the data, there isn't a documented way to update the data-table
What are the steps to reproduce?
Providing a Plunker (or similar) is the best way to get the team to see your issue. Plunker template: https://goo.gl/DlHd6U
What is the use-case or motivation for changing an existing behavior?
the md-table API doc hints at an approach but also lacks clarity
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
angular 4 material 2 typescript 2.4 windows
Is there anything else we should know?