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.
(bug report only)
The clear button in the ComboBox (MultiColumnComboBox, etc.) currently renders as a span element and has the following attributes:
<span class="k-clear-value" role="button" tabindex="-1" title="Clear"> ... </span>
Excluding a button from the Tab key sequence does not hide it from a screen reader user. A screen reader user navigating by virtual cursor (using arrow keys or "next button" shortcuts) can and will still find this span element. When they arrive at it, they will hear "Clear, button." Naturally, they will press Enter or Space to activate it.
Current behavior
(optional)
Provide additional information if the steps for reproducing the faulty behavior are not sufficient to describe the issue.
Make the span WCAG 4.1.2 compliant: https://www.w3.org/WAI/standards-guidelines/act/rules/97a4e1/
<span class="k-clear-value" role="button" tabindex="-1" aria-label="Clear selection" title="Clear"> ... </span>
We can also consider completely hiding the span from screen readers, by rendering aria-hidden="true" on the span element, for example:
<span class="k-clear-value" role="button" tabindex="-1" aria-hidden="true"> </span>
The Kendo Angular ComboBox implements a similar approach. This will be in accordance with WCAG 4.1.2, because aria-hidden="true" removes the element from the accessibility tree entirely, it is no longer parsed as an active UI component by screen readers.
(optional)
Provide the TicketID, where the bug report initiated.
In version 15.1.0, the Editor causes a browser freeze when it contains a custom tool and the Value is changed programmatically. It works as expected in version 15.0.1.
The issue occurs only in WebAssembly apps.
Test page:
@using Telerik.Blazor.Components.Editor
<TelerikButton OnClick="@(() => EditorValue = "<p>baz</p><p>baz</p>")" ButtonType="@ButtonType.Button">Change Editor Value</TelerikButton>
<TelerikEditor Tools="@EditorTools"
@bind-Value="@EditorValue">
<EditorCustomTools>
<EditorCustomTool Name="CustomEditorTool">
custom tool here
</EditorCustomTool>
</EditorCustomTools>
</TelerikEditor>
@code {
private string EditorValue { get; set; } = @"<p>foo</p><p>bar</p>";
private List<IEditorTool> EditorTools { get; set; } = new();
protected override void OnInitialized()
{
EditorTools.Add(new CustomTool("CustomEditorTool"));
base.OnInitialized();
}
}
Hello,
When a Grid is using multi column headers, and I add one more column in the OnBeforeExport event, this new column has no title in the exported file.
A possible workaround might be to use a column with zero Width and change the width in OnBeforeExport.
@using Telerik.Blazor.Common.Export.Excel
@using Telerik.Blazor.Components.Grid
<TelerikGrid TItem="@FlowRun"
Pageable="true"
OnRead="@GetData">
<GridToolBar>
<GridCommandButton Command="ExcelExport" Icon="file-excel">Export to Excel</GridCommandButton>
<GridCommandButton Command="CsvExport" Icon="file-csv">Export to CSV</GridCommandButton>
<label class="k-checkbox-label"><TelerikCheckBox @bind-Value="@ExportAllPages" />Export All Pages</label>
</GridToolBar>
<GridExport>
<GridExcelExport FileName="telerik-grid-export" AllPages="@ExportAllPages" OnBeforeExport="@BeforeExcelExport" />
<GridCsvExport FileName="telerik-grid-export" AllPages="@ExportAllPages" OnBeforeExport="@BeforeCsvExport" />
</GridExport>
<GridColumns>
<GridColumn Field="@nameof(FlowRun.FileName)" Title="File Name" Width="300px" />
<GridColumn Field="@nameof(FlowRun.Type)" Title="Type" Width="100px" />
<GridColumn Field="@nameof(FlowRun.FileSize)" Title="File Size" Width="200px" />
<GridColumn Title="Source">
<Columns>
<GridColumn Field="@(nameof(FlowRun.Source))" Title="MPID"/>
<GridColumn Field="@(nameof(FlowRun.SourceFileProtocol))" Title="Type" />
</Columns>
</GridColumn>
<GridColumn Field="@nameof(FlowRun.ErrorMessage)"
Title = "Error"
Width="0" />
</GridColumns>
</TelerikGrid>
@code {
bool ExportAllPages { get; set; }
private async Task GetData(GridReadEventArgs args)
{
args.Data = Enumerable.Range(1, 10).Select(x => new FlowRun
{
FileName = $"File {x}",
Type = $"Type {x}",
FileSize = x * 2,
Source = $"Source {x}",
SourceFileProtocol = FileProtocol.CIX,
ErrorMessage = $"Error {x}"
}).ToList();
args.Total = 100;
}
private void BeforeCsvExport(GridBeforeCsvExportEventArgs obj)
{
AddErrorMessageColumn(obj);
}
private void BeforeExcelExport(GridBeforeExcelExportEventArgs obj)
{
AddErrorMessageColumn(obj);
}
private void AddErrorMessageColumn(GridBeforeSpreadsheetExportEventArgs args)
{
args.Columns.Find(x => x.Field == nameof(FlowRun.ErrorMessage)).Width = "100px";
//args.Columns.Add(new ExcelExportableColumn
//{
// Field = nameof(FlowRun.ErrorMessage),
// Title = "Error"
//});
}
public class FlowRun
{
public string FileName { get; set; }
public string Type { get; set; }
public long? FileSize { get; set; }
public string Source { get; set; }
public FileProtocol SourceFileProtocol { get; set; }
public string ErrorMessage { get; set; }
}
public enum FileProtocol
{
Unknown,
PIX,
CIX,
SS
}
}
Example:
<PageTitle>Home</PageTitle>
<div>
<TelerikTextBox Width="20rem" Placeholder="Pallet" DebounceDelay="1000" @bind-Value="@_textInput" OnChange="@(async (input) => await OnInputChanged(input))" />
</div>
<p>@_textInput</p>
@code {
private string? _textInput;
private async Task OnInputChanged(object input)
{
Console.WriteLine($"Immediate: function parameter: {input}, bound variable: {_textInput}");
await Task.Delay(1000);
Console.WriteLine($"Delayed: function parameter: {input}, bound variable: {_textInput}");
//Make the OnChange event receive the immediate value when the DebounceDelay is set
}
}The DebounceDelay is set to 1 second to highlight the behavior, although we have observed it with delays less than 100 milliseconds when the input is from a barcode scanner and the Enter is part of the scan. Start the sample, type "123" in the input, and hit enter within 1 second.
The output in the console is:
Immediate: function parameter: , bound variable:
Delayed: function parameter: , bound variable: 123
Hello,
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; }
}
The ability to choose which options to appear in the ContextMenu.
=====
TELERIK EDIT: In the meantime, here is how to hide context menu items with CSS:
/* Hide the Rename item in the FileManager context menu */
.k-context-menu:has(.k-svg-i-download) .k-menu-item:nth-of-type(1) {
display: none;
}
/* Hide the Delete item in the FileManager context menu */
.k-context-menu:has(.k-svg-i-download) .k-menu-item:nth-of-type(3) {
display: none;
}Here is a complete example: https://blazorrepl.telerik.com/cpPkuBEq408A36p010
(Also applies to AutoComplete, DropDownList, MultiSelect, MultiColumnComboBox).
When using Height="auto" in the popup settings and filtering with a dropdown above the component, the dropdown detaches from the main component.
<ComboBoxPopupSettings Height="auto"></ComboBoxPopupSettings>https://blazorrepl.telerik.com/cKkSQGFO50ovCpr829
A possible workaround is to use a MaxHeight that is less than half the browser viewport.
<ComboBoxPopupSettings Height="auto" MaxHeight="45vh"></ComboBoxPopupSettings>
Support multiple users editing the same content in an editor.
This would be similar to the editor in something like confluence or online Word.
Regards
The only scenario that works is to set the initial Zoom to a numeric value and have an open file by default.
I would like a Blazor PropertyGrid with
-- that could be bound to an instance of a custom Type that implemented INotifyPropertyChanged
-- with expandable/collapsible sections with the ability to prevent a user from expanding a collapsed section (e.g. the user lacks privileges to see that section's data)
-- would keep track of its UI state including collapsed sections (similar to the excellent implementation in Telerik's Blazor Grid)
-- that would allow the use of all Telerik Blazor editors as cell-value editors
I am interested in using this component primarily as a data-entry UX in a data-entry-intensive line-of-business application. Such a grid offers standard navigation on all data-entry screens in the application, eliminating tab-order, thereby greatly simplifying the end-user experience. The expanding/collapsing sections make it very economical in its use of screen real-estate. I have used such a component (from a competitor of Telerik) in a WinForms application with excellent results.
(bug report only)
The label of the filter menu icon displays: “column filter menu settings”. In version 12.0.0 it included the name of the column field.
1. Run this example: https://blazorrepl.telerik.com/cKFaOPvO56rcaHqx16
2. Hover a filter icon in the Grid’s header with the mouse cursor.
(optional)
The label “column filter menu settings” appears.
The label text includes the column name, e.g., “Price column filter menu settings”.
Workaround:
https://blazorrepl.telerik.com/cUPYaPlO55EJNiKJ24