Kendo UI Template: Invalid Template Error

10,658

I came across this problem yesterday, so I found a solution that doesn't require you to remove the encoder.

using System.Web;
using System.Web.Mvc;
using System.Web.Security.AntiXss;
using System.Web.Util;

namespace Your.Namespace.Here
{
    public static class KendoMvcExtensions
    {

        public static IHtmlString ToMvcClientTemplate(this MvcHtmlString mvcString)
        {
            if (HttpEncoder.Current.GetType() == typeof (AntiXssEncoder))
            {
                var initial = mvcString.ToHtmlString();
                var corrected = initial.Replace("\\u0026", "&").Replace("%23", "#").Replace("%3D", "=").Replace(" ", " ");
                return new HtmlString(corrected);
            }

            return mvcString;
        }
    }
}

It checks to see if the AntiXssEncoder is active, and if it is, it removes the offending encoding characters. You can take out the encoder check if you want, but don't change the order that the characters are replaced... it is structured that way because .NET will make some of the characters (especially validator text) have mixed encoding (UTF-8 and Unicode in the same character set, example: \u0026#32, which un-encoded once becomes &#32 and un-encoded twice becomes " ").

To use it, just call .ToMvcClientTemplate() at the end of any offending control declaration. In the case of the OP, you would put it right after the closing parenthesis before you close the div.

I'm keeping a copy of this code here in case someone somewhere else posts a better solution, as I've posted this code in several places.

HTH

Share:
10,658
Aaron Salazar
Author by

Aaron Salazar

C# .NET Developer

Updated on June 14, 2022

