I have a cascading DropDownList scenario with virtual scrolling. When the first DropDownList changes value, the second one should reset its scrollbar to the top, because it now contains new data. This doesn't happen.
Here is a REPL test page.
===
ADMIN EDIT
===
As a workaround for the time being, you may track when the value is changed in the parent DropDownList to dispose and re-initialize the child DropDownList.
Here is an example: https://blazorrepl.telerik.com/mdafHabk585ZtzyV54.
Hello,
If I scroll the page down and open a filterable DropDownList, the page will scroll up.
Here is a REPL test page
UI for Blazor 2.30 works as expected. This broke in version 3.0.0. The issue exists only in WebAssembly apps.
The following knowledge base article describes how to select the default value in a drop down, but if there's no default value the selection is not cleared using this method.
When setting the bind value to null (or the default, or frankly anything that doesn't exist in the drop down) I'd like the drop down list selection to be cleared when there's no default value set on the DropDownList.
@page "/"
<br />
<TelerikButton OnClick="@ClearSelection">Clear selection</TelerikButton>
<TelerikDropDownList Data="@data" @bind-Value="selectedValue" />
@code {
List<string> data = new() { "selection" };
string selectedValue;
void ClearSelection()
{
// This does not cause the drop down to clear the selection and I think it should.
selectedValue = null;
}
}
Hello,
would it be possible to add "OnFocus" event to DropDownList as there is already "OnBlur" event?
Thanks
---
ADMIN EDIT
This behavior is observed in the DropDownList when filtering is enabled and in the ComboBox regardless of whether filtering is enabled or not.
The (filter) input gets focus, which shows the soft keyboard, which changes the viewport size, which causes the dropdown to hide. Unfortunately, there is no workaround at the moment (except perhaps disabling filtering for small viewports).
---
The DropDownList component is too basic to be used in complex environments. In the real world, no one is binding DropDownLists to List<string>, they are binding to complex datatypes, and the ability to do so has been present in MVC apps for a long time.
Given the following code, it is possible to bind to a List<object>, and two-way bind to the object that was selected.
<select @onchange="@OnChangedAsync">
<option></option>
@if (DataSource != null)
{
@foreach (var item in DataSource)
{
<option @key="item" value="@optionValueFunc(item)" selected="@(item.Equals(SelectedItem))">@optionTextFunc(item)</option>
}
}
</select>
#region Private Members
private Func<TSource, object> optionTextFunc;
private Func<TSource, object> optionValueFunc;
private TSource selectedItem = default(TSource);
#endregion
#region Public Parameters
/// <summary>
/// A List of objects to bind against.
/// </summary>
[Parameter]
public IList<TSource> DataSource { get; set; } = new List<TSource>();
/// <summary>
/// A lambda expression referencing the property containing the text to display to the end user. Example: @(c => c.DisplayName)
/// </summary>
[Parameter]
public Expression<Func<TSource, object>> OptionText { get; set; }
/// <summary>
/// A lambda expression referencing the property containing the value for this object, usually an identifier. Example: @(c => c.Id)
/// </summary>
[Parameter]
public Expression<Func<TSource, object>> OptionValue { get; set; }
/// <summary>
/// The item from the <see cref="DataSource" /> that has been selected.
/// </summary>
[Parameter]
public TSource SelectedItem { get; set; }
/// <summary>
/// The callback event required for two-way binding.
/// </summary>
[Parameter]
public EventCallback<TSource> SelectedItemChanged { get; set; }
#endregion
private async Task OnChangedAsync(ChangeEventArgs changeEventArgs)
{
await UpdateSelection(DataSource.FirstOrDefault(c => optionValueFunc(c).ToString() == changeEventArgs.Value.ToString()));
}
private async Task UpdateSelection(TSource item)
{
selectedItem = item;
await SelectedItemChanged.InvokeAsync(selectedItem);
}
protected override async Task OnInitializedAsync()
{
if (optionTextFunc == null && OptionText != null)
{
optionTextFunc = OptionText.Compile();
}
if (optionValueFunc == null && OptionText != null)
{
optionValueFunc = OptionValue.Compile();
}
await Task.CompletedTask;
}
Would really appreciate it if you would consider adding this to the next release.
The drop down list component does not allow the user to associate a label with the underlying html select input control, which goes against accessibility standards. It appears that most, if not all, of the other components follow the accessibility standards. Please fix the drop down list and/or allow attribute splatting so that developers can apply their own attributes (like aria-label) to meet accessibility standards.
---
ADMIN EDIT
Here is a reproducible with the workaround highlighted in green:
@using System.Collections.ObjectModel
<h4>Option Selected: 6 @selectedSix</h4>
<br />
<TelerikDropDownList Data="@myDdlData"
TextField="MyTextField"
ValueField="MyValueField"
@bind-Value="@selectedSix" />
<h4>Option Selected: 7 @selectedSeven</h4>
<br />
<TelerikDropDownList Data="@myDdlData"
TextField="MyTextField"
ValueField="MyValueField"
@bind-Value="@selectedSeven">
</TelerikDropDownList>
<TelerikButton OnClick="@AddOption">Add Item</TelerikButton>
<ul>
@foreach (var item in myDdlData)
{
<li>@item.MyValueField</li>
}
</ul>
@code {
int selectedSix { get; set; } = 6;
int selectedSeven { get; set; } = 7;
ObservableCollection<MyDdlModel> myDdlData = new ObservableCollection<MyDdlModel>(Enumerable.Range(1, 5).Select(x => new MyDdlModel { MyTextField = "item " + x, MyValueField = x }));
protected override async Task OnInitializedAsync()
{
AddOption();
await Task.Delay(TimeSpan.FromSeconds(1));
AddOption();
}
void AddOption()
{
myDdlData.Add(new MyDdlModel { MyTextField = "item " + (myDdlData.Count + 1), MyValueField = myDdlData.Count + 1 });
int origSelection = selectedSeven;
selectedSeven = 0;
StateHasChanged();
//add this if it does not work
//await Task.Delay(30);//wait a rendering frame
selectedSeven = origSelection;
//add this if it does not work
//StateHasChanged();
}
public class MyDdlModel
{
public int MyValueField { get; set; }
public string MyTextField { get; set; }
}
}
Note: This behavior also occurs if the initial data is received after the component is initialized. The workaround in this case will be similar - set the selected value after the data is received.
---
When used in Bootstrap Grid the DropDownList popup is misaligned on the first open. On a second click, it is aligned.
This behavior is also valid for Combobox and Autocomplete.
Reproduction code:
<div class="box">
<div class="row mt-3" style="align-items:center">
<div class="col-12 col-lg-4">
<span class="bold">ComboBox</span>
</div>
<div class="col">
<TelerikComboBox Data="@myComboData" TextField="ComboTextField" ValueField="ComboValueField"
@bind-Value="selectedCombo" ClearButton="true" Filterable="true">
</TelerikComboBox>
</div>
</div>
<div class="row mt-3" style="align-items:center">
<div class="col-12 col-lg-4">
<span class="bold">DropDownList</span>
</div>
<div class="col">
<TelerikDropDownList Data="@myDdlData" TextField="MyTextField" ValueField="MyValueField"
@bind-Value="@selectedDropDown">
</TelerikDropDownList>
</div>
</div>
<div class="row mt-3" style="align-items:center">
<div class="col-12 col-lg-4">
<span class="bold">Autocomplete</span>
</div>
<div class="col">
<TelerikAutoComplete Data="@Suggestions" @bind-Value="@AutoCompleteValue"
ClearButton="true" />
</div>
</div>
</div>
@code {
public int selectedDropDown { get; set; }
public int selectedCombo { get; set; }
public string AutoCompleteValue { get; set; }
//ComboBox
public class ComboModel
{
public int ComboValueField { get; set; }
public string ComboTextField { get; set; }
}
IEnumerable<ComboModel> myComboData = Enumerable.Range(1, 20).Select(x => new ComboModel { ComboTextField = "item " + x, ComboValueField = x });
//DropDownList
public class MyDdlModel
{
public int MyValueField { get; set; }
public string MyTextField { get; set; }
}
IEnumerable<MyDdlModel> myDdlData = Enumerable.Range(1, 20).Select(x => new MyDdlModel { MyTextField = "item " + x, MyValueField = x });
//Autocomplete
List<string> Suggestions { get; set; } = new List<string> {
"Manager", "Developer", "QA", "Technical Writer", "Support Engineer", "Sales Agent", "Architect", "Designer"
};
}
I have two cascaded dropdownlists, in attached example car brands and selectable colors. The dependent dropdown has defaulttext option. After the parent dropdown has changed, in its event handler I reload the dependent data source and set a new valid value. If the data source does not contain the previous (!) value, the dropdownlist calls the valuechanged callback with default value. In next round when dependent dropdown holds the default value, after reloading datasource it works as expected. And parent changes again, if the updated datasource does not contain the previous dependent value the dropdownlist sets its value to default.
When I do not pass defaulttext parameter, the dependent dropdown selects the first element from the updated datasource. In my case it is not acceptable because I want to set a specific value (in this example the default color), not the first and not the default.
This feedback drives me to try setting value to default and wait for re-render the descendant dropdownlist before set the wanted value.
Is there any way to avoid this behaviour of the dropdownlist?
<TelerikDropDownList TItem="Brand"
TValue="int"
ValueField=@nameof(Brand.Id)
TextField=@nameof(Brand.Name)
Data="@BrandList"
Value="@Data.BrandId"
ValueChanged=@OnBrandChanged />
<TelerikDropDownList TItem="Color"
TValue="int"
ValueField=@nameof(Brand.Id)
TextField=@nameof(Brand.Name)
Data="@FilteredColorList"
Value="@Data.ColorId"
ValueChanged="@OnColorChanged"
DefaultText="select color ..." />
async Task OnBrandChanged(int brandId)
{
Data.ColorId = default;
await Task.Delay(5);
Data.BrandId = brandId;
Data.ColorId = GetDefaultColor(brandId);
FilteredColorList = GetFilteredColorList(brandId);
}
When the Default text value is changed by some business logic, the component does not react to that change to update the Default text value in the view model.
DropDownList should re-render on change of the Default text parameter
At the moment, typing with the keyboard focuses the first item that starts with the last letter you pressed. To focus the next one you should either use Down Arrow, or type the same letter again.
I would like it to behave like the regular <select> or like a combo box with filtering - typing characters quickly should highlight the item that begins with all those characters, instead of using only the first letter.
===
Admit edit: some keywords for better findability: DropDownList keyboard search filter accessibility