I have a relation that I am trying to represent in a grid.
One object has a Guid that points to another object which has a textual representation of the field.
I want to display the textual value in the grid.
The editor should display a pick list of values that display the textual values (drop down list), but puts the guid into the referencing object.
So to say this another way, I want a guid field in the grid to display as the related textual value. When you edit the field, it should be a pic list with the textual values from that table. The selected value from that list should save the related guid into the model object.
I imagine this is a common use case.
Do you have an example of something like this?
10 Answers, 1 is accepted
To do this you need to use:
- the cell template of the column to translate the guid to a human-readable string
- the edit template of the column to place a dropdown bound to the desired data
You can find examples of both in the documentation: https://docs.telerik.com/blazor-ui/components/grid/templates.
Here is a more specific one I made for you:
@
using
Telerik.Blazor.Components.Grid
<TelerikGrid Data=@MyData EditMode=
"inline"
Pageable=
"true"
>
<TelerikGridColumns>
<TelerikGridColumn Field=@nameof(SampleData.ID) Title=
"ID"
Editable=
"false"
/>
<TelerikGridColumn Field=@nameof(SampleData.Name) Title=
"Name"
/>
<TelerikGridColumn Field=@nameof(SampleData.Role) Title=
"Position"
>
<Template Context=
"currEmployee"
>
@(GetRoleText(currEmployee
as
SampleData))
</Template>
<EditorTemplate>
@{
CurrentlyEditedEmployee = context
as
SampleData;
<select bind=@CurrentlyEditedEmployee.Role>
@
foreach
(MyDdlModel item
in
myDdlData)
{
<option value=@item.MyValueField>@item.MyTextField</option>
}
</select>
}
</EditorTemplate>
</TelerikGridColumn>
<TelerikGridCommandColumn>
<TelerikGridCommandButton Command=
"Save"
Icon=
"save"
ShowInEdit=
"true"
>Update</TelerikGridCommandButton>
<TelerikGridCommandButton Command=
"Edit"
Icon=
"edit"
>Edit</TelerikGridCommandButton>
</TelerikGridCommandColumn>
</TelerikGridColumns>
<TelerikGridEvents>
<EventsManager OnUpdate=
"@UpdateHandler"
></EventsManager>
</TelerikGridEvents>
</TelerikGrid>
@functions {
public
SampleData CurrentlyEditedEmployee {
get
;
set
; }
public
void
UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
//perform actual data source operations here
//if you have a context added through an @inject statement, you could call its SaveChanges() method
//myContext.SaveChanges();
var matchingItem = MyData.FirstOrDefault(c => c.ID == item.ID);
if
(matchingItem !=
null
)
{
matchingItem.Name = item.Name;
matchingItem.Role = item.Role;
}
}
protected
override
void
OnInit()
{
GetRoles();
GetGridData();
}
void
GetRoles()
{
if
(myDdlData ==
null
)
{
myDdlData =
new
List<MyDdlModel>();
myDdlData = Enumerable.Range(1, 20).Select(x =>
new
MyDdlModel
{
MyTextField =
"role "
+ x,
MyValueField = x
}).ToList();
}
}
void
GetGridData()
{
MyData =
new
List<SampleData>();
for
(
int
i = 1; i < 50; i++)
{
MyData.Add(
new
SampleData()
{
ID = i,
Name =
"name "
+ i,
Role = i % (myDdlData.Count - 1)
});
}
}
private
string
GetRoleText(SampleData currEmployee)
{
MyDdlModel currRoleModel = myDdlData.Where(x => x.MyValueField == currEmployee.Role).FirstOrDefault();
if
(currRoleModel !=
null
)
{
return
currRoleModel.MyTextField;
}
return
"unknown"
;
}
//in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public
class
SampleData
{
public
int
ID {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
int
Role {
get
;
set
; }
}
public
class
MyDdlModel
{
public
int
MyValueField {
get
;
set
; }
public
string
MyTextField {
get
;
set
; }
}
List<MyDdlModel> myDdlData {
get
;
set
; }
public
List<SampleData> MyData {
get
;
set
; }
}
Regards,
Marin Bratanov
Progress Telerik UI for Blazor

Awesome, I should have tried combining the two template sections. It wasn't immediately obvious that you could do that.
Thanks for all your help! I am almost done with my application. I will send you screen shots of my creation. I am stealing your Dashboard css/layout scheme.
Thanks,
Kenny
It's good to hear you are making progress :)
I hope the sample app will be helpful to you, we published it so it can be used as an example and you can freely reuse it.
I'll be looking forward to seeing what you create with the help of our components, it will be interesting to see them in the wild!
Regards,
Marin Bratanov
Progress Telerik UI for Blazor

