This REPL test page is based on the TreeView Filtering demo, but with added checkboxes.
A possible workaround is to also filter (or clear) the collection that is bound to the CheckedItems parameter of the TreeView.
The "Bold" button in the code snippet below remains visible despite the fact that it's Visible property is false
<TelerikToolBar>
In the TelerikDatePicker, when I select the date and click outside, the event triggers one time only, but when I do the same inside the TelerikDateTimePicker it triggers two times (the first when I set the time and the second when I click outside).
In the end of the ticket I will provide a simple demo code used in Telerik REPL for Blazor comparing the behaviour between the two elements.
Additionally I would like to report the fact that in the TelerikDateTimePicker, when there's no value and I open the calendar and click "Set" without doing anything else, the DateTime is set to "01/01/0001 00:00" instead of null.
The problematic behavior appears in this specific scenario:
In this case, the custom typed value is lost and the component value is the first item in the list matching the input. Thus, the user cannot set their desired custom value.
Reproduction with steps listed inside: https://blazorrepl.telerik.com/GokVlXEW12KGZ36F15.
===
ADMIN EDIT
===
A possible option for the time being:
Here is a basic sample: https://blazorrepl.telerik.com/wourlNOC51FRcNAX54.
The Grid automatically scrolls to top when adding a new item in inline or incell edit mode. However, when the Grid has locked (frozen) columns, this scrolling doesn't occur.
Here is a test page with a JavaScript workaround in the OnAdd event:
@using System.ComponentModel.DataAnnotations
@inject IJSRuntime js
<label><TelerikCheckBox @bind-Value="@EnableScrollWorkaround" /> Enable Workaround</label>
<TelerikGrid Data="@GridData"
EditMode="@GridEditMode.Inline"
OnAdd="@OnGridAdd"
OnUpdate="@OnGridUpdate"
OnCreate="@OnGridCreate"
Width="700px"
Height="400px"
Class="grid-class">
<GridToolBarTemplate>
<GridCommandButton Command="Add">Add Item</GridCommandButton>
</GridToolBarTemplate>
<GridColumns>
<GridColumn Field="@nameof(Product.Name)" Width="200px" Locked="true" />
<GridColumn Field="@nameof(Product.Price)" Width="200px" />
<GridColumn Field="@nameof(Product.Quantity)" Width="200px" />
<GridCommandColumn Width="200px" Locked="true">
<GridCommandButton Command="Edit">Edit</GridCommandButton>
<GridCommandButton Command="Save" ShowInEdit="true">Save</GridCommandButton>
<GridCommandButton Command="Cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
<script suppress-error="BL9992">
function scrollGridToTop() {
var gridContentArea = document.querySelector(".grid-class .k-grid-content");
if (gridContentArea) {
gridContentArea.scrollTop = 0;
}
}
</script>
@code {
private bool EnableScrollWorkaround { get; set; } = true;
private List<Product> GridData { get; set; } = new();
private int LastId { get; set; }
private async Task OnGridAdd(GridCommandEventArgs args)
{
if (EnableScrollWorkaround)
{
await js.InvokeVoidAsync("scrollGridToTop");
}
}
private void OnGridUpdate(GridCommandEventArgs args)
{
var updatedItem = (Product)args.Item;
var originalItemIndex = GridData.FindIndex(i => i.Id == updatedItem.Id);
if (originalItemIndex != -1)
{
GridData[originalItemIndex] = updatedItem;
}
}
private void OnGridCreate(GridCommandEventArgs args)
{
var createdItem = (Product)args.Item;
createdItem.Id = ++LastId;
GridData.Insert(0, createdItem);
}
protected override void OnInitialized()
{
for (int i = 1; i <= 30; i++)
{
GridData.Add(new Product()
{
Id = ++LastId,
Name = $"Product {LastId}",
Quantity = (short)Random.Shared.Next(0, 1000),
StartDate = DateTime.Now.AddDays(-Random.Shared.Next(60, 1000)),
IsActive = LastId % 4 > 0
});
}
}
public class Product
{
public int Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public int Quantity { get; set; }
public DateTime StartDate { get; set; }
public bool IsActive { get; set; }
}
}
Hi,
starting with version 6.0, dialogs used together with loading indicator are at wrong z-index order.
- None of hotfixes with "delay" helped.
- users are stucked and cant confirm anything
How to replicate
Click on "Show Confirm with loading indicator". Loading animation should be at BACK of confirm dialog(as at older versions, prior 6.0)
https://blazorrepl.telerik.com/GeOfQMkt56AMkdof43
The issue can be reproduced when clicking on a button that opens a predefined Dialog, then making some changes on the page and hot reloading. In this scenario, I get the following error:
Microsoft.JSInterop.JSException: Cannot read properties of null (reading 'addEventListener') TypeError: Cannot read properties of null (reading 'addEventListener')
In a navigable Grid with incell edit, if a column has Editable=false the tabbing behavior is as follows: while the user is editing the previous editable cell pressing tab results in skipping the non-editable cell and moving the focus to the next editable cell to open it for edit.
However, the behavior is different when cancelling the editing through the OnEdit event. In this case, while the user is editing the previous editable cell pressing tab results in exiting the edit and keeping the focus to the cell. Subsequent tab press moves to focus to the pager.
Reproduction: https://blazorrepl.telerik.com/mykLFEFJ14mlqei429.
===
ADMIN EDIT
===
A possible option for the time being is to cancel the edit as shown in the example above but also force the Grid to enter edit of the next editable cell. You can do that through the State: Enter and Exit Grid Edit Mode Programmatically.
Here is a basic example, you may adjust it as needed to fit your exact requirements: https://blazorrepl.telerik.com/mSuLPAFP05HRs7B555.
With
<TelerikNumericTextBox @bind-Value="myValue" Format="C" SelectOnFocus="true">
the content of the input is not selected upon focussing. Without the Format="C" it is.
Cases:
<Admin>
<script suppress-error="BL9992">
window.navigateToHref = (ev) => {
if (ev.key === "Enter") {
location.href = ev.target.href
}
};
</script>
@* This example shows how to create header and footer for the Drawer and select an item manually. *@
<TelerikDrawer @bind-Expanded="@DrawerExpanded"
Data="@Data"
MiniMode="true"
Mode="@DrawerMode.Push"
@bind-SelectedItem="@SelectedItem"
@ref="@DrawerRef">
<Template>
@* the header *@
<div>
<TelerikButton OnClick="@(() => DrawerRef.ToggleAsync())" Icon="@FontIcon.Menu" />
@if (DrawerExpanded)
{
<div class="text-info" style="border-bottom:solid; font-weight: bold; margin-bottom: 3em; white-space:nowrap">
<a href="https://google.com" onkeydown="navigateToHref(event)">
My Custom Navigation to Google
</a>
</div>
}
else
{
<div class="text-info" style="border-bottom:solid; font-weight: bold;">
Nav
</div>
}
</div>
@* custom items rendering and item selection *@
<div class="k-drawer-items">
<ul>
@if (SelectedItem != null && DrawerExpanded)
{
<li class="k-drawer-item" style="white-space:nowrap">
<div>
<p><strong>@SelectedItem.Text</strong></p>
<p>@SelectedItem.Description</p>
</div>
</li>
}
@foreach (var item in Data)
{
@* Use onclick to handle manual item selection *@
<li @onclick="@(() => SelectedItem = item)"
class="k-drawer-item @GetSelectedItemClass(item)" style="white-space:nowrap">
<TelerikFontIcon Icon="@item.Icon"></TelerikFontIcon>
@if (DrawerExpanded)
{
<div>
<div>@item.Text</div>
</div>
}
</li>
}
</ul>
</div>
@* the footer *@
@if (DrawerExpanded)
{
<div style="text-align: center; margin-top: 3em; padding-top: 2em; border-top: 2px solid black; white-space:nowrap">
<img src="user-avatar.png" alt="my avatar" style="border-radius: 50%; width: 50px; height: 50px;" />
<br /><br />
<TelerikButton Icon="@FontIcon.Logout" ThemeColor="primary">Log Out</TelerikButton>
</div>
}
</Template>
<DrawerContent>
<div class="m-5">Content for @SelectedItem?.Text - @SelectedItem?.Description</div>
</DrawerContent>
</TelerikDrawer>
@code {
public TelerikDrawer<DrawerItem> DrawerRef { get; set; }
public DrawerItem SelectedItem { get; set; }
public bool DrawerExpanded { get; set; } = true;
public IEnumerable<DrawerItem> Data { get; set; } = new List<DrawerItem>
{
new DrawerItem {Text = "Shopping Cart", Icon = FontIcon.Cart, Description = "Items in shopping cart"},
new DrawerItem {Text = "Settings", Icon = FontIcon.Gear, Description = "My profile settings"},
new DrawerItem {Text = "Notifications", Icon = FontIcon.ExclamationCircle, Description = "My profile notifications"},
new DrawerItem {Text = "Calendar", Icon = FontIcon.Calendar, Description = "My events"},
};
public string GetSelectedItemClass(DrawerItem item)
{
if (SelectedItem == null) return string.Empty;
return SelectedItem.Text.ToLowerInvariant().Equals(item.Text.ToLowerInvariant()) ? "text-info" : "";
}
public class DrawerItem
{
public string Text { get; set; }
public FontIcon? Icon { get; set; }
public string Description { get; set; }
}
}
</Admin>
When the user renames a folder, the TreeView foes not refresh to display the new folder name.
The test page below is based on the FileManager Events example.
A possible workaround is to recreate the FileManager in the OnUpdate handler:
@using System.IO
@if (ShouldRenderFileManager)
{
<TelerikFileManager @ref="@FileManagerRef"
Data="@Files"
@bind-Path="@DirectoryPath"
View="@CurrentView"
ViewChanged="@OnViewChanged"
Height="400px"
OnCreate="@OnCreateHandler"
OnUpdate="@OnUpdateHandler"
OnDelete="@OnDeleteHandler"
OnModelInit="@OnModelInitHandler"
OnDownload="@OnDownloadHandler"
SelectedItems="@SelectedItems"
SelectedItemsChanged="@((IEnumerable<FlatFileEntry> selectedFiles) => OnSelect(selectedFiles))">
</TelerikFileManager>
}
@foreach (var item in Files)
{
<div>@item.Name</div>
}
@code {
private bool ShouldRenderFileManager { get; set; } = true;
private TelerikFileManager<FlatFileEntry>? FileManagerRef { get; set; }
private List<FlatFileEntry> Files { get; set; } = new();
private string DirectoryPath { get; set; } = string.Empty;
private IEnumerable<FlatFileEntry> SelectedItems { get; set; } = new List<FlatFileEntry>();
private FileManagerViewType CurrentView { get; set; }
private void OnViewChanged(FileManagerViewType newView)
{
CurrentView = newView;
}
private async Task OnCreateHandler(FileManagerCreateEventArgs args)
{
var newFolder = args.Item as FlatFileEntry;
var parent = GetParent(newFolder, DirectoryPath);
newFolder.Id = "20";
newFolder.ParentId = parent.Id;
newFolder.Name = "New folder";
newFolder.IsDirectory = true;
newFolder.HasDirectories = false;
newFolder.DateCreated = DateTime.Now;
newFolder.DateCreatedUtc = DateTime.Now;
newFolder.DateModified = DateTime.Now;
newFolder.DateModifiedUtc = DateTime.Now;
newFolder.Path = Path.Combine(DirectoryPath, newFolder.Name);
newFolder.Extension = null;
var parentDirectory = GetDirectory(DirectoryPath) ?? GetParent(newFolder, DirectoryPath);
if (parentDirectory != null)
{
// Simulate add to the file system.
newFolder.ParentId = parentDirectory.Id;
Files.Add(newFolder);
parentDirectory.HasDirectories = Files.Count(x => x.ParentId == parentDirectory.Id) > 0;
}
else
{
// Create a folder in the root directory.
Files.Add(newFolder);
}
RefreshData();
}
private FlatFileEntry GetDirectory(string path)
{
var directory = Files.FirstOrDefault(x => x.IsDirectory && x.Path == path);
return directory;
}
private FlatFileEntry GetParent(FlatFileEntry currItem, string currDirectory)
{
var parentItem = Files
.FirstOrDefault(x => x.IsDirectory && x.Path == currDirectory);
return parentItem;
}
private async Task OnUpdateHandler(FileManagerUpdateEventArgs args)
{
var item = args.Item as FlatFileEntry;
if (item.IsDirectory)
{
var name = item.Name ?? string.Empty;
var updatedItem = Files.FirstOrDefault(x => x.Id == item.Id);
updatedItem.Name = item.Name;
updatedItem.Path = Path.Combine(DirectoryPath, name);
ShouldRenderFileManager = false;
await Task.Delay(1);
ShouldRenderFileManager = true;
}
else
{
// The name property is updated, but also update the path to the file.
var name = item.Name ?? string.Empty;
var extension = item.Extension ?? string.Empty;
var fullName = extension.Length > 0 && name.EndsWith(extension) ?
name : $"{name}{extension}";
var updatedItem = Files.FirstOrDefault(x => x.Id == item.Id);
updatedItem.Name = item.Name;
updatedItem.Path = Path.Combine(DirectoryPath, fullName);
Console.WriteLine(updatedItem.Path);
}
}
private async Task OnDownloadHandler(FileManagerDownloadEventArgs args)
{
var selectedItem = args.Item as FlatFileEntry;
// The Filemanager does not have the actual file.
// Obtain the file contents, based on args.Item, and set the event arguments:
//args.Stream = the file stream of the actual selected file;
//args.MimeType = the MIME type of the actual file;
//args.FileName = the file name that the browser will receive (optional);
FlatFileEntry actualFile = (FlatFileEntry)args.Item;
string dummyFileContent = $"This file is a dummy version of {actualFile.Name}. It was downloaded with the Telerik Blazor FileManager.";
byte[] dummyFileBuffer = System.Text.Encoding.UTF8.GetBytes(dummyFileContent);
args.Stream = new MemoryStream(dummyFileBuffer);
args.MimeType = "text/plain";
args.FileName = $"filemanager-{actualFile.Name}-{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}.txt";
}
private async Task OnDeleteHandler(FileManagerDeleteEventArgs args)
{
var currItem = args.Item as FlatFileEntry;
var itemToDelete = Files.FirstOrDefault(x => x.Id == currItem.Id);
Files.Remove(itemToDelete);
RefreshData();
}
private FlatFileEntry OnModelInitHandler()
{
var item = new FlatFileEntry();
item.Name = $"New folder";
item.Size = 0;
item.Path = Path.Combine(DirectoryPath, item.Name);
item.IsDirectory = true;
item.HasDirectories = false;
item.DateCreated = DateTime.Now;
item.DateCreatedUtc = DateTime.Now;
item.DateModified = DateTime.Now;
item.DateModifiedUtc = DateTime.Now;
return item;
}
private void OnSelect(IEnumerable<FlatFileEntry> selectedFiles)
{
// Update the view model.
SelectedItems = selectedFiles;
}
private void RefreshData()
{
Files = new List<FlatFileEntry>(Files);
}
protected override async Task OnInitializedAsync()
{
Files = await GetFlatFileEntries();
}
public class FlatFileEntry
{
public string Id { get; set; }
public string ParentId { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public string Path { get; set; }
public string Extension { get; set; }
public bool IsDirectory { get; set; }
public bool HasDirectories { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateCreatedUtc { get; set; }
public DateTime DateModified { get; set; }
public DateTime DateModifiedUtc { get; set; }
}
// the next lines are hardcoded data generation so you can explore the FileManager freely
private async Task<List<FlatFileEntry>> GetFlatFileEntries()
{
var workFiles = new FlatFileEntry()
{
Id = "1",
ParentId = null,
Name = "Work Files",
IsDirectory = true,
HasDirectories = true,
DateCreated = new DateTime(2022, 1, 2),
DateCreatedUtc = new DateTime(2022, 1, 2),
DateModified = new DateTime(2022, 2, 3),
DateModifiedUtc = new DateTime(2022, 2, 3),
Path = Path.Combine("files"),
Size = 3 * 1024 * 1024
};
var Documents = new FlatFileEntry()
{
Id = "2",
ParentId = workFiles.Id,
Name = "Documents",
IsDirectory = true,
HasDirectories = false,
DateCreated = new DateTime(2022, 1, 2),
DateCreatedUtc = new DateTime(2022, 1, 2),
DateModified = new DateTime(2022, 2, 3),
DateModifiedUtc = new DateTime(2022, 2, 3),
Path = Path.Combine(workFiles.Path, "documents"),
Size = 1024 * 1024
};
var Images = new FlatFileEntry()
{
Id = "3",
ParentId = workFiles.Id,
Name = "Images",
IsDirectory = true,
HasDirectories = false,
DateCreated = new DateTime(2022, 1, 2),
DateCreatedUtc = new DateTime(2022, 1, 2),
DateModified = new DateTime(2022, 2, 3),
DateModifiedUtc = new DateTime(2022, 2, 3),
Path = Path.Combine(workFiles.Path, "images"),
Size = 2 * 1024 * 1024
};
var files = new List<FlatFileEntry>()
{
workFiles,
Documents,
Images
};
return files;
}
}
The input should be focused after the user clicks the clear button.
If you are zooming a page containing a DateTimePicker with "AdaptiveMode" set to "AdaptiveMode.Auto", the application crashes occasionally with the error:
Microsoft.JSInterop.JSException: Cannot read properties of null (reading 'addEventListener') TypeError: Cannot read properties of null (reading 'addEventListener')
The more adaptive DateTimePicker instances the page contains, the more likely the error is to occur.
The Grid shows row skeletons in virtual scrolling scenarios when:
Test page: https://blazorrepl.telerik.com/mSkBaXkC50cEXmMB42
A possible workaround is to:
Example: https://blazorrepl.telerik.com/cSYrvEYW19htMCD934
Another possible solution is to disable the virtual scrolling at runtime if the total item count is too small: https://blazorrepl.telerik.com/mSOhvYuW47DaMk6c00
We have a grid with a GridCheckboxColumn that we have configured through a '.unselectable-row' style so that certain elements cannot be selected (those elements with a padlock in the second column cannot be selected).
The grid works correctly in isolation, but when we add a TelerikLoaderContainer that is displayed during data loading process, the grid doesn't working properly: it is possible to select all the enabled elements of the grid using the button in the header of the checkbox column. However it is not possible to deselect them from the button in the header of the checkbox column when there is any unselectable element.
Here it is a link to REPL with a reproducible example: https://blazorrepl.telerik.com/GyYhYXPI24gIYgIJ03
To reproduce the problem, you sholud select all grid elements from the checkbox column header button and try to deselect them. You will not be able to deselect all the elements.
Now comment the LoaderContainer component and repeat the test. You will see that now it is possible to deselect correctly all the elements.
How can we deselect all the elements from the header while keeping the loadercontainer?
If I type the maximum value for a decimal (79228162514264337593543950335) and then try to increase the number through the arrow buttons, I get the following exception:
System.OverflowException: Value was either too large or too small for a Decimal.
The behavior is reproducible with or without setting the Max parameter to decimal.MaxValue: https://blazorrepl.telerik.com/mSuFwebI299wPCzV25.