Skip to content

Commit 1926ee2

Browse files
committed
Address jelbourn's review comments
1 parent 8b279b5 commit 1926ee2

File tree

10 files changed

+140
-147
lines changed

10 files changed

+140
-147
lines changed

src/cdk-experimental/selection/BUILD.bazel

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package(default_visibility = ["//visibility:public"])
22

3-
load("//src/e2e-app:test_suite.bzl", "e2e_test_suite")
4-
load("//tools:defaults.bzl", "ng_e2e_test_library", "ng_module", "ng_test_library", "ng_web_test_suite")
3+
load("//tools:defaults.bzl", "ng_module")
54

65
ng_module(
76
name = "selection",

src/cdk-experimental/selection/row-selection.ts

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

9-
import {Directive, HostBinding, Input} from '@angular/core';
9+
import {coerceNumberProperty, NumberInput} from '@angular/cdk/coercion';
10+
import {Directive, Input} from '@angular/core';
1011

1112
import {CdkSelection} from './selection';
1213

@@ -19,31 +20,24 @@ import {CdkSelection} from './selection';
1920
*/
2021
@Directive({
2122
selector: '[cdkRowSelection]',
23+
host: {
24+
'[class.cdk-selected]': '_selection.isSelected(this._value, this._index)',
25+
'[attr.aria-selected]': '_selection.isSelected(this._value, this._index)',
26+
},
2227
})
2328
export class CdkRowSelection<T> {
24-
@Input()
25-
get cdkRowSelectionValue(): T {
26-
return this._value;
27-
}
28-
set cdkRowSelectionValue(value: T) {
29-
this._value = value;
30-
}
31-
_value: T;
29+
@Input('cdkRowSelectionValue') _value: T;
3230

33-
@Input()
34-
get cdkRowSelectionIndex(): number|undefined {
31+
@Input('cdkRowSelectionIndex')
32+
get index(): number|undefined {
3533
return this._index;
3634
}
37-
set cdkRowSelectionIndex(index: number|undefined) {
38-
this._index = index;
35+
set index(index: number|undefined) {
36+
this._index = coerceNumberProperty(index);
3937
}
4038
_index?: number;
4139

42-
constructor(private readonly _selection: CdkSelection<T>) {}
40+
constructor(readonly _selection: CdkSelection<T>) {}
4341

44-
@HostBinding('class.cdk-selected')
45-
@HostBinding('attr.aria-selected')
46-
get isSelected() {
47-
return this._selection.isSelected(this._value, this._index);
48-
}
42+
static ngAcceptInputType_index: NumberInput;
4943
}

src/cdk-experimental/selection/select-all.ts

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

9-
import {Directive, Inject, OnDestroy, OnInit, Optional, Self} from '@angular/core';
9+
import {Directive, Inject, isDevMode, OnDestroy, OnInit, Optional, Self} from '@angular/core';
1010
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
11-
import {BehaviorSubject, of as observableOf, Subject} from 'rxjs';
11+
import {Observable, of as observableOf, ReplaySubject} from 'rxjs';
1212
import {switchMap, takeUntil} from 'rxjs/operators';
1313

1414
import {CdkSelection} from './selection';
@@ -32,14 +32,18 @@ export class CdkSelectAll<T> implements OnDestroy, OnInit {
3232
* The checked state of the toggle.
3333
* Resolves to `true` if all the values are selected, `false` if no value is selected.
3434
*/
35-
readonly checked$ = new BehaviorSubject(false);
35+
readonly checked: Observable<boolean> = this._selection.change.pipe(
36+
switchMap(() => observableOf(this._selection.isAllSelected())),
37+
);
3638

3739
/**
3840
* The indeterminate state of the toggle.
3941
* Resolves to `true` if part (not all) of the values are selected, `false` if all values or no
4042
* value at all are selected.
4143
*/
42-
readonly indeterminate$ = new BehaviorSubject(false);
44+
readonly indeterminate: Observable<boolean> = this._selection.change.pipe(
45+
switchMap(() => observableOf(this._selection.isPartialSelected())),
46+
);
4347

4448
/**
4549
* Toggles the select-all state.
@@ -60,55 +64,43 @@ export class CdkSelectAll<T> implements OnDestroy, OnInit {
6064
});
6165
}
6266

63-
private readonly _destroyed$ = new Subject();
67+
private readonly _destroyed = new ReplaySubject(1);
6468

6569
constructor(
6670
@Optional() private readonly _selection: CdkSelection<T>,
6771
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) private readonly _controlValueAccessor:
6872
ControlValueAccessor[]) {}
6973

7074
ngOnInit() {
71-
if (!this._selection) {
72-
throw new Error('CdkSelectAll: missing CdkSelection in the parent');
73-
}
74-
75-
if (!this._selection.cdkSelectionMultiple) {
76-
throw new Error('CdkSelectAll: CdkSelection must have cdkSelectionMultiple set to true');
77-
}
78-
79-
this._selection.cdkSelectionChange
80-
.pipe(
81-
switchMap(() => observableOf(this._selection.isAllSelected())),
82-
takeUntil(this._destroyed$),
83-
)
84-
.subscribe((state) => {
85-
this.checked$.next(state);
86-
});
87-
88-
this._selection.cdkSelectionChange
89-
.pipe(
90-
switchMap(() => observableOf(this._selection.isPartialSelected())),
91-
takeUntil(this._destroyed$),
92-
)
93-
.subscribe((state) => {
94-
this.indeterminate$.next(state);
95-
});
75+
this._assertValidParentSelection();
76+
this._configureControlValueAccessor();
77+
}
9678

79+
private _configureControlValueAccessor() {
9780
if (this._controlValueAccessor && this._controlValueAccessor.length) {
9881
this._controlValueAccessor[0].registerOnChange((e: unknown) => {
9982
if (e === true || e === false) {
10083
this.toggle();
10184
}
10285
});
103-
104-
this.checked$.pipe(takeUntil(this._destroyed$)).subscribe((state) => {
86+
this.checked.pipe(takeUntil(this._destroyed)).subscribe((state) => {
10587
this._controlValueAccessor[0].writeValue(state);
10688
});
10789
}
10890
}
10991

92+
private _assertValidParentSelection() {
93+
if (!this._selection && isDevMode()) {
94+
throw Error('CdkSelectAll: missing CdkSelection in the parent');
95+
}
96+
97+
if (!this._selection.multiple && isDevMode()) {
98+
throw Error('CdkSelectAll: CdkSelection must have cdkSelectionMultiple set to true');
99+
}
100+
}
101+
110102
ngOnDestroy() {
111-
this._destroyed$.next();
112-
this._destroyed$.complete();
103+
this._destroyed.next();
104+
this._destroyed.complete();
113105
}
114106
}

src/cdk-experimental/selection/selection-column.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {CdkCellDef, CdkColumnDef, CdkHeaderCellDef, CdkTable} from '@angular/cdk
1010
import {
1111
Component,
1212
Input,
13+
isDevMode,
1314
OnDestroy,
1415
OnInit,
1516
Optional,
@@ -29,11 +30,11 @@ import {CdkSelection} from './selection';
2930
template: `
3031
<ng-container cdkColumnDef>
3132
<th cdkHeaderCell *cdkHeaderCellDef>
32-
<input type="checkbox" *ngIf="selection.cdkSelectionMultiple"
33+
<input type="checkbox" *ngIf="selection.multiple"
3334
cdkSelectAll
3435
#allToggler="cdkSelectAll"
35-
[checked]="allToggler.checked$ | async"
36-
[indeterminate]="allToggler.indeterminate$ | async"
36+
[checked]="allToggler.checked | async"
37+
[indeterminate]="allToggler.indeterminate | async"
3738
(click)="allToggler.toggle($event)">
3839
</th>
3940
<td cdkCell *cdkCellDef="let row; let i = $index">
@@ -43,18 +44,18 @@ import {CdkSelection} from './selection';
4344
[cdkSelectionToggleValue]="row"
4445
[cdkSelectionToggleIndex]="i"
4546
(click)="toggler.toggle()"
46-
[checked]="toggler.checked$ | async">
47+
[checked]="toggler.checked | async">
4748
</td>
4849
</ng-container>
4950
`,
5051
})
5152
export class CdkSelectionColumn<T> implements OnInit, OnDestroy {
5253
/** Column name that should be used to reference this column. */
53-
@Input()
54-
get cdkSelectionColumnName(): string {
54+
@Input('cdkSelectionColumnName')
55+
get name(): string {
5556
return this._name;
5657
}
57-
set cdkSelectionColumnName(name: string) {
58+
set name(name: string) {
5859
this._name = name;
5960

6061
this.syncColumnDefName();
@@ -71,8 +72,8 @@ export class CdkSelectionColumn<T> implements OnInit, OnDestroy {
7172
) {}
7273

7374
ngOnInit() {
74-
if (!this.selection) {
75-
throw new Error('CdkSelectionColumn: missing CdkSelection in the parent');
75+
if (!this.selection && isDevMode()) {
76+
throw Error('CdkSelectionColumn: missing CdkSelection in the parent');
7677
}
7778

7879
this.syncColumnDefName();
@@ -82,7 +83,9 @@ export class CdkSelectionColumn<T> implements OnInit, OnDestroy {
8283
this._columnDef.headerCell = this._headerCell;
8384
this.table.addColumnDef(this._columnDef);
8485
} else {
85-
throw new Error('CdkSelectionColumn: missing parent table');
86+
if (isDevMode()) {
87+
throw Error('CdkSelectionColumn: missing parent table');
88+
}
8689
}
8790
}
8891

src/cdk-experimental/selection/selection-set.ts

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

9-
import {TrackByFunction} from '@angular/core';
9+
import {isDevMode, TrackByFunction} from '@angular/core';
1010
import {Subject} from 'rxjs';
1111

12+
/**
13+
* Maintains a set of selected values. One or more values can be added to or removed from the
14+
* selection.
15+
*/
1216
interface TrackBySelection<T> {
1317
isSelected(value: SelectableWithIndex<T>): boolean;
1418
select(...values: Array<SelectableWithIndex<T>>): void;
1519
deselect(...values: Array<SelectableWithIndex<T>>): void;
16-
changed$: Subject<SelectionChange<T>>;
20+
changed: Subject<SelectionChange<T>>;
1721
}
1822

1923
/**
@@ -42,7 +46,7 @@ export interface SelectionChange<T> {
4246
*/
4347
export class SelectionSet<T> implements TrackBySelection<T> {
4448
private selectionMap = new Map<T|ReturnType<TrackByFunction<T>>, SelectableWithIndex<T>>();
45-
changed$ = new Subject<SelectionChange<T>>();
49+
changed = new Subject<SelectionChange<T>>();
4650

4751
constructor(private _multiple = false, private _trackByFn?: TrackByFunction<T>) {}
4852

@@ -51,8 +55,8 @@ export class SelectionSet<T> implements TrackBySelection<T> {
5155
}
5256

5357
select(...selects: Array<SelectableWithIndex<T>>) {
54-
if (!this._multiple && selects.length > 1) {
55-
throw new Error('SelectionSet: not multiple selection');
58+
if (!this._multiple && selects.length > 1 && isDevMode()) {
59+
throw Error('SelectionSet: not multiple selection');
5660
}
5761

5862
const before = this._getCurrentSelection();
@@ -73,12 +77,12 @@ export class SelectionSet<T> implements TrackBySelection<T> {
7377

7478
const after = this._getCurrentSelection();
7579

76-
this.changed$.next({before, after});
80+
this.changed.next({before, after});
7781
}
7882

7983
deselect(...selects: Array<SelectableWithIndex<T>>) {
80-
if (!this._multiple && selects.length > 1) {
81-
throw new Error('SelectionSet: not multiple selection');
84+
if (!this._multiple && selects.length > 1 && isDevMode()) {
85+
throw Error('SelectionSet: not multiple selection');
8286
}
8387

8488
const before = this._getCurrentSelection();
@@ -94,7 +98,7 @@ export class SelectionSet<T> implements TrackBySelection<T> {
9498
}
9599

96100
const after = this._getCurrentSelection();
97-
this.changed$.next({before, after});
101+
this.changed.next({before, after});
98102
}
99103

100104
private _markSelected(key: T|ReturnType<TrackByFunction<T>>, toSelect: SelectableWithIndex<T>) {
@@ -110,11 +114,11 @@ export class SelectionSet<T> implements TrackBySelection<T> {
110114
return select.value;
111115
}
112116

113-
if (select.index == null) {
114-
throw new Error('SelectionSet: index required when trackByFn is used.');
117+
if (select.index == null && isDevMode()) {
118+
throw Error('SelectionSet: index required when trackByFn is used.');
115119
}
116120

117-
return this._trackByFn(select.index, select.value);
121+
return this._trackByFn(select.index!, select.value);
118122
}
119123

120124
private _getCurrentSelection(): Array<SelectableWithIndex<T>> {

0 commit comments

Comments
 (0)