Hi guys,
I have a grid with inline editing and I want to add some custom validation, as you can check below.
<TelerikGrid Data="@Model.Equipments"
EditMode="GridEditMode.Inline"
OnUpdate="@OnUpdate"
OnCreate="@OnCreate"
OnDelete="@OnDelete">
<GridToolBarTemplate>
<GridCommandButton Command="Add">Add new equipment</GridCommandButton>
</GridToolBarTemplate>
<GridColumns>
<GridColumn Field="@nameof(Equipment.Code)"
Title="Code">
<EditorTemplate>
@{
Equipment item = (Equipment)context;
}
<div class="k-form-field-wrap">
<TelerikTextBox @bind-Value="item.Code" />
<TelerikValidationMessage For="@(() => item.Code)" />
</div>
</EditorTemplate>
</GridColumn>
<GridColumn Field="@nameof(Equipment.Name)"
Title="Name">
<EditorTemplate>
@{
Equipment item = (Equipment)context;
}
<div class="k-form-field-wrap">
<TelerikTextBox @bind-Value="item.Name" />
<TelerikValidationMessage For="@(() => item.Name)" />
</div>
</EditorTemplate>
</GridColumn>
<GridCommandColumn Width="185px">
<GridCommandButton Command="Edit">Edit</GridCommandButton>
<GridCommandButton Command="Delete">Delete</GridCommandButton>
<GridCommandButton Command="Save" ShowInEdit="true">Save</GridCommandButton>
<GridCommandButton Command="Cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
public sealed class Equipment
{
public Guid Id { get; set; }
[Required]
public string? Name { get; set; }
[Required]
public string? Code { get; set; }
}
If I don't fill in the Name or Code, I and I hit Save, I can see the validation message under the corresponding column in the row that is in edit mode. So far so good.
However, say that I want the code to be unique. How to I tackle this one? I would like to see a validation message under the Code textbox "That code already exists", or whatever the message might be.
Any guidance on the recommended approach here would be great—thanks!
Regards,
Bogdan
When I call "Dialogs.AlertAsync", I get null reference error. Any reason why? The whole page is under TelerikRootComponent.
<TelerikGrid Data="@availableSchedules" class="myTelerik-grid" SelectionMode="GridSelectionMode.Multiple"
SelectedItems="@selectedSchedules"
SelectedItemsChanged="@((IEnumerable<BTWInstructorAvailability> newSelected) => OnRowSelect(newSelected))"
ScrollMode="GridScrollMode.Scrollable" Height="300px">
<GridColumns>
<GridCheckboxColumn CheckBoxOnlySelection="true" SelectAll="false" />
<GridColumn Field="InstructorName" Title="Instructor Name" />
<GridColumn Field="StartDate" DisplayFormat="{0:MM/dd/yyyy}" Title="Start Date" />
<GridColumn Field="EndDate" DisplayFormat="{0:MM/dd/yyyy}" Title="End Date" />
<GridColumn Field="Languages" Title="Languages" />
</GridColumns>
</TelerikGrid>
protected async Task OnRowSelect(IEnumerable<BTWInstructorAvailability> newSelected)
{
// Enforce max selection of 3
if (newSelected.Count() > 3)
{
await Dialogs.AlertAsync("Maximum of 3 lessons can be selected.");
return;
}
selectedSchedules = newSelected;
}
I have a grid that is needs to use EditMode=GridEditMode.Incell. I have a Telerik CheckBox defined under Template for a GridColumn. In order to prevent the need to click twice on the checkbox in the grid (click once to enter edit and click again to actually change the state of the checkbox to checked/unchecked), I have to set the GridColumn to Editable=false and then use OnChange to set the model value:
<TelerikGrid @ref="@BookingEquipmentGridRef"
Data="@BookingEquipmentList"
EditMode="@GridEditMode.Incell"
OnEdit="@OnEquipmentEdit"
OnRowClick="@OnEquipmentRowClick"
OnRowRender="@OnRowRenderHandler"
OnUpdate="@OnEquipmentUpdate"
OnStateInit="@((GridStateEventArgs<BookingEquipmentModel> args) => OnEquipmentGridStateInit(args))"
Height="226px"
Size="@ThemeConstants.Grid.Size.Small"
SelectionMode="GridSelectionMode.Single"
SelectedItems="@SelectedEquipmentList"
FilterMode="GridFilterMode.FilterMenu"
Resizable="true"
Sortable="true"
Reorderable="true"
Pageable="true"
EnableLoaderContainer="false"
PageSize="25">
<GridColumns>
<GridColumn Field=@nameof(BookingEquipmentModel.IsChassis) Title="Chassis" Editable="false" Filterable="false" Width="5rem">
<Template>
@{
var bem = (BookingEquipmentModel)context;
}
<TelerikCheckBox Value="@bem.IsChassis" ValueExpression="@(() => bem.IsChassis)" ValueChanged="@((bool newValue) => OnChassisChanged(newValue, bem))" />
</Template>
</GridColumn>
</GridColumns>
</TelerikGrid>
Because I have to set Editable=false the OnEdit event is not fired so I no longer can use args.IsCancelled = true to prevent cell update. In my OnChassisChanged I can not assigned the value to the model but the visual state will no longer match.
private Task OnChassisChanged(bool newValue, object item)
{
if (item == null) return Task.CompletedTask;
BookingEquipmentModel selectedEquipmentModel = (BookingEquipmentModel)item;
if (EditableState(SelectedBooking, selectedEquipmentModel) == BookingEquipmentState.EditableStatus.No) return Task.CompletedTask;
selectedEquipmentModel.IsChassis = newValue;
selectedEquipmentModel.IsEdit = true;
DataState.State = DataState.States.UnSaved;
return Task.CompletedTask;
}
My users were complaining about having to click twice on a checkbox to set it's new state (checked or unchecked) ... and I agree with their issue, but I can't seem to find a solution (and keep using the TelerikCheckBox) ... any suggestions?
I seem to recall reading another thread from some other user having similar problem, but seem unable to locate it again.
When a user makes a selection in a dropdown in the first row of a Blazor Grid I want to be able to hide the same column in all the remaining rows to prevent them from making selections in those dropdowns. Is this possible?
I'm getting this error when bound data list for a detail template is null
I don't have a Parameter 'source' in any model so don't understand what this is in reference to?
<DetailTemplate>
<div class="form-group form-inline right">
@{
var bookingEquip = context as BookingEquipmentModel;
<TelerikGrid @ref="@bookingEquipmentCommodityGridRef"
Data="bookingEquip.Commodities"
Pageable="true"
PageSize="4"
Resizable="true"
Size="@ThemeConstants.Grid.Size.Small"
Width="90rem"
EditMode="@GridEditMode.Incell"
OnDelete="@((GridCommandEventArgs args) => OnCommodityDelete(args, bookingEquip))"
OnCreate="@((GridCommandEventArgs args) => OnCommodityCreate(args, bookingEquip))"
OnUpdate="@((GridCommandEventArgs args) => OnCommodityUpdate(bookingEquip, args))">
<GridToolBarTemplate>
<!-- can only add a single commodity if there are none associated with this equipment) -->
<GridCommandButton Command="Add" Class="btn-green" Icon="@FontIcon.Plus" Enabled="@(!bookingEquip.Commodities.Any())">Add Commodity</GridCommandButton>
</GridToolBarTemplate>
<GridColumns>
<!-- Commodity Types -->
<GridColumn Field=@nameof(BookingEquipmentCommodityModel.CommodityType) Editable="true" Title="Description" Width="6rem">
<EditorTemplate Context="cbecContext">
@{
_currentBookingEquipmentCommodityModel = cbecContext as BookingEquipmentCommodityModel;
if (_currentBookingEquipmentCommodityModel != null)
{
<TelerikDropDownList Data="@_CommodityList"
Value="@_currentBookingEquipmentCommodityModel.CommodityTypeId"
for the Data reference, bookingEquip is NOT null but it's property bookingEquip.Commodities is indeed null (expected).
The grid displays correctly, but as soon as I click on the "+" expand it will crash with exception in the control.
I'm puzzled as to why this is happening? When I populate other grids (not using a DetailTemplate) in my Blazor app, and the Data reference is a null, nothing is displayed/render in the grid and I just get a "No records available." ... which is good. But the same behavior doesn't seem to happen when using DetailTemplate?
Any suggestions?
Rob.
If I want to restrict the number of selected rows to just three, can I do this with a configuration or a property? I am looking at the following demo. Thanks!
public static List<AggregateFunctionsGroup>? DeserializeGroups<TGroupItem>(this List<AggregateFunctionsGroup> groups)
{
if (groups is null) return null;
for (int i = 0; i < groups.Count; i++)
{
var group = groups[i];
// Workaround for JsonElement -> string
if (group.Key is JsonElement elem && elem.ValueKind == JsonValueKind.String)
{
group.Key = elem.GetString();
}
if (group.HasSubgroups)
{
var subGroups = group.Items
.Cast<JsonElement>()
.Select(x => x.Deserialize<AggregateFunctionsGroup>())
.ToList();
group.Items = DeserializeGroups<TGroupItem>(subGroups);
}
else
{
var items = group.Items
.Cast<JsonElement>()
.Select(x => x.Deserialize<TGroupItem>())
.ToList();
group.Items = items;
}
}
return groups;
}
public async Task ReadItems(GridReadEventArgs args)
{
if (!ModelIsReady) return;
if (_readItemsPending) return;
if (string.IsNullOrWhiteSpace(PreparedQuery.Id)) return;
_readItemsPending = true;
try
{
var result = await ApiService.QueryDataSourceAsync<UniversalDSModel>(PreparedQuery.QueryId, args.Request, CancellationToken.None);
if (result is null) return;
if (args.Request.Groups.Count > 0)
{
args.Data = result?.GroupedData.DeserializeGroups<UniversalDSModel>();
}
else
{
args.Data = result?.CurrentPageData.Cast<object>().ToList();
}
if (result?.AggregateResults != null)
{
args.AggregateResults = result.AggregateResults;
}
if (result != null) { args.Total = result.TotalItemCount; }
}
catch (Exception ex)
{
Console.WriteLine($"Error loading data: {ex.Message}");
ApiRequestFailed = true;
}
finally
{
_readItemsPending = false;
LoaderContainerVisible = false;
}
}