I converted this over to a Guid and I am getting some strange compile time errors. Can you see what I missed?
@using Telerik.Blazor.Components.Grid
using Telerik.Blazor.Components.Grid
<TelerikGrid Data=@MyData EditMode="inline" Pageable="true">
<TelerikGridColumns>
<TelerikGridColumn Field=@nameof(SampleData.ID) Title="ID" Editable="false" />
<TelerikGridColumn Field=@nameof(SampleData.Name) Title="Name" />
<TelerikGridColumn Field=@nameof(SampleData.Role) Title="Position">
<Template Context="currEmployee">
@(GetRoleText(currEmployee as SampleData))
</Template>
<EditorTemplate>
@{
CurrentlyEditedEmployee = context as SampleData;
<select bind=@CurrentlyEditedEmployee.Role>
@foreach (MyDdlModel item in myDdlData)
{
<option value=@item.MyValueField>@item.MyTextField</option>
}
</select>
}
</EditorTemplate>
</TelerikGridColumn>
<TelerikGridCommandColumn>
<TelerikGridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</TelerikGridCommandButton>
<TelerikGridCommandButton Command="Edit" Icon="edit">Edit</TelerikGridCommandButton>
</TelerikGridCommandColumn>
</TelerikGridColumns>
<TelerikGridEvents>
<EventsManager OnUpdate="@UpdateHandler"></EventsManager>
</TelerikGridEvents>
</TelerikGrid>
@functions {
public SampleData CurrentlyEditedEmployee { get; set; }
public void UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
//perform actual data source operations here
//if you have a context added through an @inject statement, you could call its SaveChanges() method
//myContext.SaveChanges();
var matchingItem = MyData.FirstOrDefault(c => c.ID == item.ID);
if (matchingItem != null)
{
matchingItem.Name = item.Name;
matchingItem.Role = item.Role;
}
}
protected override void OnInit()
{
GetRoles();
GetGridData();
}
void GetRoles()
{
if (myDdlData == null)
{
myDdlData = new List<MyDdlModel>();
for (int i = 1; i <= 20; i++)
{
var model = new MyDdlModel();
model.MyTextField = "role " + i;
model.MyValueField = new Guid();
myDdlData.Add(model);
}
}
}
void GetGridData()
{
MyData = new List<SampleData>();
for (int i = 1; i < 50; i++)
{
MyData.Add(new SampleData()
{
ID = i,
Name = "name " + i,
Role = new Guid()
});
}
}
private string GetRoleText(SampleData currEmployee)
{
MyDdlModel currRoleModel = myDdlData.FirstOrDefault(x => x.MyValueField == currEmployee.Role);
if (currRoleModel != null)
{
return currRoleModel.MyTextField;
}
return "unknown";
}
//in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public class SampleData
{
public int ID { get; set; }
public string Name { get; set; }
public Guid Role { get; set; }
}
public class MyDdlModel
{
public Guid MyValueField { get; set; }
public string MyTextField { get; set; }
}
List<MyDdlModel> myDdlData { get; set; }
public List<SampleData> MyData { get; set; }
}
I am getting a compiler error: Cannot implicitly convert type 'string' to 'System.Guid'
The line of code from the razor.g.cs file is here:
builder3.AddAttribute(28, "onchange", Microsoft.AspNetCore.Components.EventCallback.Factory.CreateBinder(this, __value => CurrentlyEditedEmployee.Role = __value, CurrentlyEditedEmployee.Role));
Before we continue, would it be OK with you if I moved this thread to the public forum? I believe the information and examples in it can be useful for other people as well.
It looks like the select element can't handle a Guid value, because the following will not compile either, for the same reason:
<select bind=@TestVar.Role>
@
foreach
(MyDdlModel item
in
myDdlData)
{
<option value=@item.MyValueField>@item.MyTextField</option>
}
</select>
@TestVar.Role
@functions {
SampleData TestVar {
get
;
set
; } =
new
SampleData { ID = 1234, Name =
"the test"
, Role =
new
Guid() };
}
Perhaps you can go through the string representation of the guid for the value, and populate it in the model through the onchange handler of the select (I highlighted the changes):
@
using
Telerik.Blazor.Components.Grid
<TelerikGrid Data=@MyData EditMode=
"inline"
Pageable=
"true"
>
<TelerikGridColumns>
<TelerikGridColumn Field=@nameof(SampleData.ID) Title=
"ID"
Editable=
"false"
/>
<TelerikGridColumn Field=@nameof(SampleData.Name) Title=
"Name"
/>
<TelerikGridColumn Field=@nameof(SampleData.Role) Title=
"Position"
>
@*<Template Context=
"currEmployee"
>
@(GetRoleText(currEmployee
as
SampleData))
</Template>*@
<EditorTemplate>
@{
CurrentlyEditedEmployee = context
as
SampleData;
<select onchange=
"@SetGuidFromString"
>
@
foreach
(MyDdlModel item
in
myDdlData)
{
<option value=@item.MyValueField>@item.MyTextField</option>
}
</select>
}
</EditorTemplate>
</TelerikGridColumn>
<TelerikGridCommandColumn>
<TelerikGridCommandButton Command=
"Save"
Icon=
"save"
ShowInEdit=
"true"
>Update</TelerikGridCommandButton>
<TelerikGridCommandButton Command=
"Edit"
Icon=
"edit"
>Edit</TelerikGridCommandButton>
</TelerikGridCommandColumn>
</TelerikGridColumns>
<TelerikGridEvents>
<EventsManager OnUpdate=
"@UpdateHandler"
></EventsManager>
</TelerikGridEvents>
</TelerikGrid>
@functions {
public
SampleData CurrentlyEditedEmployee {
get
;
set
; }
void
SetGuidFromString(UIChangeEventArgs e)
{
string
selectedString = e.Value.ToString();
Guid actualGuid =
new
Guid(selectedString);
CurrentlyEditedEmployee.Role = actualGuid;
}
public
void
UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
//perform actual data source operations here
//if you have a context added through an @inject statement, you could call its SaveChanges() method
//myContext.SaveChanges();
var matchingItem = MyData.FirstOrDefault(c => c.ID == item.ID);
if
(matchingItem !=
null
)
{
matchingItem.Name = item.Name;
matchingItem.Role = item.Role;
}
}
protected
override
void
OnInit()
{
GetRoles();
GetGridData();
}
void
GetRoles()
{
if
(myDdlData ==
null
)
{
myDdlData =
new
List<MyDdlModel>();
for
(
int
i = 1; i <= 20; i++)
{
var model =
new
MyDdlModel();
model.MyTextField =
"role "
+ i;
model.MyValueField = Guid.NewGuid().ToString();
myDdlData.Add(model);
}
}
}
void
GetGridData()
{
MyData =
new
List<SampleData>();
for
(
int
i = 1; i < 50; i++)
{
MyData.Add(
new
SampleData()
{
ID = i,
Name =
"name "
+ i,
Role =
new
Guid()
});
}
}
private
string
GetRoleText(SampleData currEmployee)
{
MyDdlModel currRoleModel = myDdlData.FirstOrDefault(x => x.MyValueField == currEmployee.Role.ToString());
if
(currRoleModel !=
null
)
{
return
currRoleModel.MyTextField;
}
return
"unknown"
;
}
//in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public
class
SampleData
{
public
int
ID {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
Guid Role {
get
;
set
; }
}
public
class
MyDdlModel
{
public
string
MyValueField {
get
;
set
; }
public
string
MyTextField {
get
;
set
; }
}
List<MyDdlModel> myDdlData {
get
;
set
; }
public
List<SampleData> MyData {
get
;
set
; }
}
Regards,
Marin Bratanov
Progress Telerik UI for Blazor

