-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Cdk listbox control accessor #20071
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cdk listbox control accessor #20071
Conversation
@@ -67,6 +68,9 @@ export class CdkOption implements ListKeyManagerOption, Highlightable { | |||
this._disabled = coerceBooleanProperty(value); | |||
} | |||
|
|||
/** The form value of the option. */ | |||
@Input() value: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the option should be generic so people can type the value if they want to? E.g.
class CdkOption<T = any> {
value: T;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this seems like a good idea. Do you know if there's a reason why MatOption doesn't do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, MatOption
didn't do this because we didn't know any better back when we wrote it. I would, though, use unknown
instead of any
for the default
this.deselect(option); | ||
} | ||
|
||
for (const value of values) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this break down if the value
isn't an array? Based on the typing it could be a string which will work inside the for...of
loop, but will loop through character by character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I neglected to test that out. I'll test out different methods and find a way to handle it. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to Kristiyan's comments; once those are good you should be able to add the unit tests
@@ -67,6 +68,9 @@ export class CdkOption implements ListKeyManagerOption, Highlightable { | |||
this._disabled = coerceBooleanProperty(value); | |||
} | |||
|
|||
/** The form value of the option. */ | |||
@Input() value: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, MatOption
didn't do this because we didn't know any better back when we wrote it. I would, though, use unknown
instead of any
for the default
…terate through string characters.
Addressed feedback and added some unit tests. |
_onTouched: () => void = () => {}; | ||
|
||
/** `View -> model callback called when value changes` */ | ||
_onChange: (value: any) => void = () => {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_onChange: (value: any) => void = () => {}; | |
_onChange: (value: T) => void = () => {}; |
@@ -235,6 +244,8 @@ export class CdkListbox implements AfterContentInit, OnDestroy, OnInit { | |||
this._useActiveDescendant = coerceBooleanProperty(shouldUseActiveDescendant); | |||
} | |||
|
|||
@Input() compareWith: (o1: any, o2: any) => boolean = (a1, a2) => a1 === a2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Input() compareWith: (o1: any, o2: any) => boolean = (a1, a2) => a1 === a2; | |
@Input() compareWith: (o1: T, o2: T) => boolean = (a1, a2) => a1 === a2; |
* Saves a callback function to be invoked when the select's value | ||
* changes from user input. Required to implement ControlValueAccessor. | ||
*/ | ||
registerOnChange(fn: (value: any) => void): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
registerOnChange(fn: (value: any) => void): void { | |
registerOnChange(fn: (value: T) => void): void { |
@@ -178,12 +182,18 @@ export class CdkOption implements ListKeyManagerOption, Highlightable { | |||
'[attr.aria-activedescendant]': '_getAriaActiveDescendant()' | |||
} | |||
}) | |||
export class CdkListbox implements AfterContentInit, OnDestroy, OnInit { | |||
export class CdkListbox implements AfterContentInit, OnDestroy, OnInit, ControlValueAccessor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export class CdkListbox implements AfterContentInit, OnDestroy, OnInit, ControlValueAccessor { | |
export class CdkListbox<T> implements AfterContentInit, OnDestroy, OnInit, ControlValueAccessor { |
And all references to CdkOption
throughout should be CdkOption<T>
} | ||
|
||
/** Sets the select's value. Required to implement ControlValueAccessor. */ | ||
writeValue(values: any | any[]): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
writeValue(values: any | any[]): void { | |
writeValue(value: T | T[]): void { |
} | ||
|
||
/** Selects an option that has the corresponding given value. */ | ||
private _setSelectionByValue(values: any | any[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private _setSelectionByValue(values: any | any[]) { | |
private _setSelectionByValue(values: T| T[]) { |
} | ||
|
||
const valuesArray = coerceArray(values); | ||
console.log(valuesArray); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra log
@@ -655,3 +738,23 @@ class ListboxActiveDescendant { | |||
this.focusedOption = option; | |||
} | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also add test cases for actually using the listbox with a FormControl
, and then testing that the interaction works as expected via that FormControl
…it tests for using form control.
Feedback address. Ready for review and check on the changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like there's a few lingering any
types in the listbox that can be T
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Implemented ControlValueAccessor in listbox, which entailed adding a
value
property and implementing several required methods. This is done to allow for listbox to be used with form control.