(bug report only)
Regression introduced in 13.0.0.
1. Run this example: https://blazorrepl.telerik.com/wUuSGClv00orFeRm59
(optional)
The Size, Rounded, FillMode parameters are ignored.
The parameter values should apply and change the appearance of the SearchBox.
Hi,
Using VS code I tried to create a project using the latest Telerik UI for Blazor Productivity tools. Updated 24-12-03
The Error:
I would like to be able to disable one or more radio buttons in the RadioGroup.
=====
TELERIK EDIT
In the meantime, consider the following workaround, which relies on CSS and RadioGroup ItemTemplate.
<h4>Default Value Disabled</h4>
RadioGroupValue1: @RadioGroupValue1
<TelerikRadioGroup Data="@Options"
@bind-Value="@RadioGroupValue1"
ValueField="@nameof(RadioModel.Id)"
TextField="@nameof(RadioModel.Text)">
<ItemTemplate>
@{
var dataItem = (RadioModel)context;
var isChecked = dataItem.Id == RadioGroupValue1;
}
@if (!dataItem.Enabled)
{
<span class="disabled-radio-option">
<span class="k-radio-wrap">
<input type="radio" value="@dataItem.Id" aria-checked="@isChecked" aria-disabled="true" aria-invalid="true"
class="@( $"fake k-radio k-radio-md {(isChecked ? "k-checked" : "")}" )" style="user-select: none;" />
</span>
<span>@dataItem.Text</span>
</span>
}
else
{
<span>@dataItem.Text</span>
}
</ItemTemplate>
</TelerikRadioGroup>
<h4>No Default Value</h4>
RadioGroupValue2: @RadioGroupValue2
<TelerikRadioGroup Data="@Options"
@bind-Value="@RadioGroupValue2"
ValueField="@nameof(RadioModel.Id)"
TextField="@nameof(RadioModel.Text)">
<ItemTemplate>
@{
var dataItem = (RadioModel)context;
var isChecked = dataItem.Id == RadioGroupValue2;
}
@if (!dataItem.Enabled)
{
<span class="disabled-radio-option">
<span class="k-radio-wrap">
<input type="radio" value="@dataItem.Id" aria-checked="@isChecked" aria-disabled="true" aria-invalid="true"
class="@( $"fake k-radio k-radio-md {(isChecked ? "k-checked" : "")}" )" style="user-select: none;" />
</span>
<span>@dataItem.Text</span>
</span>
}
else
{
<span>@dataItem.Text</span>
}
</ItemTemplate>
</TelerikRadioGroup>
<style>
.k-radio-list-item:has(.disabled-radio-option) {
pointer-events: none;
cursor: default;
opacity: 0.6;
gap: 0;
}
.disabled-radio-option {
display: flex;
align-items: center;
align-content: center;
gap: var(--kendo-spacing-1);
}
.k-radio-list-item:has(.disabled-radio-option) input:not(.fake) {
display: none;
}
</style>
@code{
private int RadioGroupValue1 { get; set; } = 2;
private int RadioGroupValue2 { get; set; }
private List<RadioModel> Options { get; set; } = new List<RadioModel>
{
new RadioModel { Id = 1, Text = "Option 1" },
new RadioModel { Id = 2, Text = "Option 2", Enabled = false },
new RadioModel { Id = 3, Text = "Option 3" },
new RadioModel { Id = 4, Text = "Option 4", Enabled = false },
new RadioModel { Id = 5, Text = "Option 5" },
};
public class RadioModel
{
public int Id { get; set; }
public string Text { get; set; } = string.Empty;
public bool Enabled { get; set; } = true;
}
}
With Blazor server, clicking the NOW button (obviously) sets the time to the time on the server since that's where the code is running. Is there a way to trap the NOW button click or somehow give it an offset or define the value that NOW means so NOW will mean the time that the user is sitting in?
---
TELERIK EDIT
In the meantime, here are a few possible workarounds:
1. Use the DateTimePicker's ValueChanged event to detect new values that are very close or match the server's current DateTime. In such cases, you can assume that the user has clicked on TODAY / NOW, and set the local user time as a component value.
Server Time on UI Refresh: @DateTime.Now.ToLongTimeString()
<br />
User Local Time on Page Load: @LocalTime?.ToLongTimeString()
<br />
User Local Time Offset: @LocalOffset
<br />
<br />
<TelerikDateTimePicker Value="@PickerValue"
ValueChanged="@( (DateTime? newValue) => PickerValueChanged(newValue) )"
ValueExpression="@( () => LocalTime )"
Format="yyyy-MMM-dd HH:mm:ss"
Width="240px" />
<!-- Move JS code to a separate JS file in production -->
<script suppress-error="BL9992">
function getLocalTime() {
var d = new Date();
return d.getTimezoneOffset();
}
</script>
@code {
private DateTime? PickerValue { get; set; }
private DateTime? LocalTime { get; set; }
private int LocalOffset { get; set; }
private void PickerValueChanged(DateTime? newValue)
{
DateTime serverNow = DateTime.Now;
DateTime utcNow = DateTime.UtcNow;
TimeSpan nowTolerance = new TimeSpan(0, 0, 10);
if (newValue - serverNow < nowTolerance)
{
PickerValue = utcNow.AddMinutes(-LocalOffset);
}
else
{
PickerValue = newValue;
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
LocalOffset = await js.InvokeAsync<int>("getLocalTime");
LocalTime = DateTime.UtcNow.AddMinutes(-LocalOffset);
StateHasChanged();
}
await base.OnAfterRenderAsync(firstRender);
}
}
2. Use the DatePicker's HeaderTemplate with a custom TODAY / NOW button.
3. Hide the NOW button with CSS:
<style>
.no-now-button .k-time-now {
display: none;
}
</style>
<TelerikDateTimePicker @bind-Value="@PickerValue"
Format="yyyy-MMM-dd HH:mm:ss"
PopupClass="no-now-button"
Width="240px" />
@code {
private DateTime? PickerValue { get; set; }
}
I would like to see icon support for the switch control. See the attached screen shot for the use case.
The NumericTextBox does not render the new Value that is set in ValueChanged if this new value is different than the event argument. Instead, the component clears the textbox, even though the component Value parameter is correct.
https://blazorrepl.telerik.com/wzaAHYas221go9xd48
The problem occurs only if there is an existing value and the user removes it with Backspace.
Could you include the OnHide event in the TelerikPopover, similar to the Popup component? The Popover already hides on outside clicks, but we have no method to programatically react to it, for example to reset input values and treat it as a cancellation.
===
TELERIK EDIT: In the meantime, a possible workaround is to detect clicks outside the Popover with JavaScript:
https://blazorrepl.telerik.com/QKOBbSbF25rgdsgP20
@implements IAsyncDisposable
@inject IJSRuntime JS
<TelerikPopover @ref="@PopoverRef"
AnchorSelector=".popover-target"
ShowOn="@PopoverShowOn.Click"
Position="@PopoverPosition.Right"
Offset="20"
Class="my-popover">
<PopoverContent>
Telerik Popover for Blazor
</PopoverContent>
</TelerikPopover>
<p>Popover Hide Log: @PopoverOnHideLog</p>
<TelerikButton Class="popover-target" OnClick="ShowPopover">
Show Popover
</TelerikButton>
<script suppress-error="BL9992">
var dotnetRef;
window.registerOutsideClick = function (dotnetHelper) {
dotnetRef = dotnetHelper;
document.addEventListener("click", onPopoverOutsideClick);
};
window.unregisterOutsideClick = function () {
dotnetRef = null;
document.removeEventListener("click", onPopoverOutsideClick);
};
function onPopoverOutsideClick(e) {
window.setTimeout(() => {
const popover = document.querySelector(".my-popover");
const anchor = document.querySelector(".popover-target");
const clickedInsidePopover = popover?.contains(e.target);
const clickedAnchor = anchor?.contains(e.target);
if (!clickedInsidePopover && !clickedAnchor) {
dotnetRef?.invokeMethodAsync("OnPopoverHide");
}
}, 100);
}
</script>
@code {
#nullable enable
private DotNetObjectReference<__Main>? DotNetRef { get; set; }
private TelerikPopover? PopoverRef;
private string PopoverOnHideLog { get; set; } = string.Empty;
private void ShowPopover()
{
PopoverRef?.Show();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("registerOutsideClick", DotNetRef);
}
}
protected override void OnInitialized()
{
DotNetRef = DotNetObjectReference.Create(this);
}
[JSInvokable]
public void OnPopoverHide()
{
PopoverOnHideLog = $"Popover closed automatically at {DateTime.Now.ToString("HH:mm:ss")}";
StateHasChanged();
}
public async ValueTask DisposeAsync()
{
if (DotNetRef != null)
{
DotNetRef.Dispose();
}
await JS.InvokeVoidAsync("unregisterOutsideClick");
}
}
The AutoComplete component does not update the category grouping header, even when the data within that group has been removed. As a result, the outdated group header remains visible until you scroll down to another group, at which point the first group header refreshes and disappears as expected.
Repro: REPL link.
The Grid performance worsens progressively with each subsequent edit operation. Please optimize that.
Test page: https://blazorrepl.telerik.com/mJuHFNbb17FpJu9b54
Click on a Price or Quantity cell to start edit mode and tab repetitively to observe the degradation.
The disable option is still showing the step and it is not good for me. I have 35 types of transactions and all of them have generic and specific step.
---
ADMIN EDIT
Here is a potential workaround - basic conditional markup can add or remove steps. The key thing is that they will be added to the end of the wizard if they had not been rendered. To handle this, dispose and re-initialize the component, so the step will be rendered at the correct position.
If you have complex steps, you can work around this by creating a collection of descriptor models for the list of steps and create the steps based on that collection, where you can keep the VIsible flag, in a fashion similar to this example for the TabStrip.
<TelerikButton OnClick="@ToggleStep">Toggle attachments step visibility</TelerikButton>
@if (WizardVisible)
{
<TelerikWizard @bind-Value="@CurrStepIndex">
<WizardSteps>
<WizardStep Label="Personal Details" Icon="SvgIcon.User">
<Content>
content here
</Content>
</WizardStep>
@if (AttachmentsStepVisible)
{
<WizardStep Label="Attachments" Icon="SvgIcon.Paperclip">
<Content>
conditional content here
</Content>
</WizardStep>
}
<WizardStep Label="Confirmation" Icon="SvgIcon.Check">
<Content>
other content here
</Content>
</WizardStep>
</WizardSteps>
</TelerikWizard>
}
@code {
private bool AttachmentsStepVisible { get; set; }
private bool WizardVisible { get; set; } = true;
private int CurrStepIndex { get; set; }
private async void ToggleStep()
{
//dispose the Wizard
WizardVisible = false;
// defence against hiding the step when it is the last step, which would cause an exception
if (AttachmentsStepVisible && CurrStepIndex == 2)
{
CurrStepIndex = 1;
}
//the actual visibility toggle
AttachmentsStepVisible = !AttachmentsStepVisible;
//allow some time for the disposal and toggling the step visibility prior to re-initialization
await Task.Delay(10);
//re-initialize the Wizard
WizardVisible = true;
StateHasChanged();
}
}---
The CheckBoxList filter does not work as expected when the Grid is bound to ExpandoObject
===
ADMIN EDIT: A possible workaround is to bind the Grid with OnRead event and populate the MemberType property of the filter descriptors manually:
@using System.Dynamic
@using Telerik.DataSource
@using Telerik.DataSource.Extensions
<TelerikGrid OnRead="@OnGridRead"
TItem="@ExpandoObject"
Pageable="true"
Sortable="true"
FilterMode="@GridFilterMode.FilterMenu"
FilterMenuType="@FilterMenuType.CheckBoxList"
Height="400px">
<GridToolBarTemplate>
<GridSearchBox />
</GridToolBarTemplate>
<GridColumns>
@{
if (GridData != null && GridData.Any())
{
<GridColumn Field="PropertyInt" FieldType="@GridPropertyTypes["PropertyInt"]" />
<GridColumn Field="PropertyString" FieldType="@GridPropertyTypes["PropertyString"]" />
<GridColumn Field="PropertyGroup" FieldType="@GridPropertyTypes["PropertyString"]" />
<GridColumn Field="PropertyDate" FieldType="@GridPropertyTypes["PropertyDate"]" />
<GridColumn Field="PropertyBool" FieldType="@GridPropertyTypes["PropertyBool"]" />
}
}
</GridColumns>
</TelerikGrid>
@code {
private List<ExpandoObject> GridData { get; set; } = new List<ExpandoObject>();
private Dictionary<string, Type> GridPropertyTypes { get; set; } = new Dictionary<string, Type>() {
{ "Id", typeof(int) },
{ "PropertyInt", typeof(int) },
{ "PropertyString", typeof(string) },
{ "PropertyGroup", typeof(string) },
{ "PropertyDate", typeof(DateTime) },
{ "PropertyBool", typeof(bool) }
};
private async Task OnGridRead(GridReadEventArgs args)
{
args.Request.Filters.OfType<CompositeFilterDescriptor>()
.Each(x =>
{
x.FilterDescriptors.OfType<FilterDescriptor>()
.Each(y => y.MemberType = GridPropertyTypes[y.Member]);
});
var result = GridData.ToDataSourceResult(args.Request);
args.Data = result.Data;
args.Total = result.Total;
args.AggregateResults = result.AggregateResults;
}
protected override void OnInitialized()
{
for (int i = 1; i <= 18; i++)
{
dynamic expando = new ExpandoObject();
expando.Id = i;
expando.PropertyGroup = $"Group {(i % 3 + 1)}";
expando.PropertyInt = i;
expando.PropertyString = $"String {(char)(64 + i)}{(char)(64 + i)}";
expando.PropertyDate = DateTime.Now.AddMonths(-i);
expando.PropertyBool = i % 2 != 0;
GridData.Add(expando);
}
}
}
The problem with the extra characters at the beginning of the PDF document has resurfaced.
The bytes returned by GetFileAsync() don't start with %PDF-, but with JS.ReceiveByteArray. Some PDF readers and my antivirus flag the file as corrupt or suspicious. I worked around it by stripping everything before the first %PDF- occurrence in the bytes before writing to disk.
Telerik input components inside EditorTemplate render the whole grid on each keystroke
<AdminEdit>
As a workaround, you can use the standard Input components provided by the framework together with a CSS class that would visually make them like the Telerik Input Components. An example for the TextArea:
<InputTextArea class="k-textarea" @bind-Value="@myValue"></InputTextArea></AdminEdit>
At the moment start and end times effectively "round" to the nearest half an hour. This can give the impression of events overlapping when they do not
e.g.