Yea, you can put any of our threads in public forum. Should I ask these kind of questions there?
Thanks for all your help!


If you don't have anything that you want kept private, or anything urgent, I would suggest considering a public forum thread. This makes the information available to everyone and our discussion may help someone else down the road.
As for the guid issue - it it not, indeed, related to the event handling problems in the framework. What I can say on the matter is that we are looking into the possibility to allow guid fields to be used for the value of a Telerik dropdownlist, but it is not available there yet either.
Regards,
Marin Bratanov
Progress Telerik UI for Blazor

I ran into an issue with this work around when adding new items to the grid.
If you don't select a new item from the drop down list (you go with the default or first element), then in the call to OnCreate the Guids value will be all 0's (or Guid.Empty). Makes sense, since we changed over from a bind to oncreate. Since we don't pick a value, the onchange event is never called.
I came up with a work around. In the OnCreate handler, check for the Guid value being empty. If it is set it to the first value in the pick list values List like this:
if (itemForPost.ApplicationNameId.Equals(Guid.Empty))
{
itemForPost.ApplicationNameId = ApplicationNames[0].Id;
}
I know it's a bit of a kludge, but until we get native support for Guids in select this will do.
I have a another small improvement to the example you sent me. This set's the selected attribute for the item that is currently selected, so it will be the default value in the drop down:
CurrentlyEditedEmployee = context as SampleData;
<select onchange="@SetGuidFromString" >
@foreach (MyDdlModel item in myDdlData)
{
if (item.MyValueField.Equals(CurrentlyEditedEmployee.Role.ToString()))
{
<option value=@item.MyValueField selected="selected">@item.MyTextField</option>
}
else
{
<option value=@item.MyValueField>@item.MyTextField</option>
}
}
</select>
Just thought that be a useful addition.
Thanks again for all your help!