Kendo UI EditorTemplate not working with hierarchy/child grid: Invalid Template
1 Answer 49 Views
Peter
Top achievements
Rank 1
Peter asked on 19 May 2021, 09:40 PM | edited on 19 May 2021, 09:42 PM

Hi,

I am creating a Kendo grid which involves using a Dropdown List for certain cells. I have created the Editor Template for the dropdown inside the Shared/EditorTemplates folder called DropdownList.cshtml. The dropdown list works as intended, I have inline editing enabled and I am able to update the values via Ajax.

Here's the column in the initial grid:

columns.Bound(e => e.Balance).Width(40).Title("Balance").ClientTemplate("<span>#=getIcon(Balance)#</span>").EditorTemplateName("DropdownList");

The problem occurs when I try to use that same EditorTemplate called DropdownList in a hierarchy grid, just below its predecessor. The subgrid is configured using .ClientDetailTemplateId("template"), where the child grid is titled .Name("tracking-grid_#=id#"), and linked using .ToClientTemplate(). (As shown in the Telerik demonstration here.).

As soon as I add the .EditorTemplateName("DropdownList"); to the following line, the grid does not load and I receive the following error in the browser console: Uncaught Error: Invalid template

columns.Bound(e => e.Balance).Width(40).Title("Balance").ClientTemplate("<span>#=getIcon(Balance)#</span>").EditorTemplateName("DropdownList");

** Note: I know these columns have the same name, but they are being taken from different datasets. It just so happens to appear in both grids.

