88
99namespace EventLogExpert . Shared . Components ;
1010
11- public sealed partial class ValueSelect < T > : BaseComponent < T >
11+ public sealed partial class ValueSelect < T > : BaseComponent < T > , IAsyncDisposable
1212{
1313 private readonly string _itemId = $ "select_{ Guid . NewGuid ( ) . ToString ( ) [ ..8 ] } ";
1414 private readonly List < ValueSelectItem < T > > _items = [ ] ;
@@ -30,6 +30,8 @@ public ValueSelectItem<T>? HighlightedItem
3030 get => _highlightedItem ;
3131 set
3232 {
33+ if ( ReferenceEquals ( _highlightedItem , value ) ) { return ; }
34+
3335 _highlightedItem = value ;
3436 StateHasChanged ( ) ;
3537 }
@@ -62,46 +64,64 @@ private string? DisplayString
6264
6365 [ Inject ] private IJSRuntime JSRuntime { get ; init ; } = null ! ;
6466
65- public bool AddItem ( ValueSelectItem < T > item )
67+ public void AddItem ( ValueSelectItem < T > item )
6668 {
67- if ( _items . Contains ( item ) )
69+ if ( ! _items . Contains ( item ) )
6870 {
69- return _selectedValues . Contains ( item . Value ) ;
71+ _items . Add ( item ) ;
7072 }
73+ }
7174
72- _items . Add ( item ) ;
75+ public async Task ClearAll ( )
76+ {
77+ _selectedValues . Clear ( ) ;
78+ _highlightedItem = null ;
7379
74- if ( IsMultiSelect && Values . Contains ( item . Value ) )
80+ if ( IsMultiSelect )
7581 {
76- _selectedValues . Add ( item . Value ) ;
77- return true ;
82+ Values . Clear ( ) ;
83+ await ValuesChanged . InvokeAsync ( Values ) ;
7884 }
85+ else
86+ {
87+ Value = default ! ;
88+ await ValueChanged . InvokeAsync ( Value ) ;
89+ }
90+ }
7991
80- if ( Value ? . Equals ( item . Value ) is not true ) { return false ; }
81-
82- _selectedValues . Clear ( ) ;
83- _selectedValues . Add ( item . Value ) ;
92+ public async Task CloseDropDown ( ) => await JSRuntime . InvokeVoidAsync ( "closeDropdown" , _selectComponent ) ;
8493
85- return true ;
94+ public async ValueTask DisposeAsync ( )
95+ {
96+ try
97+ {
98+ await JSRuntime . InvokeVoidAsync ( "unregisterDropdown" , _selectComponent ) ;
99+ }
100+ catch ( JSDisconnectedException )
101+ {
102+ // Expected during app shutdown
103+ }
86104 }
87105
88- public void ClearSelected ( ) => _selectedValues . Clear ( ) ;
89-
90- public async Task CloseDropDown ( ) => await JSRuntime . InvokeVoidAsync ( "closeDropdown" , _selectComponent ) ;
106+ public bool IsItemSelected ( T value ) => _selectedValues . Contains ( value ) ;
91107
92108 public async Task OpenDropDown ( ) => await JSRuntime . InvokeVoidAsync ( "openDropdown" , _selectComponent ) ;
93109
94- public void RemoveItem ( ValueSelectItem < T > item ) => _items . Remove ( item ) ;
110+ public void RemoveItem ( ValueSelectItem < T > item )
111+ {
112+ _items . Remove ( item ) ;
113+
114+ if ( ReferenceEquals ( _highlightedItem , item ) )
115+ {
116+ HighlightedItem = null ;
117+ }
118+ }
95119
96120 public async Task UpdateValue ( T item )
97121 {
98122 if ( IsMultiSelect )
99123 {
100- if ( item is null )
101- {
102- Values . Clear ( ) ;
103- }
104- else if ( _selectedValues . Remove ( item ) )
124+ if ( _selectedValues . Remove ( item ) )
105125 {
106126 Values . Remove ( item ) ;
107127 }
@@ -137,8 +157,27 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
137157 await base . OnAfterRenderAsync ( firstRender ) ;
138158 }
139159
160+ protected override void OnParametersSet ( )
161+ {
162+ _selectedValues . Clear ( ) ;
163+
164+ if ( IsMultiSelect )
165+ {
166+ foreach ( var v in Values )
167+ {
168+ _selectedValues . Add ( v ) ;
169+ }
170+ }
171+ else if ( Value is not null )
172+ {
173+ _selectedValues . Add ( Value ) ;
174+ }
175+ }
176+
140177 private async Task HandleKeyDown ( KeyboardEventArgs args )
141178 {
179+ _preventDefault = false ;
180+
142181 switch ( args . Code )
143182 {
144183 case "Space" :
@@ -164,10 +203,12 @@ private async Task HandleKeyDown(KeyboardEventArgs args)
164203 {
165204 if ( HighlightedItem . ClearItem )
166205 {
167- ClearSelected ( ) ;
206+ await ClearAll ( ) ;
207+ }
208+ else
209+ {
210+ await UpdateValue ( HighlightedItem . Value ) ;
168211 }
169-
170- await UpdateValue ( HighlightedItem . Value ) ;
171212 }
172213 else
173214 {
@@ -180,14 +221,15 @@ private async Task HandleKeyDown(KeyboardEventArgs args)
180221
181222 return ;
182223 }
183-
184- _preventDefault = false ;
185224 }
186225
187226 private async Task OnInputChange ( ChangeEventArgs args )
188227 {
189- Value = ( T ) Convert . ChangeType ( args . Value , typeof ( T ) ) ! ;
190- await ValueChanged . InvokeAsync ( Value ) ;
228+ if ( BindConverter . TryConvertTo < T > ( $ "{ args . Value } ", null , out var result ) )
229+ {
230+ Value = result ;
231+ await ValueChanged . InvokeAsync ( Value ) ;
232+ }
191233 }
192234
193235 private async Task SelectAdjacentItem ( int direction )
@@ -196,33 +238,30 @@ private async Task SelectAdjacentItem(int direction)
196238
197239 if ( IsMultiSelect || IsInput )
198240 {
199- index = _items . FindIndex ( x => x . Equals ( _items . FirstOrDefault ( item => item . Equals ( HighlightedItem ) ) ) ) ;
241+ index = HighlightedItem is not null ? _items . IndexOf ( HighlightedItem ) : - 1 ;
200242 }
201243 else
202244 {
203- index = _items . FindIndex ( x => x . Equals (
204- _items . FirstOrDefault ( item => item . Value ? . Equals ( _selectedValues . FirstOrDefault ( ) ) is true ) ) ) ;
245+ index = _items . FindIndex ( item => item . Value ? . Equals ( _selectedValues . FirstOrDefault ( ) ) is true ) ;
205246 }
206247
207- // Need to account for first item being an empty placeholder
208- if ( index < 0 ) { index = 0 ; }
248+ if ( index < 0 )
249+ {
250+ index = direction > 0 ? - 1 : _items . Count ;
251+ }
209252
210253 for ( int i = 0 ; i < _items . Count ; i ++ )
211254 {
212255 index += direction ;
213256
214- if ( index < 0 ) { index = 0 ; }
215-
216- if ( index >= _items . Count ) { index = _items . Count - 1 ; }
257+ if ( index < 0 || index >= _items . Count ) { return ; }
217258
218259 if ( _items [ index ] . IsDisabled ) { continue ; }
219260
220261 if ( IsMultiSelect || IsInput )
221262 {
222263 HighlightedItem = _items [ index ] ;
223264
224- StateHasChanged ( ) ;
225-
226265 await JSRuntime . InvokeVoidAsync ( "scrollToHighlightedItem" , _selectComponent ) ;
227266 }
228267 else
0 commit comments