Please support ColumnVirtualization in a Grid that also has multi-column headers (column bands) and locked columns, all three at once.
Follows ticket 1720022, where Ivan Danchev confirmed two defects in this combination (Telerik UI for Blazor 15.1.0, Blazor Server, ScrollMode Virtual, 45 columns of fixed px width in bands, the first band locked, Grid Width in px):
1. A band's header colspan is computed from its visible leaf columns and ignores the columns hidden by virtualization, so the header row goes out of step with the data rows and a band partly in view shows no title.
2. With any locked column the virtualizer merges every hidden column into one spacer cell. The spacer is a whole number of columns wide, so it cannot match an arbitrary scroll offset and leaves an empty strip, narrower than one column, between the locked block and the first scrolled column, in the header and every row. The spacer also carries the first hidden column's band into the header row.
Why it matters: on Blazor Server every rendered cell is a component held on the circuit. For our 45-column logbook grid the cells and loading placeholders are most of each user's memory (about 50 MB of render tree), and column virtualization would cut that by about two thirds. Wide data grids are usually grouped into bands with an identifying block locked on the left, so the combination is the normal case for a grid wide enough to need column virtualization.
Related: feedback items 1546425 and 1538964.
I have been trying to improve my Lighthouse score with Google and one of the items it is tagging is the "telerik-blazor.js" file. I have seen new practices where the JavaScript is imported as needed, see this article here from Microsoft.
Can you please consider this in the future?
===
Telerik edit: A possible workaround is to build the Telerik JavaScript file without some of the components that you don't need.
The PDF Viewer may render parts of the contents as blank (empty space) and only form elements like checkboxes remain visible.
Test PDF file in ticket 1716925
My users use Tab to focus the masked textbox and when they start typing (its content was highlighted because of getting focus with Tab), that typing action does not put the range (caret) in the correct place - it remains at position 0 rather than going to position 1.
For example, in the below phone mask they type "9" and then "0" and I would expect to get "90" but I get "0".
---
ADMIN EDIT
A workaround is to collapse the range when the input gets focus:
@inject IJSRuntime JsInterop
<input />
<span @onfocusin="@CollapseInputSelection" @ref="@ParentElem">
<TelerikMaskedTextBox Mask="+1 (000) 000-0000"
IncludeLiterals="true"
@bind-Value="@CellPhoneNumber"
Class="form-control" />
</span>
@* move this script to an actual script file instead of using this hack *@
<script suppress-error="BL9992">
function collapseInputSelection(root) {
setTimeout(function () {
var input = root.querySelector("input");
if (input) {
input.setSelectionRange(0, 0);
}
}, 20);
}
</script>
@code{
string CellPhoneNumber { get; set; }
ElementReference ParentElem { get; set; }
async Task CollapseInputSelection()
{
await JsInterop.InvokeVoidAsync("collapseInputSelection", ParentElem);
}
}---
I want the user to only be able to select times between, for example, 11AM and 1PM. Setting Min and Max does not limit that, I can select any time:
Selected time: @selectedTimeA RadioGroup inside a Grid EditorTemplate will fire OnBlur when the user clicks on it. This will close the edit cell and (usually) not apply the new value.
Here is a test page: https://blazorrepl.telerik.com/wvbmkMvd48rpMN4547
The code below compiles and doesn't give any browser errors when run, but when you collapse a row, all data is collapsed and you can't expand it again.
If you change the line that generates the data to use a List instead of IEnumerable it will work as expected.
REPRODUCIBLE
<TelerikTreeList Data=Data
IdField="@nameof(Record.Id)"
ParentIdField="@nameof(Record.ParentId)"
Height="100%">
<TreeListColumns>
<TreeListCheckboxColumn CheckBoxOnlySelection="true" />
<TreeListColumn Field="@nameof(Record.Text)" Title="" Expandable="true" />
<TreeListColumn Field="@nameof(Record.Id)" Title="ID" />
<TreeListColumn Field="@nameof(Record.ParentId)" Title="PARENT" />
</TreeListColumns>
</TelerikTreeList>
@code {
protected IEnumerable<Record> Data = new List<Record>();
protected override void OnInitialized()
{
Data = Enumerable.Range(1, 10).Select(i => new Record(i));
}
public class Record
{
public Record(int i)
{
Id = i;
if (i % 5 == 1)
ParentId = null;
else
ParentId = (i - ((i - 1) % 5));
Text = "Item " + i;
}
public long Id { get; set; }
public long? ParentId { get; set; }
public string Text { get; set; }
}
} WORKAROUND
<TelerikTreeList Data=Data
IdField="@nameof(Record.Id)"
ParentIdField="@nameof(Record.ParentId)"
Height="100%">
<TreeListColumns>
<TreeListCheckboxColumn CheckBoxOnlySelection="true" />
<TreeListColumn Field="@nameof(Record.Text)" Title="" Expandable="true" />
<TreeListColumn Field="@nameof(Record.Id)" Title="ID" />
<TreeListColumn Field="@nameof(Record.ParentId)" Title="PARENT" />
</TreeListColumns>
</TelerikTreeList>
@code {
protected List<Record> Data = new List<Record>();
protected override void OnInitialized()
{
Data = Enumerable.Range(1, 10).Select(i => new Record(i)).ToList();
}
public class Record
{
public Record(int i)
{
Id = i;
if (i % 5 == 1)
ParentId = null;
else
ParentId = (i - ((i - 1) % 5));
Text = "Item " + i;
}
public long Id { get; set; }
public long? ParentId { get; set; }
public string Text { get; set; }
}
}
The ContextMenu components triggers a page scroll up on first opening. The problem may be specific to WebAssembly apps. Here is a test page with an applied workaround:
https://blazorrepl.telerik.com/wglavwvy31XgaQIJ18
The important code in the above example is:
<TelerikContextMenu @ref="@ContextMenuRef" />
@code {
private TelerikContextMenu<ContextMenuItem> ContextMenuRef { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && ContextMenuRef is not null)
{
await Task.Delay(1);
await ContextMenuRef.ShowAsync(1, 1);
await ContextMenuRef.HideAsync();
}
}
}
I'm trying to use the Blazor editor but the "Insert Image" function is very basic. Previously using Webforms & Core the insert image in the editor presented the user with a file management and image upload popup. Is this functionality available with the Blazor component?
=====ADMIN EDIT=====
Possible alternative:
The NOW button in the TimePicker's TimeView sets the time value, according to the server's time zone. Instead, it should use the client-side (user) time zone.
===
Telerik edit:
In the meantime, you can subscribe to the TimePicker's ValueChanged event and detect when the user clicks on Now. In such cases, the event handler will receive the current server time with a small margin of error, that depends on the latency.
<TelerikTimePicker Value="@TimePickerValue"
ValueChanged="@( (DateTime? d) => TimePickerValueChanged(d) )">
</TelerikTimePicker>
@code {
private DateTime? TimePickerValue { get; set; }
private void TimePickerValueChanged(DateTime? newValue)
{
if (newValue.HasValue && newValue - DateTime.Now < new TimeSpan(0, 0, 1))
{
// Retrieve and set the correct user's local time. The dummy code below is just for testing.
TimePickerValue = DateTime.Now.AddMinutes(2);
}
else
{
TimePickerValue = newValue;
}
}
}
I would like to see icon support for the switch control. See the attached screen shot for the use case.
Try with culture es-ES and you will see the problem.
When es-ES, "dot [.]" is not a decimal separator, therefore you can't use the "NumpadDecimal" key to write a decimal number.
@using System.Globalization
<b>Culture:</b> @CultureInfo.CurrentCulture.Name;
<br />
<b>Culture UI:</b> @CultureInfo.CurrentUICulture.Name
<br />
<b>DefaultThreadCurrentCulture:</b> @CultureInfo.DefaultThreadCurrentCulture?.Name
<br />
<b>DefaultThreadCurrentUICulture:</b> @CultureInfo.DefaultThreadCurrentUICulture?.Name
<br /><br />
<b>Val 1:</b>
<TelerikNumericTextBox @bind-Value="@Val1" Decimals="6" Width="100px" />
<TelerikNumericTextBox @bind-Value="@Val1" Decimals="6" Width="100px" />
<input type="number" @bind-value="@Val1" step="any" style="width: 100px" />
<br />
<b>Val 2:</b>
<input type="number" @bind-value="@Val2" step="any" style="width: 100px" />
<input type="number" @bind-value="@Val2" step="any" style="width: 100px" />
@code {
decimal Val1 { get; set; }
decimal Val2 { get; set; }
protected override void OnInitialized()
{
CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("es-ES");
//CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
}
}
[ADMIN EDIT]
In general, our components obey the culture that is set in the application. If the current culture requires a "," decimal separator, our component will accept commas and ignore dots. Our component doesn't know if the user is pressing the decimal separator key on the numeric pad, or the "standard" [ > . ] key.
What we can do to improve the behavior is to implement a feature for automatic handling of the decimal separator character. In other words, if the component detects invalid decimal separator input, it will switch to the correct one. This feature will handle the Numpad key and output it in the right culture.
Here is a possible workaround that uses JavaScript to intercept the "other" decimal separator and insert the "correct" one in the NumericTextBox.
@inject IJSRuntime js
<span @onkeydown="@( (KeyboardEventArgs args) => OnSpanKeyDown(args, "ntb1") )">
<TelerikNumericTextBox @bind-Value="@DValue"
Width="200px"
Id="ntb1" />
</span>
Code: @LogCode , Key: @LogKey
<!-- Move JS to external JS file in production apps -->
<script suppress-error="BL9992">
function addDot(ntbId) {
var textbox = document.querySelector("#" + ntbId);
if (textbox && textbox.value.indexOf(".") == -1) { // or ","
textbox.value += "."; // or ","
}
}
</script>
@code {
decimal DValue { get; set; }
string LogCode { get; set; }
string LogKey { get; set; }
async Task OnSpanKeyDown(KeyboardEventArgs args, string ntbId)
{
LogCode = args.Code;
LogKey = args.Key;
if (args.Key == ",") // or "."
{
await js.InvokeVoidAsync("addDot", ntbId);
}
}
}Another option in the meantime is to use a standard HTML input or InputNumber with the Telerik CSS class "k-textbox". This way the input will look the same as a Telerik textbox and keep the app look consistent.