Hello everyone,
We have opened this Feature Request to gather your insights on the addition of disabled items for the DropDownList.
For the time being, you can make items look disabled via DropDownListItemTemplate. Also, prevent clicks with @onclick and use the ValueChanged event to skip disabled items during keyboard navigation.
UPDATE: The associated built-in feature is the OnItemRender event, which can help style specific items without a template.
<TelerikDropDownList Data="@Products"
TItem="@Product"
TValue="@(int?)"
Value="@SelectedProductId"
ValueField="@nameof(Product.Id)"
TextField="@nameof(Product.Name)"
DefaultText="Select Product..."
ValueChanged="@( (int? newValue) => SelectedProductChanged(newValue) )"
Width="200px">
<DropDownListSettings>
<DropDownListPopupSettings Class="disabled-items" />
</DropDownListSettings>
<ItemTemplate>
@{ var p = context as Product; }
<div class="item-div @( !p.Active ? "disabled" : "" )"
@onclick:preventDefault="@(!p.Active)"
@onclick:stopPropagation="@(!p.Active)">
@p.Name
</div>
</ItemTemplate>
</TelerikDropDownList>
<style>
/* remove default item padding to prevent selection outside the template div */
.disabled-items .k-list-item {
padding: 0;
}
/* add back inner padding */
.disabled-items .item-div {
padding: 4px 8px;
}
/* style disabled items */
.disabled-items .disabled {
cursor: not-allowed;
width: 100%;
color: #ccc;
}
</style>
@code {
private List<Product> Products { get; set; }
private int? SelectedProductId { get; set; }
private async Task SelectedProductChanged(int? newValue)
{
var newProduct = Products.FirstOrDefault(x => x.Id == newValue);
if (newProduct?.Active == true || !newValue.HasValue)
{
// select only active items or DefaultText
SelectedProductId = newValue;
}
else
{
// skip disabled items during keyboard navigation
var oldProductIndex = Products.FindIndex(x => x.Id == SelectedProductId);
var newProductIndex = Products.FindIndex(x => x.Id == newValue);
if (newProductIndex > oldProductIndex)
{
// skip forward
SelectedProductId = Products[++newProductIndex].Id;
}
else
{
// skip backward
SelectedProductId = Products[--newProductIndex].Id;
}
}
}
protected override void OnInitialized()
{
Products = new List<Product>();
for (int i = 1; i <= 7; i++)
{
var active = i % 3 != 0;
Products.Add(new Product()
{
Id = i,
Name = (active ? "" : "Disabled ") + "Product " + i,
Active = active
});
}
base.OnInitialized();
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
}
Clicking on the <label> opens the dropdown, but clicking on its main element does not
Selected value: @selectedValue
<br />
<label>some label for the dropdown, open it and test whether clicking outside closes it
<TelerikDropDownList Data="@myDdlData" TextField="MyTextField" ValueField="MyValueField" @bind-Value="selectedValue">
</TelerikDropDownList>
</label>
@code {
//in a real case, the model is usually in a separate file
//the model type and value field type must be provided to the dropdpownlist
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 });
int selectedValue { get; set; } = 3; //usually the current value should come from the model data
}
Before, the Value from the first item in the Data was populated through @bind-Value to the view model. It no longer is.
In the following snippet, I expect to see "1" in the initial load of the page, but I see "0" - the default value for the integer.
@selectedValue
<TelerikDropDownList Data="@myDdlData" TextField="MyTextField" ValueField="MyValueField" @bind-Value="@selectedValue">
</TelerikDropDownList>
@code {
//in a real case, the model is usually in a separate file
//the model type and value field type must be provided to the dropdpownlist
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 });
int selectedValue { get; set; }
}
Hi!
When i use combination of LINQ inside TelerikDropDownLists Data attribute and TelerikGrid 's GridEditMode.Popup mode, i get weird behavior when i try to select an item from TelerikDropDownLists - everything freezes. Please check the solution. Everything works fine if i don't use LINQ or GridEditMode.Popup mode.
Thank you!
Hello,
Initial I want no item to be selected to let the user select a value. I thought it would be enough if my bindvalue would be of a nullable type. I'm getting an exception when trying. If this is not supported, how can I do it?
<div class="form-group col-md-2">
<label class="col-form-label" for="ddReleaseType">Fönstertyp</label>
<TelerikDropDownList Data="@ReleaseTypeFilterOptions" @bind-Value="FilterState.ReleaseType" TextField="DisplayText" ValueField="ReleaseType" Class="max-width form-control" @ref="ddReleaseType"></TelerikDropDownList>
</div>
public enum ReleaseType : int
{
All = 0,
Category = 1,
Season = 2,
Misc = 3
}
protected Telerik.Blazor.Components.TelerikDropDownList<ReleaseTypeFilterModel?, SessionState.ReleaseType?> ddReleaseType;
protected class ReleaseTypeFilterModel
{
public SessionState.ReleaseType ReleaseType { get; set; }
public string DisplayText { get { return ReleaseType.ToString(); } }
}
Telerik.Blazor.Components.Common.TelerikSelectBase<TItem, TValue>.TryParseValueFromString(string value, out TValue result, out string validationErrorMessage)
_Host.cshtml
As stated in the documentation the Event OnChange for DropDownList is shown by intellisense but should not be used. However, in some situations it would be very useful to bind the value of the DropDownList and additionally have an event when the value changes, e.g. show additional inputs when a value is selected.
Currently it is either possible to have data binding to value by @bind-Value or listen for the changed event by using Value and ValueChanged.
Is it possible to drop dropDownList from outside, for example after its data has been changed, without clicking on it ?
ADMIN EDIT:
This feature is also applicable to ComboBox, AutoComplete, Multiselect, Date and Time Pickers components.
Add the ability to make the drop down list expanded contents wider than the closed control, or just automatically determine appropriate width (doesn't always work well for very long text fields, so you need both properties).
Hi,
Is it possible to implement search/look-ahead in the current version of the DropDown component? If not, will you be adding this feature soon?
Thank you.
Ben
When bound to a nullable GUID, the DropDownList invokes validation and shows validation messages as soon as the view loads.
Expected: the same behavior as with nullable int - validation is to be triggered by the form submission or selection from the dropdown.
Worked as expected in 1.2.0.
Reproducible:
@
using
Telerik.Blazor.Components.DropDownList
@
using
System.ComponentModel.DataAnnotations
<EditForm Model=
"@person"
OnValidSubmit=
"@HandleValidSubmit"
>
<DataAnnotationsValidator />
<ValidationSummary />
<p
class
=
"gender"
>
Gender: <TelerikDropDownList @bind-Value=
"person.Gender"
DefaultItem=
"@ddlHint"
Data=
"@genders"
TextField=
"MyTextField"
ValueField=
"MyValueField"
>
</TelerikDropDownList>
<ValidationMessage For=
"@(() => person.Gender)"
></ValidationMessage>
</p>
<button type=
"submit"
>Submit</button>
</EditForm>
@code {
// Usually the model classes would be in different files
public
class
Person
{
[Required(ErrorMessage =
"Gender is mandatory."
)]
//the value field in the dropdown model must be null in the default item
public
Guid? Gender {
get
;
set
; }
}
public
class
MyDdlModel
{
//nullable so the default item can allow required field validation
public
Guid? MyValueField {
get
;
set
; }
public
string
MyTextField {
get
;
set
; }
}
Person person =
new
Person();
MyDdlModel ddlHint =
new
MyDdlModel { MyValueField =
null
, MyTextField =
"Gender"
};
IEnumerable<MyDdlModel> genders =
new
List<MyDdlModel>
{
new
MyDdlModel {MyTextField =
"female"
, MyValueField =
new
Guid()},
new
MyDdlModel {MyTextField =
"male"
, MyValueField =
new
Guid()},
new
MyDdlModel {MyTextField =
"other"
, MyValueField =
new
Guid()},
new
MyDdlModel {MyTextField =
"I'd rather not say"
, MyValueField =
new
Guid()}
};
void
HandleValidSubmit()
{
Console.WriteLine(
"OnValidSubmit"
);
}
}
This will allow the dropdown to be large enough to fit a reasonable number of items without a scrollbar. Alternatively, you could limit it through a pixel value you can set, or through the MaxPopupHeight property if it gets implemented: https://feedback.telerik.com/blazor/1412653-maxpopupheight.
Right now when a DropDownList has PopupHeight="Auto" the popup gets the height necesaary to display its items properly.
But when there are many items the popup also displays all items without a vertical scrollbar (maybe over the entire page and beyond), which is not good.
My suggestion would be to add a property for specifyig a "MaxPopupHeight" to limit the growth of the popup.
Also if "PopupHeight" is not specified it should take "Auto" as the default value instead of a static height in px, instead give the new "MaxPopupHeight" a limiting default value.
***Admin Edit***
Released in 3.0.0 through PopupSettings tag: https://docs.telerik.com/blazor-ui/upgrade/breaking-changes/3-0-0#popup-settings
***Admin Edit***
When the Value you bind to the DropDownList is null (for example, because it is a model that is not filled in by the user yet, and you need to perform validation), the component throws a null reference exception.
This does not happen for a nullable integer (example here)
Reproducible:
@
using
System.ComponentModel.DataAnnotations
@
using
Telerik.Blazor.Components.DropDownList
<EditForm Model=
"@PageData"
OnValidSubmit=
"@HandleValidSubmit"
>
<DataAnnotationsValidator />
<ValidationSummary />
@PageData.QuoteState
<TelerikDropDownList bind-Value=
"@PageData.QuoteState"
DefaultItem=
"@Hint"
Width=
"300px"
Data=
"@states"
TextField=
"stateName"
ValueField=
"stateID"
>
</TelerikDropDownList>
<ValidationMessage For=
"@(() => PageData.QuoteState)"
></ValidationMessage>
<button type=
"submit"
>Submit</button>
</EditForm>
@functions {
public
MyViewModel PageData {
get
;
set
; } =
new
MyViewModel();
public
statesModel Hint {
get
;
set
; } =
new
statesModel { stateID =
null
, stateName =
"Not Selected"
};
public
class
statesModel
{
public
string
stateID {
get
;
set
; }
public
string
stateName {
get
;
set
; }
}
public
class
MyViewModel
{
[Required(ErrorMessage =
"State is mandatory."
)]
//the value field in the dropdown model must be null in the default item
public
string
QuoteState {
get
;
set
; }
}
public
IEnumerable<statesModel> states =
new
List<statesModel>
{
new
statesModel { stateID =
"ACT"
, stateName =
"ACT"
},
new
statesModel { stateID =
"NSW"
, stateName =
"NSW"
},
new
statesModel { stateID =
"NT"
, stateName =
"NT"
},
new
statesModel { stateID =
"QLD"
, stateName =
"QLD"
},
new
statesModel { stateID =
"SA"
, stateName =
"SA"
},
new
statesModel { stateID =
"TAS"
, stateName =
"TAS"
},
new
statesModel { stateID =
"VIC"
, stateName =
"VIC"
},
new
statesModel { stateID =
"WA"
, stateName =
"WA"
}
};
void
HandleValidSubmit()
{
Console.WriteLine(
"OnValidSubmit"
);
}
}
Posting this feature request as per your suggestion in my original forum post at: https://www.telerik.com/forums/data-source-using-scalar-list
I would like the DropDownList component to support lists of scalar values as data source. I.e:
<TelerikDropDownList Data="@MyList" bind-Value=@MyItem>
</TelerikDropDownList>
@functions {
protected List<string> MyList = new List<string>() { "a", "b", "c" };
protected string MyItem { get; set; } = "b";
}
The DropDownList would infer the scalar type from the Data property. The TextField items shown in the list (and the associated ValueField) would be the same: i.e. the value of each scalar in the list.