Searching for solutions, I made sure to try escaping all (#) hash characters with \\ wherever they appear, and I tried creating an alternate file in the EditorTemplates folder so they would be distinct. The grid still breaks and fails to render each time from just this one line.

I found a similar discussion here that I thought would help me, but no luck.

I understand that I am trying to use the same Editor Template in two separate grids. But I really need to use this dropdownlist in both. Is MVC not able to use the same editor template in nested grids like this, or is there something else I'm missing?

Thanks.

Peter
Top achievements
Rank 1
commented on 20 May 2021, 01:41 PM

UPDATE:

I have now gotten the grid to render by escaping jQuery items using \# in the actual script template. However, the dropdownlist still does not display in the hierarchy grid. When I click the cell, it opens the inline editing tool as if the editortemplate is being ignored.

1 Answer, 1 is accepted

Sort by
0
Patrick
Telerik team
answered on 24 May 2021, 08:42 PM

Hi Peter,

The Kendo UI Grid can allow for a specific field to use the same editor in both a master and child Grid.  One way to accomplish this is to use the UIHint Attribute.  For example, say you have two classes which have a Balance field: Employee and Order.

Employee.cs

    public class Employee
    {
        public int EmployeeID { get; set; }
        public string EmployeeName { get; set; }
        public int BalanceID { get; set; }
        [UIHint("BalanceEditor")]
        public virtual Balance Balance { get; set; }

    }

Order.cs

    public class Order
    {
        public int OrderID { get; set; }
        public string OrderName { get; set; }
        public int BalanceID { get; set; }

        [UIHint("BalanceEditor")]
        public virtual Balance Balance { get; set; }
        public int? EmployeeID { get; set; }

    }

BalanceEditorTemplate.cs

@model GridExample.Models.Balance

@(Html.Kendo().DropDownListFor(m => m)
        .DataValueField("BalanceID")
        .DataTextField("BalanceName")
        .BindTo((System.Collections.IEnumerable)ViewData["balances"])
)

 

In each Grid, the Balance field will be within a Bound column with a clientTemplate pointing to the DataTextField(in this case "BalanceName").  But to get the field accurately in the child grid, the hash literals will need to be escaped.  Otherwise, you'll get the master grid's template data.

MasterGrid

        .Columns(columns =>
        {
            columns.Bound(e => e.EmployeeID).Width(130);
            columns.Bound(e => e.EmployeeName).Width(130);
            columns.Bound(e => e.Balance).ClientTemplate("#=Balance.BalanceName#");
            columns.Command(command => { command.Edit(); command.Destroy(); }).Width(300);
        })

ChildGrid

            .Columns(columns =>
            {
                columns.Bound(o => o.OrderID).Width(110);
                columns.Bound(o => o.OrderName).Width(150);
                columns.Bound(o => o.Balance).ClientTemplate("\\#=Balance.BalanceName\\#");
                columns.Command(command => { command.Edit(); command.Destroy(); }).Width(300);
            })

The model should also include a defaultValue to ensure when creating a new record it will be populated correctly and no errors show like in this Editing custom editor demo(see Description Section).  The ViewData["defaultBalance"] gets the first record of balances:

        .DataSource(dataSource => dataSource
            .Ajax()
            .Model(model =>
            {
                model.Id(p => p.EmployeeID);
                model.Field(p => p.EmployeeID).Editable(false);
                model.Field(p => p.Balance).DefaultValue(
                   ViewData["defaultBalance"] as GridExample.Models.Balance);
            })
            //...
        )

Lastly, to ensure one record is edited at a time during Inline editing, during the BeforeEdit event, check if there are any rows existing with "k-grid-edit-row".  If so, prevent the edit similar to this Kendo UI Knowledge Base article.

JavaScript

    function onBeforeEdit(e) {
        var grids = $(".k-grid");
        var editRows = grids.find(".k-grid-edit-row");

        if (editRows.length > 0) {
            alert("Please complete the editing operation before editing another row");
            e.preventDefault();
        }
    }

Please take a look at this screencast and the attached project which demonstrates the approach above in action and for a comparison.  It uses EF6 and database seeding within MSSQLLocalDB called TestDB1520404 with tables Employee, Order, and Balance.

DbInitializer.cs

    public class DbInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<EmployeeDataContext>
    {
        protected override void Seed(EmployeeDataContext context)
        {
            var balances = new List<Balance> 
            { 
                new Balance { BalanceID = 1, BalanceName = "BalanceOne" },
                new Balance { BalanceID = 2, BalanceName = "BalanceTwo"},
                new Balance { BalanceID = 3, BalanceName = "BalanceThree" }
            };

            balances.ForEach(b => context.Balances.Add(b));
            context.SaveChanges();

            var employees = new List<Employee>
            {
             new Employee{ 
                 EmployeeName = "John", 
                 BalanceID = 1, 
               },
             new Employee{ 
                 EmployeeName = "Jane", 
                 BalanceID = 2, 
                },
            };

            employees.ForEach(e => context.Employees.Add(e));
            context.SaveChanges();

            var orders = new List<Order>
            {
                new Order{ 
                    OrderName = "OrderOne", 
                    EmployeeID= 1, 
                    BalanceID = 1, 
                },
                new Order{ 
                    OrderName = "OrderTwo",
                    EmployeeID= 2, 
                    BalanceID = 2, 
                },
                new Order{
                    OrderName = "OrderThree",
                    EmployeeID= 1, 
                    BalanceID = 3, 
                },
                new Order{ 
                    OrderName = "OrderFour", 
                    EmployeeID= 2, 
                    BalanceID = 1, 
                },
                new Order{ 
                    OrderName = "OrderFive", 
                    EmployeeID= 1,
                    BalanceID = 2,
                },
                new Order{ 
                    OrderName = "OrderSix",
                    EmployeeID= 2,
                    BalanceID = 3,
                },
            };

            orders.ForEach(o => context.Orders.Add(o));
            context.SaveChanges();

        }
    }

I hope this information helps out!

Regards,
Patrick
Progress Telerik

Тhe web is about to get a bit better! 

The Progress Hack-For-Good Challenge has started. Learn how to enter and make the web a worthier place: https://progress-worthyweb.devpost.com.

Peter
Top achievements
Rank 1
commented on 25 May 2021, 01:09 PM

Hi Patrick,

Thank you for the detailed response. While your information was helpful, it doesn't exactly apply to my scenario. I have one dropdownlist stored in a file: Shared/EditorTemplates/DropdownList.cshtml.

This dropdown was created entirely in jQuery - The reason is because I am using icons to represent a specific set of values to be chosen from. It sets the "status" of a letter in the DB via Ajax:

<input id="dropdownlist" />
<script>
// Initialize dropdownlist options
var items = [
{ text: " ", template: "<span> </span>", value: "remove" },
{ text: " ", template: "<span><i class='fa fa-check-square' style='color:green;'></i></span>", value: "received" },
{ text: " ", template: "<span><i class='fa fa-circle' style='color:goldenrod;'></i></span>", value: "none" },
{ text: " ", template: "<span><i class='fa fa-exclamation-triangle' style='color:red;'></i></span>", value: "alert" },
{ text: " ", template: "<span><i class='fa fa-minus-circle' style='color:black;'></i></span>", value: "na" },
{ text: " ", template: "<span><i class='fa fa-question' style='color:black;'></i></span>", value: "auditor" }
];

// Create dropdownlist, set data source
$("\#dropdownlist").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: items,
change: onChange
});
</script>

In this case, the onChange method is where I save the value into SQL Server, and refresh the grid to display the icon. You can see I am not using .BindTo((System.Collections.IEnumerable)ViewData["balances"]), or the UIHint Attribute.

To actually apply this dropdownlist in the grids, I simply set the EditorTemplateName to the template title (in this case, DropdownList):

columns.Bound(e => e.Balance).Width(40).Title("Balance").ClientTemplate("<span>#=getIcon(Balance)#</span>").EditorTemplateName("DropdownList");

As I mentioned, the parent grid allows me to select and update values from the dropdownlist. When I click on a cell in the child grid, it opens the inline editor but does not display the Dropdownlist Editor Template,
ignoring it despite the fact that it is being specified with the .EditorTemplateName("DropdownList").

Sorry for not specifying in my original post - But hopefully this accurately describes what my problem is.

Thanks!
Patrick
Telerik team
commented on 25 May 2021, 05:26 PM

To keep the project available and to address the different issue, I'll reply to your other post.   Please feel free to review the previous reply for future reference.

Asked by
Peter
Top achievements
Rank 1
Answers by
Patrick
Telerik team
Share this question
or