Skip to content

Commit aa42b04

Browse files
committed
refactor(material/core): Update internal state of option to use signals
This updates the internal state to use signals, eliminating any ExpressionChanged... issues when developers programatically update disabled or selected state during change detection.
1 parent 22b68e0 commit aa42b04

File tree

1 file changed

+17
-21
lines changed

1 file changed

+17
-21
lines changed

src/material/core/option/option.ts

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
QueryList,
2525
ViewChild,
2626
booleanAttribute,
27+
signal,
2728
} from '@angular/core';
2829
import {Subject} from 'rxjs';
2930
import {MAT_OPTGROUP, MatOptgroup} from './optgroup';
@@ -83,9 +84,9 @@ export class MatOptionSelectionChange<T = any> {
8384
imports: [MatPseudoCheckbox, MatRipple],
8485
})
8586
export class MatOption<T = any> implements FocusableOption, AfterViewChecked, OnDestroy {
86-
private _selected = false;
87-
private _active = false;
88-
private _disabled = false;
87+
private _selected = signal(false);
88+
private _active = signal(false);
89+
private _disabled = signal(false);
8990
private _mostRecentViewValue = '';
9091

9192
/** Whether the wrapping component is in multiple selection mode. */
@@ -95,7 +96,7 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
9596

9697
/** Whether or not the option is currently selected. */
9798
get selected(): boolean {
98-
return this._selected;
99+
return this._selected();
99100
}
100101

101102
/** The form value of the option. */
@@ -107,10 +108,10 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
107108
/** Whether the option is disabled. */
108109
@Input({transform: booleanAttribute})
109110
get disabled(): boolean {
110-
return (this.group && this.group.disabled) || this._disabled;
111+
return (this.group && this.group.disabled) || this._disabled();
111112
}
112113
set disabled(value: boolean) {
113-
this._disabled = value;
114+
this._disabled.set(value);
114115
}
115116

116117
/** Whether ripples for the option are disabled. */
@@ -147,7 +148,7 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
147148
* for components like autocomplete where focus must remain on the input.
148149
*/
149150
get active(): boolean {
150-
return this._active;
151+
return this._active();
151152
}
152153

153154
/**
@@ -161,9 +162,8 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
161162

162163
/** Selects the option. */
163164
select(emitEvent = true): void {
164-
if (!this._selected) {
165-
this._selected = true;
166-
this._changeDetectorRef.markForCheck();
165+
if (!this._selected()) {
166+
this._selected.set(true);
167167

168168
if (emitEvent) {
169169
this._emitSelectionChangeEvent();
@@ -173,9 +173,8 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
173173

174174
/** Deselects the option. */
175175
deselect(emitEvent = true): void {
176-
if (this._selected) {
177-
this._selected = false;
178-
this._changeDetectorRef.markForCheck();
176+
if (this._selected()) {
177+
this._selected.set(false);
179178

180179
if (emitEvent) {
181180
this._emitSelectionChangeEvent();
@@ -200,9 +199,8 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
200199
* events will display the proper options as active on arrow key events.
201200
*/
202201
setActiveStyles(): void {
203-
if (!this._active) {
204-
this._active = true;
205-
this._changeDetectorRef.markForCheck();
202+
if (!this._active()) {
203+
this._active.set(true);
206204
}
207205
}
208206

@@ -213,8 +211,7 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
213211
*/
214212
setInactiveStyles(): void {
215213
if (this._active) {
216-
this._active = false;
217-
this._changeDetectorRef.markForCheck();
214+
this._active.set(false);
218215
}
219216
}
220217

@@ -239,8 +236,7 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
239236
*/
240237
_selectViaInteraction(): void {
241238
if (!this.disabled) {
242-
this._selected = this.multiple ? !this._selected : true;
243-
this._changeDetectorRef.markForCheck();
239+
this._selected.set(this.multiple ? !this._selected() : true);
244240
this._emitSelectionChangeEvent(true);
245241
}
246242
}
@@ -264,7 +260,7 @@ export class MatOption<T = any> implements FocusableOption, AfterViewChecked, On
264260
// we have to check for changes in the DOM ourselves and dispatch an event. These checks are
265261
// relatively cheap, however we still limit them only to selected options in order to avoid
266262
// hitting the DOM too often.
267-
if (this._selected) {
263+
if (this._selected()) {
268264
const viewValue = this.viewValue;
269265

270266
if (viewValue !== this._mostRecentViewValue) {

0 commit comments

Comments
 (0)