Skip to content

Commit 0ab8113

Browse files
crisbetommalerba
authored andcommitted
fix(tree,scrolling): don't require user DataSource to extend DataSource (#14966)
Currently the way we verify that the passed in data source is by using `instanceof` which assumes that the consumer has extended our `DataSource`. In `cdk/table` we do the verification by checking whether the object matches the interface of a `DataSource` instead. These changes add a utility method to check whether something is a data source and refactor the `tree` and `scrolling` entry points to be consistent with `table`.
1 parent 64010d7 commit 0ab8113

File tree

5 files changed

+26
-16
lines changed

5 files changed

+26
-16
lines changed

src/cdk/collections/data-source.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,11 @@ export abstract class DataSource<T> {
2929
*/
3030
abstract disconnect(collectionViewer: CollectionViewer): void;
3131
}
32+
33+
/** Checks whether an object is a data source. */
34+
export function isDataSource(value: any): value is DataSource<any> {
35+
// Check if the value is a DataSource by observing if it has a connect function. Cannot
36+
// be checked as an `instanceof DataSource` since people could create their own sources
37+
// that match the interface, but don't extend DataSource.
38+
return value && typeof value.connect === 'function';
39+
}

src/cdk/scrolling/virtual-for-of.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {ArrayDataSource, CollectionViewer, DataSource, ListRange} from '@angular/cdk/collections';
9+
import {
10+
ArrayDataSource,
11+
CollectionViewer,
12+
DataSource,
13+
ListRange,
14+
isDataSource,
15+
} from '@angular/cdk/collections';
1016
import {
1117
Directive,
1218
DoCheck,
@@ -82,7 +88,7 @@ export class CdkVirtualForOf<T> implements CollectionViewer, DoCheck, OnDestroy
8288
}
8389
set cdkVirtualForOf(value: DataSource<T> | Observable<T[]> | NgIterable<T>) {
8490
this._cdkVirtualForOf = value;
85-
const ds = value instanceof DataSource ? value :
91+
const ds = isDataSource(value) ? value :
8692
// Slice the value if its an NgIterable to ensure we're working with an array.
8793
new ArrayDataSource<T>(
8894
value instanceof Observable ? value : Array.prototype.slice.call(value || []));

src/cdk/table/table.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
9+
import {CollectionViewer, DataSource, isDataSource} from '@angular/cdk/collections';
1010
import {
1111
AfterContentChecked,
1212
Attribute,
@@ -449,7 +449,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
449449
this._onDestroy.next();
450450
this._onDestroy.complete();
451451

452-
if (this.dataSource instanceof DataSource) {
452+
if (isDataSource(this.dataSource)) {
453453
this.dataSource.disconnect(this);
454454
}
455455
}
@@ -769,7 +769,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
769769
private _switchDataSource(dataSource: CdkTableDataSourceInput<T>) {
770770
this._data = [];
771771

772-
if (this.dataSource instanceof DataSource) {
772+
if (isDataSource(this.dataSource)) {
773773
this.dataSource.disconnect(this);
774774
}
775775

@@ -796,12 +796,8 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
796796

797797
let dataStream: Observable<T[] | ReadonlyArray<T>> | undefined;
798798

799-
// Check if the datasource is a DataSource object by observing if it has a connect function.
800-
// Cannot check this.dataSource['connect'] due to potential property renaming, nor can it
801-
// checked as an instanceof DataSource<T> since the table should allow for data sources
802-
// that did not explicitly extend DataSource<T>.
803-
if ((this.dataSource as DataSource<T>).connect instanceof Function) {
804-
dataStream = (this.dataSource as DataSource<T>).connect(this);
799+
if (isDataSource(this.dataSource)) {
800+
dataStream = this.dataSource.connect(this);
805801
} else if (this.dataSource instanceof Observable) {
806802
dataStream = this.dataSource;
807803
} else if (Array.isArray(this.dataSource)) {

src/cdk/tree/tree.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {FocusableOption} from '@angular/cdk/a11y';
9-
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
9+
import {CollectionViewer, DataSource, isDataSource} from '@angular/cdk/collections';
1010
import {
1111
AfterContentChecked,
1212
ChangeDetectionStrategy,
@@ -185,10 +185,8 @@ export class CdkTree<T>
185185
private _observeRenderChanges() {
186186
let dataStream: Observable<T[] | ReadonlyArray<T>> | undefined;
187187

188-
// Cannot use `instanceof DataSource` since the data source could be a literal with
189-
// `connect` function and may not extends DataSource.
190-
if (typeof (this._dataSource as DataSource<T>).connect === 'function') {
191-
dataStream = (this._dataSource as DataSource<T>).connect(this);
188+
if (isDataSource(this._dataSource)) {
189+
dataStream = this._dataSource.connect(this);
192190
} else if (this._dataSource instanceof Observable) {
193191
dataStream = this._dataSource;
194192
} else if (Array.isArray(this._dataSource)) {

tools/public_api_guard/cdk/collections.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export declare abstract class DataSource<T> {
1515

1616
export declare function getMultipleValuesInSingleSelectionError(): Error;
1717

18+
export declare function isDataSource(value: any): value is DataSource<any>;
19+
1820
export declare type ListRange = {
1921
start: number;
2022
end: number;

0 commit comments

Comments
 (0)