-
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
feat(table): add MatTableDataSource #6747
feat(table): add MatTableDataSource #6747
Conversation
src/demo-app/table/table-demo.ts
Outdated
// Needs to be set up after the view is initialized since the data source will look at the sort | ||
// and paginator's initial values to know what data should be rendered. | ||
this.dataSource!.sort = this.sort; | ||
this.dataSource!.paginator = this._paginator; |
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.
This looks awesome and very user friendly! MdTableDataSource
's properties seem to document themselves, but I think using ViewChild and setting the instances in AfterViewInit will trip up some newcomers. IMO this little bit necessitates an example. I'd suggest using an "out of the way" data array like the Basic Example to emphasize how easy this is.
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.
Totally, I'm racking my brain to think of ways we can help devs avoid this but I can't think of anything. I wish I had access to the view ref in the data source and know whether or not they are passing it in at the right time. Maybe I should throw an error if they pass in an empty sort or paginator, saying that perhaps they are assigning it at the wrong time
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.
The error would be nice, but I'm afraid it's a valid - though rare - use case to initially pass in a paginator and then try to disable it later during the table's life. If you could get around that, the more descriptive errors are, the better!
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.
Here's an idea of a more magical version. MdSort can inject itself into the data source by injecting the table instance (assumes it is on the table element). MdPaginator can create an input that accepts the data source. This way, the user doesn't need to know about view init.
Check it out here: 097a2ff
@jelbourn I know you are avoiding magic, think this goes too far? Or are we not going far enough... =D
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.
Hah that's pretty slick! 🔮 I still think it'd require an example since passing the data source to the paginator is not an immediately obvious thing to do.. I prefer the original; the AfterViewInit part is plenty straight forward once you've done it once. I just don't think everyone will realize that's the correct approach without an example.
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 defer to your judgment that people would get it after seeing an example. I imagine we'll have some canonical StackOverflow question that addresses the issue people would see. Would prefer not to have such tightly coupled magic anyways. If we end up seeing that its an issue, we can always add it into MdSort and MdPaginator later too
src/demo-app/table/table-demo.html
Outdated
@@ -167,6 +72,6 @@ | |||
|
|||
<md-paginator #paginator | |||
[length]="_peopleDatabase.data.length" |
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.
this would be wrong when filtering is applied, wouldn't it?
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! Good catch, forgot to include some affordance for this. I imagine we could either directly change the pagination length in the data source since we have access to it, or offer some variable they could assign to the paginator's [length]
. I think I'll go with the former and see how that works
8b25d5b
to
e14d0ec
Compare
Updated for review (includes tests). |
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.
Lint
ERROR: /home/travis/build/angular/material2/src/demo-app/table/table-demo.ts[39, 5]: unused expression, expected an assignment or function call
ERROR: /home/travis/build/angular/material2/src/demo-app/table/table-demo.ts[39, 27]: Missing semicolon
src/lib/table/table-data-source.ts
Outdated
// Sorting and/or pagination should be watched if MdSort and/or MdPaginator are provided. | ||
// Otherwise, use an empty observable stream to take their place. | ||
const sortChange = this._sort ? this._sort.mdSortChange : observableOf(); | ||
const pageChange = this._paginator ? this._paginator.page : observableOf(); |
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.
observableOf()
-> empty()
?
src/lib/table/table-data-source.ts
Outdated
this._renderChangesSubscription = RxChain.from(this._data) | ||
// Watch for base data or filter changes to provide a filtered set of data. | ||
.call(combineLatest, this._filter) | ||
.call(map, ([data]) => this._filterData(data.slice())) |
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.
Why do you clone the array on every call?
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.
From _updateChangeSubscription
's perspective, those calls may change the data in some way (filter, reorder, or splice). When an event triggers, e.g. sort order changed, it wants to make sure data
is preserved so it sends a copy to be processed. If sort order changes again, it knows that data array provided on the stream has been protected from mutation.
The exception here is that filterData
doesn't actually mutate the data array, but it felt unsymmetrical to "know" that it can be passed the original array safely.
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 would think that the cloning logic more belongs inside the functions that here in the chain
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.
SGTM - not too opinionated on it. Moved cloning to the functions themselves
src/lib/table/table-data-source.ts
Outdated
// If there is a filter string, filter out data that does not contain it. | ||
// Each data object is converted to a string using the function defined by filterTermAccessor. | ||
// May be overriden for customization. | ||
const filteredData = this.filter === '' ? data : data.filter(obj => { |
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.
When filter is null
/ undefined
? What about when filter is all whitespace?
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.
Changed to !this.filter
to catch null/undefined. Not sure about whitespace, I think that our users should be doing these things according to their needs (e.g. toLowerCase
, trim
, etc.) before setting filter
src/lib/table/table-data-source.ts
Outdated
let valueA = this.sortingDataAccessor(a, this.sort!.active); | ||
let valueB = this.sortingDataAccessor(b, this.sort!.active); | ||
return (valueA < valueB ? -1 : 1) * (this.sort!.direction == 'asc' ? 1 : -1); | ||
}); |
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.
You could avoid the non-nullability assertion operator by storing a reference to this.sort
if (!this.sort || !this.sort.active || this.sort.direction == '') {
return data;
}
const sort = this.sort;
return data.sort((a, b) => {
let valueA = this.sortingDataAccessor(a, sort.active);
let valueB = this.sortingDataAccessor(b, sort.active);
return (valueA < valueB ? -1 : 1) * (sort.direction == 'asc' ? 1 : -1);
});
Thanks, fixed lint and changed to use empty(), and changed logic with filter/sort |
src/lib/table/table.spec.ts
Outdated
component.sort.sort(component.sortHeader); | ||
fixture.detectChanges(); | ||
expectTableToMatchContent(tableElement, [ | ||
['Column ASorted by a descending', 'Column B', 'Column C'], |
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.
Why is there no space between Column A
and Sorted
?
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.
Side-effect of how I set up the expectTableToMatchContent
- it converts a cell to its .textContent
, which includes visually hidden elements. Sorted headers have a cdk-visually-hidden
element that describes the sort.
In our case here, we've got three siblings in the cell (approx.):
<button> Column A </button>
<div class="sort-arrow"></div>
<span class="cdk-visually-hidden"> Sorted by a descending </span>
This converts to Column ASorted by a descending
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.
This will be an issue when we turn on whitespace collapsing; we should add an
between those
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.
SGTM - added an HTML space before the description label and changed the tests to check for that break
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.
LGTM
f6ef763
to
53e174d
Compare
53e174d
to
28980f1
Compare
@andrewseguin Check out the linter error? https://travis-ci.org/angular/material2/jobs/282300920 |
e3b2792
to
0a654e9
Compare
Fixed lint |
@andrewseguin Rebase? |
0a654e9
to
392db44
Compare
Rebased |
392db44
to
ce47a7d
Compare
MatTableDataSource is not imported in @angular/material this error is occurred ...Please give me solution |
I am getting the error '@angular/material/material' has no exported member 'MatTableDataSource'. |
Hi,
Here will be one solution for these error you use version of angular
material 5.0.0 rc0 this version is helpful to resolve this error
On 18-Nov-2017 2:34 PM, "Nidish K Viswanathan" <notifications@github.com> wrote:
I am getting the error '@angular/material/material' has no exported member
'MatTableDataSource'.
Using "@angular/material": "2.0.0-beta.12"
"@angular/cdk": "2.0.0-beta.12",
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#6747 (comment)>,
or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AciCJTtCIsrgRTsHuujb997seMskPofYks5s3p2ogaJpZM4PID6X>
.
|
Thanks @nishantp12345 . Its working fine when using 5.0.0 rc0 version |
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. |
This is a data source that can be used by users that don't want to deal with streams to render a table.
Accepts a data array and optional extras such as MdSort, MdPaginator, and filter string.
Allows user to set up their own data accessor for sorting (params include the data object and sort header id), and the filter accessor which converts their data object into a search string that the filter will compare against.
Closes #6911