Comments

  • Aaron Salazar
    Aaron Salazar almost 2 years

    I'm trying to make a Kendo UI grid template. When I run the following Chrome gives me the error message. I've left out most of the rest of the message because it is just printing out all the generated HTML and javascript to the console.

    Uncaught Error: Invalid template:'<div class="k-widget&#32;k-grid" id="l...

    I'm trying to follow the "detailtemplate.cshtml" example on the page http://demos.kendoui.com/web/grid/detailtemplate.html

    I'm having a hard time figuring out what I'm doing wrong. If I erase everything between the template's script tags and just put in some dumb HTML it all works fine so I'm sure the problem has something to do with the way I'm putting the kendo grid in.

    This is the code I have in my HTML page. The problem is somewhere inside the <script> with the id "GridDetailsTemplate".

    <div id="pendingApproval-tab">
        @(Html.Kendo().Grid<Moly.BusinessLogic.Entities.MolyAssayEntity>()
            .Name("pending-approval-grid")
            .HtmlAttributes(new { style = "overflow: auto; height: 600px"})
            .Columns(columns =>
            {
                columns.Bound(x => x.MolyLotID).HtmlAttributes(new {@class = "moly-lot-id"}).Hidden();
                columns.Template(@<div></div>).ClientTemplate("<input class='ready-checkbox' type='checkbox'/>").Title("Ready");
                columns.Bound(x => x.LotNo).Title("Lot").Groupable(false);
                columns.Bound(x => x.DateProduced).Format("{0:MM/dd/yy}").Title("Date");
                columns.Bound(x => x.NetWetWeight).Title("Net Wet Weight");
                columns.Bound(x => x.TareWeight).Title("Tare Weight");
                columns.Bound(x => x.NetDryWeight).Title("Dry Weight");
                columns.Bound(x => x.GrossWeight).Title("Gross Weight");
                columns.Bound(x => x.MolyWeight).Title("Lbs Mo");
                columns.Bound(x => x.MoisturePercent).Title("% H20");
                columns.Bound(x => x.MolyPercent).Title("Mo");
                columns.Bound(x => x.CopperPercent).Title("Cu");
                columns.Bound(x => x.LeadPercent).Title("Pb");
                columns.Bound(x => x.InsolublesPercent).Title("Insol");
                columns.Bound(x => x.ArsenicPercent).Title("As");
                columns.Bound(x => x.CalciumOxidePercent).Title("CaO");
                columns.Bound(x => x.IronPercent).Title("Fe");
                columns.Bound(x => x.MagnesiumOxidePercent).Title("MgO");
                columns.Bound(x => x.SodiumPercent).Title("Na");
                columns.Bound(x => x.BatchID).Title("Batch ID");
                columns.Bound(x => x.DunnageWt).Title("Dunnage Wt.");
                columns.Bound(x => x.Comment).Title("Comments");
            })
            .ToolBar(toolbar =>
            {
                toolbar.Save();
            })
            .Editable(editable => editable.Mode(GridEditMode.InCell))
            .ClientDetailTemplateId("GridDetailsTemplate")
            .DataSource(ds => ds
                .Ajax()
                .Batch(true)
                .Model(model => 
                {
                    model.Id(m => m.MolyLotID);       
                })
                .Update(update => update.Action("UpdateMoly", "MolyLot"))
                .Read(read => read
                    .Action("PendingApproval", "MolyLot")
                    .Type(HttpVerbs.Post)
                )
            )
            .Events(events => events.DataBound("dataBound"))
        )
    </div>
    
    <script type="text/javascript">
        function dataBound() {
            this.expandRow(this.tbody.find("tr.k-master-row").first());
        }
    </script>
    
    <script id="GridDetailsTemplate" type="text/kendo-tmpl">
        @(Html.Kendo().Grid<Moly.BusinessLogic.Entities.UnroastedContainerEntity>()
            .Name("lot-details-grid")
            .Columns(columns =>
            {
                columns.Bound(x => x.ContainerNumber).Title("Number");
                columns.Bound(x => x.Type).Title("Type");
                columns.Bound(x => x.GrossWeight).Title("Gross Weight");
                columns.Bound(x => x.TareWeight).Title("Tare Weight");
            })
            .DataSource(DataSource => DataSource
                .Ajax()
                .Read(read => read.Action("GetBags", "MolyLot"))
            )
            .ToClientTemplate()
        )
    </script>
    

    Here is the "real" template that is generated with my template code:

    <div class="k-widget&#32;k-grid" id="lot-details-grid">
        <table cellspacing="0">
            <colgroup>
                <col />
                <col />
                <col />
                <col />
            </colgroup>
            <thead class="k-grid-header">
                <tr>
                    <th class="k-header" data-field="ContainerNumber" data-title="Number"
                    scope="col"><span class="k-link">Number</span>
                    </th>
                    <th class="k-header" data-field="Type" data-title="Type" scope="col"><span class="k-link">Type</span>
                    </th>
                    <th class="k-header" data-field="GrossWeight" data-title="Gross&#32;Weight"
                    scope="col"><span class="k-link">Gross Weight</span>
                    </th>
                    <th class="k-header" data-field="TareWeight" data-title="Tare&#32;Weight"
                    scope="col"><span class="k-link">Tare Weight</span>
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr class="t-no-data">
                    <td colspan="4"></td>
                </tr>
            </tbody>
        </table>
    </div>
    <script>
        jQuery(function () {
            jQuery("\#lot-details-grid").kendoGrid({
                "columns": [{
                    "title": "Number",
                    "field": "ContainerNumber",
                    "encoded": true
                }, {
                    "title": "Type",
                    "field": "Type",
                    "encoded": true
                }, {
                    "title": "Gross Weight",
                    "field": "GrossWeight",
                    "encoded": true
                }, {
                    "title": "Tare Weight",
                    "field": "TareWeight",
                    "encoded": true
                }],
                "scrollable": false,
                "dataSource": {
                    "transport": {
                        "read": {
                            "url": "/Moly.Web/controller/action"
                        }
                    },
                    "serverPaging": true,
                    "serverSorting": true,
                    "serverFiltering": true,
                    "serverGrouping": true,
                    "serverAggregates": true,
                    "type": "aspnetmvc-ajax",
                    "filter": [],
                    "schema": {
                        "data": "Data",
                        "total": "Total",
                        "errors": "Errors",
                        "model": {
                            "fields": {
                                "UnroastedContainerID": {
                                    "type": "number"
                                },
                                "MolyLotID": {
                                    "type": "number"
                                },
                                "GrossWeight": {
                                    "type": "number"
                                },
                                "Type": {
                                    "type": "string"
                                },
                                "TareWeight": {
                                    "type": "number"
                                },
                                "ContainerNumber": {
                                    "type": "string"
                                },
                                "Units": {
                                    "type": "string"
                                },
                                "MolyLot": {
                                    "type": "object"
                                }
                            }
                        }
                    }
                },
                "detailTemplate": kendo.template($('\#GridDetailsTemplate').html())
            });
        }); < \ / script >
            ' Generated code:'
        var o, e = kendo.htmlEncode;
        with(data) {
            o = '\n        <div class="k-widget&';
            32;
            k - grid " id="
            lot - details - grid "><table cellspacing="
            0 "><colgroup><col /><col /><col /><col /></colgroup><thead class="
            k - grid - header "><tr><th class="
            k - header " data-field="
            ContainerNumber " data-title="
            Number " scope="
            col "><span class="
            k - link ">Number</span></th><th class="
            k - header " data-field="
            Type " data-title="
            Type " scope="
            col "><span class="
            k - link ">Type</span></th><th class="
            k - header " data-field="
            GrossWeight " data-title="
            Gross & ;
            o += '32;Weight" scope="col"><span class="k-link">Gross Weight</span></th><th class="k-header" data-field="TareWeight" data-title="Tare&';
            32;
            Weight " scope="
            col "><span class="
            k - link ">Tare Weight</span></th></tr></thead><tbody><tr class="
            t - no - data "><td colspan="
            4 "></td></tr></tbody></table></div><script>
        jQuery(function(){jQuery("#lot - details - grid ").kendoGrid({"
            columns ":[{"
            title ":"
            Number ","
            field ":"
            ContainerNumber ","
            encoded ":true},{"
            title ":"
            Type ","
            field ":"
            Type ","
            encoded ":true},{"
            title ":"
            Gross Weight ","
            field ":"
            GrossWeight ","
            encoded ":true},{"
            title ":"
            Tare Weight ","
            field ":"
            TareWeight ","
            encoded ":true}],"
            scrollable ":false,"
            dataSource ":{"
            transport ":{"
            read ":{"
            url ":" / Moly.Web / controller / action "}},"
            serverPaging ":true,"
            serverSorting ":true,"
            serverFiltering ":true,"
            serverGrouping ":true,"
            serverAggregates ":true,"
            type ":"
            aspnetmvc - ajax ","
            filter ":[],"
            schema ":{"
            data ":"
            Data ","
            total ":"
            Total ","
            errors ":"
            Errors ","
            model ":{"
            fields ":{"
            UnroastedContainerID ":{"
            type ":"
            number "},"
            MolyLotID ":{"
            type ":"
            number "},"
            GrossWeight ":{"
            type ":"
            number "},"
            Type ":{"
            type ":"
            string "},"
            TareWeight ":{"
            type ":"
            number "},"
            ContainerNumber ":{"
            type ":"
            string "},"
            Units ":{"
            type ":"
            string "},"
            MolyLot ":{"
            type ":"
            object "}}}}},"
            detailTemplate ":kendo.template($('#GridDetailsTemplate').html())});});
    <\/script>
        ;o+=;}return o;'