Skip to content

Commit ba17a9e

Browse files
committed
fix(cdk-experimental/listbox): address comments
1 parent 488cd97 commit ba17a9e

File tree

2 files changed

+46
-28
lines changed

2 files changed

+46
-28
lines changed

src/cdk-experimental/listbox/listbox.ts

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
import {BooleanInput, coerceArray, coerceBooleanProperty} from '@angular/cdk/coercion';
3737
import {SelectionModel} from '@angular/cdk/collections';
3838
import {defer, merge, Observable, Subject} from 'rxjs';
39-
import {filter, map, startWith, switchMap, take, takeUntil} from 'rxjs/operators';
39+
import {filter, map, startWith, switchMap, takeUntil} from 'rxjs/operators';
4040
import {
4141
AbstractControl,
4242
ControlValueAccessor,
@@ -82,9 +82,9 @@ class ListboxSelectionModel<T> extends SelectionModel<T> {
8282
// The super class is always in multi-selection mode, so we need to override the behavior if
8383
// this selection model actually belongs to a single-selection listbox.
8484
if (this.multiple) {
85-
super.select(...values);
85+
return super.select(...values);
8686
} else {
87-
super.setSelection(...values);
87+
return super.setSelection(...values);
8888
}
8989
}
9090
}
@@ -545,7 +545,7 @@ export class CdkListbox<T = unknown>
545545
if (this._invalid) {
546546
this.selectionModel.clear(false);
547547
}
548-
this.selectionModel.select(...this.options.toArray().map(option => option.value));
548+
this.selectionModel.select(...this.options.map(option => option.value));
549549
}
550550
}
551551

@@ -635,15 +635,9 @@ export class CdkListbox<T = unknown>
635635
protected triggerOption(option: CdkOption<T> | null) {
636636
if (option && !option.disabled) {
637637
this._lastTriggered = option;
638-
let changed = false;
639-
this.selectionModel.changed
640-
.pipe(take(1), takeUntil(this.destroyed))
641-
.subscribe(() => (changed = true));
642-
if (this.multiple) {
643-
this.toggle(option);
644-
} else {
645-
this.select(option);
646-
}
638+
const changed = this.multiple
639+
? this.selectionModel.toggle(option.value)
640+
: this.selectionModel.select(option.value);
647641
if (changed) {
648642
this._onChange(this.value);
649643
this.valueChange.next({
@@ -669,10 +663,12 @@ export class CdkListbox<T = unknown>
669663
}
670664
this._lastTriggered = trigger;
671665
const isEqual = this.compareWith ?? Object.is;
672-
const options = this.options.toArray();
673-
const updateValues = options
674-
.slice(Math.max(0, Math.min(from, to)), Math.min(options.length, Math.max(from, to) + 1))
675-
.map(option => option.value);
666+
const updateValues = this.options
667+
.map(option => option.value)
668+
.slice(
669+
Math.max(0, Math.min(from, to)),
670+
Math.min(this.options.length, Math.max(from, to) + 1),
671+
);
676672
const selected = [...this.value];
677673
for (const updateValue of updateValues) {
678674
const selectedIndex = selected.findIndex(selectedValue =>
@@ -684,11 +680,7 @@ export class CdkListbox<T = unknown>
684680
selected.splice(selectedIndex, 1);
685681
}
686682
}
687-
let changed = false;
688-
this.selectionModel.changed
689-
.pipe(take(1), takeUntil(this.destroyed))
690-
.subscribe(() => (changed = true));
691-
this.selectionModel.setSelection(...selected);
683+
let changed = this.selectionModel.setSelection(...selected);
692684
if (changed) {
693685
this._onChange(this.value);
694686
this.valueChange.next({
@@ -989,6 +981,7 @@ export class CdkListbox<T = unknown>
989981
return values.filter(value => !validValues.some(validValue => isEqual(value, validValue)));
990982
}
991983

984+
/** Get the index of the last triggered option. */
992985
private _getLastTriggeredIndex() {
993986
const index = this.options.toArray().indexOf(this._lastTriggered!);
994987
return index === -1 ? null : index;

src/cdk/collections/selection-model.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,50 +56,70 @@ export class SelectionModel<T> {
5656

5757
/**
5858
* Selects a value or an array of values.
59+
* @param values The values to select
60+
* @return Whether the selection changed as a result of this call
5961
*/
60-
select(...values: T[]): void {
62+
select(...values: T[]) {
6163
this._verifyValueAssignment(values);
6264
values.forEach(value => this._markSelected(value));
65+
const changed = this._hasQueuedChanges();
6366
this._emitChangeEvent();
67+
return changed;
6468
}
6569

6670
/**
6771
* Deselects a value or an array of values.
72+
* @param values The values to deselect
73+
* @return Whether the selection changed as a result of this call
6874
*/
69-
deselect(...values: T[]): void {
75+
deselect(...values: T[]) {
7076
this._verifyValueAssignment(values);
7177
values.forEach(value => this._unmarkSelected(value));
78+
const changed = this._hasQueuedChanges();
7279
this._emitChangeEvent();
80+
return changed;
7381
}
7482

75-
setSelection(...values: T[]): void {
83+
/**
84+
* Sets the selected values
85+
* @param values The new selected values
86+
* @return Whether the selection changed as a result of this call
87+
*/
88+
setSelection(...values: T[]): boolean {
7689
this._verifyValueAssignment(values);
7790
const oldValues = this.selected;
7891
const newSelectedSet = new Set(values);
7992
values.forEach(value => this._markSelected(value));
8093
oldValues
8194
.filter(value => !newSelectedSet.has(value))
8295
.forEach(value => this._unmarkSelected(value));
96+
const changed = this._hasQueuedChanges();
8397
this._emitChangeEvent();
98+
return changed;
8499
}
85100

86101
/**
87102
* Toggles a value between selected and deselected.
103+
* @param value The value to toggle
104+
* @return Whether the selection changed as a result of this call
88105
*/
89-
toggle(value: T): void {
90-
this.isSelected(value) ? this.deselect(value) : this.select(value);
106+
toggle(value: T) {
107+
return this.isSelected(value) ? this.deselect(value) : this.select(value);
91108
}
92109

93110
/**
94111
* Clears all of the selected values.
95112
* @param flushEvent Whether to flush the changes in an event.
96113
* If false, the changes to the selection will be flushed along with the next event.
114+
* @return Whether the selection changed as a result of this call
97115
*/
98-
clear(flushEvent = true): void {
116+
clear(flushEvent = true) {
99117
this._unmarkAll();
118+
const changed = this._hasQueuedChanges();
100119
if (flushEvent) {
101120
this._emitChangeEvent();
102121
}
122+
return changed;
103123
}
104124

105125
/**
@@ -208,6 +228,11 @@ export class SelectionModel<T> {
208228
throw getMultipleValuesInSingleSelectionError();
209229
}
210230
}
231+
232+
/** Whether there are queued up change to be emitted. */
233+
private _hasQueuedChanges() {
234+
return !!(this._deselectedToEmit.length || this._selectedToEmit.length);
235+
}
211236
}
212237

213238
/**

0 commit comments

Comments
 (0)