Admin edit: This feature would be similar to the Exact Time Rendering in our WebForms suite: https://demos.telerik.com/aspnet-ajax/scheduler/examples/exacttimerendering/defaultcs.aspx
Workaround:
<TelerikGrid Data="@GridData"
SelectionMode="@GridSelectionMode.Multiple"
SelectedItems="@SelectedItems"
SelectedItemsChanged="@( (IEnumerable<Employee> newSelected) => OnSelectedItemsChanged(newSelected) )"
Height="300px">
<GridToolBarTemplate>
<TelerikButton Enabled="@(SelectedItems.Any())" OnClick="@DeleteSelectedEmployees">Delete</TelerikButton>
</GridToolBarTemplate>
<GridColumns>
<GridCheckboxColumn SelectAll="true" />
<GridColumn Field="Name" Title="Name" />
<GridColumn Field="Team" Title="Team" />
</GridColumns>
</TelerikGrid>
@code {
private List<Employee> GridData { get; set; } = Enumerable.Range(1, 10).Select(i => new Employee
{
EmployeeId = i,
Name = $"Employee {i}",
Team = $"Team {i % 3}"
}).ToList();
private List<Employee> SelectedItems { get; set; } = new();
private void OnSelectedItemsChanged(IEnumerable<Employee> items)
{
SelectedItems = items.ToList();
}
private void DeleteSelectedEmployees()
{
if (SelectedItems.Any())
{
GridData = GridData.Except(SelectedItems).ToList();
SelectedItems.Clear();
}
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
public override bool Equals(object obj) => obj is Employee e && e.EmployeeId == EmployeeId;
public override int GetHashCode() => EmployeeId.GetHashCode();
}
}
I want a less-persistent popup, where a click outside of its boundaries would close it. To give a real world example, the Share Snippet feature in REPL works in such a way.
===
Telerik edit: A workaround for the time being is to attach a JavaScript click handler that closes the Popup instance: https://blazorrepl.telerik.com/GyumGrEs22yZgoCD16