mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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`.
This commit is contained in:
committed by
mmalerba
parent
64010d785b
commit
0ab81138cd
@@ -29,3 +29,11 @@ export abstract class DataSource<T> {
|
||||
*/
|
||||
abstract disconnect(collectionViewer: CollectionViewer): void;
|
||||
}
|
||||
|
||||
/** Checks whether an object is a data source. */
|
||||
export function isDataSource(value: any): value is DataSource<any> {
|
||||
// Check if the value is a DataSource by observing if it has a connect function. Cannot
|
||||
// be checked as an `instanceof DataSource` since people could create their own sources
|
||||
// that match the interface, but don't extend DataSource.
|
||||
return value && typeof value.connect === 'function';
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ArrayDataSource, CollectionViewer, DataSource, ListRange} from '@angular/cdk/collections';
|
||||
import {
|
||||
ArrayDataSource,
|
||||
CollectionViewer,
|
||||
DataSource,
|
||||
ListRange,
|
||||
isDataSource,
|
||||
} from '@angular/cdk/collections';
|
||||
import {
|
||||
Directive,
|
||||
DoCheck,
|
||||
@@ -82,7 +88,7 @@ export class CdkVirtualForOf<T> implements CollectionViewer, DoCheck, OnDestroy
|
||||
}
|
||||
set cdkVirtualForOf(value: DataSource<T> | Observable<T[]> | NgIterable<T>) {
|
||||
this._cdkVirtualForOf = value;
|
||||
const ds = value instanceof DataSource ? value :
|
||||
const ds = isDataSource(value) ? value :
|
||||
// Slice the value if its an NgIterable to ensure we're working with an array.
|
||||
new ArrayDataSource<T>(
|
||||
value instanceof Observable ? value : Array.prototype.slice.call(value || []));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
|
||||
import {CollectionViewer, DataSource, isDataSource} from '@angular/cdk/collections';
|
||||
import {
|
||||
AfterContentChecked,
|
||||
Attribute,
|
||||
@@ -449,7 +449,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
|
||||
this._onDestroy.next();
|
||||
this._onDestroy.complete();
|
||||
|
||||
if (this.dataSource instanceof DataSource) {
|
||||
if (isDataSource(this.dataSource)) {
|
||||
this.dataSource.disconnect(this);
|
||||
}
|
||||
}
|
||||
@@ -769,7 +769,7 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
|
||||
private _switchDataSource(dataSource: CdkTableDataSourceInput<T>) {
|
||||
this._data = [];
|
||||
|
||||
if (this.dataSource instanceof DataSource) {
|
||||
if (isDataSource(this.dataSource)) {
|
||||
this.dataSource.disconnect(this);
|
||||
}
|
||||
|
||||
@@ -796,12 +796,8 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
|
||||
|
||||
let dataStream: Observable<T[] | ReadonlyArray<T>> | undefined;
|
||||
|
||||
// Check if the datasource is a DataSource object by observing if it has a connect function.
|
||||
// Cannot check this.dataSource['connect'] due to potential property renaming, nor can it
|
||||
// checked as an instanceof DataSource<T> since the table should allow for data sources
|
||||
// that did not explicitly extend DataSource<T>.
|
||||
if ((this.dataSource as DataSource<T>).connect instanceof Function) {
|
||||
dataStream = (this.dataSource as DataSource<T>).connect(this);
|
||||
if (isDataSource(this.dataSource)) {
|
||||
dataStream = this.dataSource.connect(this);
|
||||
} else if (this.dataSource instanceof Observable) {
|
||||
dataStream = this.dataSource;
|
||||
} else if (Array.isArray(this.dataSource)) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {FocusableOption} from '@angular/cdk/a11y';
|
||||
import {CollectionViewer, DataSource} from '@angular/cdk/collections';
|
||||
import {CollectionViewer, DataSource, isDataSource} from '@angular/cdk/collections';
|
||||
import {
|
||||
AfterContentChecked,
|
||||
ChangeDetectionStrategy,
|
||||
@@ -185,10 +185,8 @@ export class CdkTree<T>
|
||||
private _observeRenderChanges() {
|
||||
let dataStream: Observable<T[] | ReadonlyArray<T>> | undefined;
|
||||
|
||||
// Cannot use `instanceof DataSource` since the data source could be a literal with
|
||||
// `connect` function and may not extends DataSource.
|
||||
if (typeof (this._dataSource as DataSource<T>).connect === 'function') {
|
||||
dataStream = (this._dataSource as DataSource<T>).connect(this);
|
||||
if (isDataSource(this._dataSource)) {
|
||||
dataStream = this._dataSource.connect(this);
|
||||
} else if (this._dataSource instanceof Observable) {
|
||||
dataStream = this._dataSource;
|
||||
} else if (Array.isArray(this._dataSource)) {
|
||||
|
||||
+2
@@ -15,6 +15,8 @@ export declare abstract class DataSource<T> {
|
||||
|
||||
export declare function getMultipleValuesInSingleSelectionError(): Error;
|
||||
|
||||
export declare function isDataSource(value: any): value is DataSource<any>;
|
||||
|
||||
export declare type ListRange = {
|
||||
start: number;
|
||||
end: number;
|
||||
|
||||
Reference in New Issue
Block a user