Telerik Forums
UI for ASP.NET Core Forum
0 answers
541 views

In our UI for ASP.NET Core R3 2020 (2020.3.915) release, the Column menu message of unsticking a column is "null".

This bug will be resolved in our next official release.

In the meantime, as a workaround, manually set the Unstick Column menu message:

.ColumnMenu(c => c.Messages(m => m.Unstick("Unstick Column")))
Kendo UI
Top achievements
Rank 1
 asked on 16 Sep 2020
2 answers
13 views

Hi, I'm migrating a view that was originally written using HTML Helpers in ASP.NET MVC, and I have now ported it to ASP.NET Core using Tag Helpers.

There is a grid with another grid as its detail. The inner grid makes extensive use of variable interpolation—for example, in the grid name, the ID of the container row is used. This works correctly with the HTML Helper approach:

// the template reference
.ClientDetailTemplateId("template-controls")

//the child grid definition, variable interpolation in the grid name and the toolbar, both work
<script id="template-controls" type="text/x-kendo-template">
    @(Html.Kendo().Grid<ChildItem>()
        .Name("GroupGrid_#=GroupID#")
        .ToolBar(toolbar =>
        {
            toolbar.Template(
                "<div class='edit-toolbar'>" 
                    +"<button onclick='editChild(" + Model.ID + ",0,#=GroupID#, this)'>Edit</button>" 
                + "</div>"
            );
        })
    )
</script>

 

But when this code is migrated to ASP.NET Core using Tag Helpers, the variable interpolation in the toolbar does not occur. I would like to know whether this is an error in my code or a feature that is no longer supported.

Here is the Tag Helper code:


//the template reference
<grid-detail-template>
    <kendo-grid name="GroupGrid_${data.GroupID}">
        <toolbar client-template-id="GroupGrid_Toolbar"></toolbar>
    </kendo-grid>
</grid-detail-template>


//the child grid definition, variable interpolation works in the grid name , but the interpolation in toolbar do not
<script id="GroupGrid_Toolbar" type="text/html">
    <div class='edit-toolbar'>
        <button onclick=' editChild(@Model.ID,0,#=GroupID#, this)'>Edit</button>
    </div>
</script>

The browser shows the following error:
Uncaught ReferenceError: GroupID is not defined

The offending line is:


with (data) {
        $kendoOutput = '\n\n        <div class=\'edit-toolbar\'>\n            <button onclick=\'editChild(11941,0,' + (GroupID) + ', this)\' \n                    >\n                ' + ($kendoHtmlEncode(data.GroupID)) + ' : ' + (GroupID) + ' Edit #\n            </button>\n </div>\n ';
    }
BTW similar result if instead of the client-template-id attribute of the toolbar, it is declared as:

<toolbar>
                                    <toolbar-button>
                                        <toolbar-command-template>
// the variable interpolation placed here
                                        </toolbar-command-template>
                                    </toolbar-button>
                                </toolbar> 


Gerardo
Top achievements
Rank 1
Iron
 updated answer on 10 Sep 2025
1 answer
10 views

I have a .net core 8 web application, that has a grid that loads data via Ajax.  When I edit a row, I'd like the `Contract` column to be a multi-select dropdown.  When I edit a row, the control is rendered, but there is no data in it.  I have set static data and the data does show up.

Here's my grid:

@(
Html.Kendo().Grid<ContractBenefitViewModel>()
    .Name("ContractBenefitGrid")
    .Columns(columns =>
    {
        columns.Bound(c => c.Id).Hidden(true);
        columns.Bound(c => c.Contracts)
            .ClientTemplate("#= displayContracts(data) #")
            .EditorTemplateName("Contracts")
            .Width(400)
            .Filterable(false)
            .Sortable(false);
        columns.ForeignKey(c => c.BenefitId, (IEnumerable)ViewBag.Benefits, "Id", "DisplayName");
        columns.Bound(c => c.Gl)
            .Width(150);
        columns.Bound(c => c.Comments);
        columns.Bound(c => c.Active).Hidden(true);
        columns.Bound(c => c.Deleted).Hidden(true);
        columns.Command(command =>
            {
                command.Edit();
                command.Destroy();
            })
            .HtmlAttributes(new { style = "text-align: center;" })
            .Width(200);
    })
    .Editable(editable => editable.Mode(GridEditMode.InLine))
    .ToolBar(toolbar =>
    {
        toolbar.Create();
    })
    .Pageable(pager =>
    {
        pager.Refresh(true);
        pager.PageSizes([10, 20, 50]);
    })
    .Sortable()
    .Filterable()
    .NoRecords()
    .DataSource(dataSource => dataSource
        .Ajax()
        .Batch(true)
        .PageSize(10)
        .ServerOperation(true)
        .Events(events => events.Error("error_handler").RequestEnd("onRequestEnd('staticNotifications')"))
        .Model(model =>
        {
            model.Id(p => p.Id);
            model.Field(p => p.Contracts).DefaultValue(ViewBag.ContractId as List<ContractModel> ?? new List<ContractModel>());
            model.Field(p => p.BenefitValue).DefaultValue(ViewBag.BenefitId);
            model.Field(p => p.Comments);
            model.Field(p => p.LastUpdatedBy).DefaultValue(ViewData[Literals.EmailKey]);
            model.Field(p => p.Active).Editable(false).DefaultValue(Literals.Yes);
            model.Field(p => p.Deleted).Editable(false).DefaultValue(Literals.No);
        })
        .Filter(f =>
        {
            f.Add(x => x.Active).IsEqualTo(Literals.Yes);
            f.Add(x => x.Deleted).IsEqualTo(Literals.No);
        })
        .Read(read => read.Action("GetContractBenefits", "ContractBenefit").Data("forgeryToken"))
        .Create(create => create.Action("CreateContractBenefits", "ContractBenefit").Data("forgeryToken"))
        .Update(update => update.Action("UpdateContractBenefits", "ContractBenefit").Data("forgeryToken"))
        .Destroy(destroy => destroy.Action("DeleteContractBenefits", "ContractBenefit").Data("forgeryToken"))
        .Sort(sort =>
        {
            sort.Add(x => x.BenefitValue);
        })
    )
)

Here's the JavaScript

<script type="text/javascript">
    function displayContracts(data) {
        window.console.log('displayContracts()');
        return $.map(data.Contracts, function (e) { return e.DisplayName; }).join(", ");
    }
</script>

Here's my model

public class ContractBenefitViewModel
{
    public long Id { get; set; }

    public long BenefitId { get; set; }

    [Display(Name = "Benefit")]
    public string BenefitValue
    {
        get
        {
            var sb = new StringBuilder();
            if (Benefit is not null)
            {
                sb.Append(Benefit.Value);
                if (!string.IsNullOrWhiteSpace(Benefit.Gl))
                {
                    sb.Append(" (");
                    sb.Append(Benefit.Gl);
                    sb.Append(")");
                }
            }

            return sb.ToString();
        }
    }

    [Display(Name = "GL Code")]
    public string Gl => Benefit?.Gl ?? string.Empty;

    [Display(Name = "Comments")]
    [StringLength(ModelLiterals.CommentsLength)]
    [MaxLength(ModelLiterals.CommentsLength)]
    public string? Comments { get; set; }

    public string Active { get; set; } = ModelLiterals.Yes;
    public string Deleted { get; set; } = ModelLiterals.No;
    public string LastUpdatedBy { get; set; } = string.Empty;

    public BenefitModel? Benefit { get; set; } = null!;

    [UIHint("Contracts")]
    public IList<ContractModel> Contracts { get; set; } = new List<ContractModel>();
}

Here's my Editor Template (named Contracts.cshtml, in the EditorTemplates folder)

@model Lookups.ContractModel

<div style="width: 99%">
    @(Html.Kendo().MultiSelectFor(m => m)
    .DataValueField("Id")
    .DataTextField("DisplayName")
    .DownArrow()
    .AutoClose(false)
    .BindTo((IEnumerable<Lookups.ContractModel>)ViewData["contracts"])
        )
</div>

Here's the Index and Get data methods in my controller

[HttpGet]
public async Task<IActionResult> IndexAsync()
{
    Logger.LogDebug("{NameOf}()", nameof(IndexAsync));

    var contracts = await Client.GetContractsAsync();  //Client is my API client library - it fetches data from my API
    var benefits = await Client.GetBenefitsAsync();

    ViewBag.Contracts = contracts;
    ViewData["contracts"] = contracts;
    ViewBag.Benefits = benefitFinancialSupports;
    ViewBag.DefaultContractId = contracts?.FirstOrDefault()?.Id ?? -1;
    ViewBag.DefaultBenefitId = benefits?.FirstOrDefault()?.Id ?? -1;

    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> GetContractBenefitsAsync([DataSourceRequest] DataSourceRequest request)
{
    Logger.LogDebug("{NameOf}()", nameof(GetContractBenefitsAsync));
    var stopwatch = Stopwatch.StartNew();
    try
    {
        if (!ModelState.IsValid) return Json(InvalidModelStateMessage);
        var models = await Client.GetContractBenefitsAsync();
        var viewModels = models
            .Where(x => x is { Benefit: not null, Contract: not null })
            .GroupBy(x => x.BenefitId)
            .Select(g => new ContractBenefitViewModel
            {
                BenefitId = g.Key,
                Benefit = g.First().Benefit,
                Contracts = g.Select(x => x.Contract!).Distinct().ToList(),
                Id = g.First().Id,
                Comments = g.First().Comments,
                Active = g.First().Active,
                Deleted = g.First().Deleted,
                LastUpdatedBy = g.First().LastUpdatedBy
            })
            .ToList();

        return Json(await viewModels.ToDataSourceResultAsync(request));
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "{NameOf}()", nameof(GetContractBenefitsAsync));
        return Json(new { success = false, message = ex.Message });
    }
    finally
    {
        stopwatch.Stop();
        Logger.LogInformation("**** {NameOf} took [{Elapsed}]", nameof(GetContractBenefitsAsync),
            stopwatch.Elapsed);
    }
}

 

I should mention that I store the data one ContractId with one BenefitId (in a Mapping table), so when I return data via the `Client.GetContractBenefitsAsync()` call, it returns a List of 1-to-1 records, and I group them so I get a single Benefit with all Contracts that are associated with it (hence the Linq GroupBy call to build my ViewModel).  This is how I want to present it to my users, so they can select as many Contracts as they want in the UI, and behind the scenes I'll turn into a 1:1 association.  I'm just having trouble getting my data (the Contracts Multi Select) to display data.  Am I missing something or is there another way to do this?

 

 

 

 

 

 

 

 

 

 

 

Anton Mironov
Telerik team
 answered on 10 Sep 2025
1 answer
19 views

Hi Team,

Can we use 2020.1.114.440 kendo MVC dll in .net core application I am using same in .net framework 4.7.2.

 

Thanks & Regards

Amar Deep

Eyup
Telerik team
 answered on 11 Aug 2025
1 answer
15 views

The code below does not hit the read function so the details shows every detail row for each of the outer rows.(There should only be one detail row per outer row) I am following this example here: ASP.NET MVC Grid Detail Template Demo | Telerik UI for ASP.NET MVC which I use basically the same syntax for it and for an unknown reason theirs works and mine doesnt. My Javascript console gives me a 500 error which doesnt provide me with any way to resolve. Ive commented out stuff in the outer grid as I populate in the get method anyway. Can someone please look into this?

Outer grid:

<div id="RelatedAppearances-scheduling" style="margin-right:8px;border:none;padding:0;color:black; padding-bottom: 20px;">
	<div id="RelatedAppearancesTopRowInfo" >
		<div id="RelatedAppearances-Grid" style="width:99%;">
		@Html.Kendo().Grid(Model.RelatedAppearanceList).Name("RelatedAppearancesGrid").Size(ComponentSize.Small).Editable(GridEditMode.PopUp).Resizable(r => r.Columns(true)).ToolBar(r =>
		{
			r.Create().Text("Add Appearance");
		}

		).Columns(col =>	{
						   col.Bound(c => c.FileNumber).Title("File Number").Width(175);
						   col.Bound(c => c.CourtDate).Title("Court Date").Width(150);
						   col.Bound(c => c.CourtTime).Title("Court Time").Width(150);
						   col.Bound(c => c.Purpose).Width(100);
						}).Sortable().DataSource(dataSource => dataSource
						.Ajax()
			                        // .Read(r => r.Url("/Appearances/SchedulingInformation?handler=ReadEntity").Data("forgeryToken"))
					        // .Update(r => r.Url("/Appearances/SchedulingInformation?handler=UpdateEntity").Data("forgeryToken"))
						// .Destroy(r => r.Url("/Appearances/SchedulingInformation?handler=DestroyEntity").Data("forgeryToken"))
						// .Model(model =>
						// {
						// 	model.Id(p => p.AppearanceID);
						// })
						).ClientDetailTemplateId("RelatedAppearancesDetail");
							</div>
						</div>
					</div>

 

Javascript detail grid:

<script id="RelatedAppearancesDetail" type="text/kendo-tmpl">
		 	@(Html.Kendo().Grid(Model.RelatedAppearanceList).Name("innergrid_#=AppearanceID#")
			      .Columns(columns =>
		        	{
				columns.Bound(o => o.AppearanceDetails.AppearanceJudge).Title("Judge").Width(80);
				columns.Bound(o => o.AppearanceDetails.AppearanceType).Title("Appearance Type").Width(80);
				columns.Bound(o => o.AppearanceDetails.Outcome).Title("Outcome").Width(80);
				columns.Bound(o => o.AppearanceDetails.ToTH).Title("To T & H").Width(80);
				})
				.DataSource(dataSource => dataSource
				.Ajax()
				.Read(read => read.Action("ReadRelatedAppearanceDetail", "Grid", new { AppearanceID = "#=AppearanceID#" })))
				.Sortable()
				.ToClientTemplate())
</script>

 

Razor method:


        public JsonResult ReadRelatedAppearanceDetail(int AppearanceID, [DataSourceRequest] DataSourceRequest request)
        {
            var curAppearance = RelatedAppearanceList.Where(a => a.AppearanceID == AppearanceID).FirstOrDefault();
            return new JsonResult(new[] { curAppearance }.ToDataSourceResult(request, ModelState));

        }

 

Related Appearance Model:


 public class RelatedAppearanceDTO
 {
     public int AppearanceID {  get; set; }

     public string FileNumber {  get; set; }

     public string CourtDate { get; set; }

     public string CourtTime { get; set; }

     public string Purpose {  get; set; }

     public string AppearanceType {  get; set; }

     public string CalendarRemarks {  get; set; }

     public string Outcome {  get; set; }

     public string OutcomeComments {  get; set; }

     public string ToTAndH {  get; set; }

     public RelatedAppearancesDetailModel AppearanceDetails { get; set; }

 }

 

 

Related Appearance Detail Model:

  public class RelatedAppearancesDetailModel
  {
      public int AppearanceID { get; set; }
      public string AppearanceJudge { get; set; }

      public string AppearanceType { get; set;}

      public string CalendarRemarks { get; set; }

      public string Outcome { get; set; }

      public string OutcomeComment { get; set; }

      public string ToTH { get; set; }

      public string Minutes { get; set; }

      public string Disposition { get; set; }


  }


Ivaylo
Telerik team
 answered on 05 Aug 2025
2 answers
13 views

Good afternoon,

Is there a way to populate a second grid based on the outcome of the read action for the first grid?

For example, the read action for grid1 pulls a list of files from the file system in and runs checks against each file.  The list generated is returned to load grid1.  During the processing a number of errors are generated, creating a second list.  Ultimately I'd like grid2 to display that list.

It seems unnecessary to have a separate action for grid2 that is essentially running the same processing, just returning a different list.

With the two grids having AutoBind set to false I assume I can control the order the girds are populated.  Could grid2 be populated from a list stored in ViewData?

This article explains how two models can be returned to a single View, but ToDataSourceResult in the Controller can only return one model:

https://www.c-sharpcorner.com/UploadFile/ff2f08/multiple-models-in-single-view-in-mvc/

Kind regards,

Richard

Eyup
Telerik team
 answered on 21 Jul 2025
1 answer
14 views
Why do i have 3 buttons special the last Cancel ?


@(
Html.Kendo().Grid<IndexModel.CompanyFinancialVM>()
    .Name("gridCompanyFinancial")
    .Navigatable()
    .Height(590)
    .Sortable()
    .Editable(e => e.Mode(GridEditMode.InCell))
    .Scrollable()
    .ToolBar(t => { t.Save(); t.CancelEdit(); })
    .Columns(columns =>
    {
        columns.Bound(f => f.CompanyName).Title("Company").Width(150);
        columns.Bound(f => f.PeriodName).Title("Period").Width(120);
        columns.Bound(f => f.VariableName).Title("Variable").Width(150);
        columns.Bound(f => f.VariableTypeName).Title("Variable Type").Width(120);
        columns.Bound(f => f.Val).Title("Val")
            .Width(100)
            .Format("{0:n}") // Show 4 decimals and thousand separator
            .EditorTemplateName("Decimal");
        columns.Bound(f => f.ValCurr)
            .Title("Currency")
            .ClientTemplate("#= getCurrencyName(ValCurr) #")
            .EditorTemplateName("Currency")
            .Width(120);
        columns.Bound(f => f.QuantumFK)
            .Title("Quantum")
            .ClientTemplate("#= getQuantumName(QuantumFK) #")
            .EditorTemplateName("QuantumFK")
            .Width(120);
        columns.Bound(f => f.Priority).Title("Priority").Width(80);
        columns.Bound(f => f.SpecOrder).Title("Spec Order").Width(100);
        columns.Bound(f => f.Rem).Title("Remarks").EditorTemplateName("Rem");
    })
    .DataSource(ds => ds.Ajax()
        .Read(r => r.Url(Url.Content("~/CompanyFinancial/Index?handler=Read")).Data("getGridRequestData"))
        .Update(u => u.Url(Url.Content("~/CompanyFinancial/Index?handler=Update")).Data("forgeryToken"))
        .Batch(true)
        .Model(m =>
        {
            m.Id(f => f.Nr);
            m.Field(f => f.CompanyName);
            m.Field(f => f.PeriodName);
            m.Field(f => f.VariableName);
            m.Field(f => f.VariableTypeName);
            m.Field(f => f.Priority);
            m.Field(f => f.SpecOrder);
            m.Field(f => f.Val);
            m.Field(f => f.ValCurr);
            m.Field(f => f.QuantumFK);
            m.Field(f => f.Rem);
        })
        .Sort(s => s.Add(f => f.SpecOrder).Ascending())
        .PageSize(20)
    )
    .Pageable()
I have disabled all script on the page, except the simpel lookups for foreginkeys in dataset...
Anton Mironov
Telerik team
 answered on 07 Jul 2025
1 answer
25 views

Hi,

I'm using Teleik Core components, latest version in mvc application.

I have defined grid in view with name "gridMara"
In javascript i have code:

var gridMara = $("#gridMara").data("kendoGrid");

I checked in console, $("#gridMara") is initialized.
But when i use statement: 

var gridMara = $("#gridMara").data("kendoGrid");

the value of gridMara is undefined.

Please help.

Regards,
Tomaz

Eyup
Telerik team
 answered on 01 Jul 2025
2 answers
22 views

Hi all,

 

Going nuts over this problem. Should be simple, and for other technologies telerik shows solutions, but can not get it to work for razor pages .net core. 

 

What i want is:

I have a grid that opens in a popup when editting. In the editortemplate i have a childgrid showing all possible children that can be added to this record. That is working. However, i want to multiselect in this grid without having my customers to hold down  ctrl or use a textbox. Main reason: When using a textbox, you really have to click in the textbox, clicking outsisde of it won't work. So i removed the select column (the checkboxes) and just want people to click somewhere on a row to select it and be able to click on another row without the fiorst one loosing it's selected status. The only hook i can find is the onchange event. This indeed allows me to catch the slection process. However, the previously selected items are not available any more, so i oose them. 

Anyone an idea how to do this quite simple trick?

Alexander
Top achievements
Rank 1
Veteran
Iron
 answered on 28 Jun 2025
1 answer
23 views
I am trying to perform like this drag item from kendo Treelist to Drop in Kendo grid but not working in .net code using 
But when I doing drag from treelist to grid I am not event getitng debug 
Please help me asap if anyone has solution 

Razor page code:

<div style="height: 100%;">
    <!-- Parent Grid -->
    <div style="width: 60%; height: 100%; float: left;">
        <h2>{_ParentItem_}s</h2>
        @(Html.Kendo().TreeList<ParentChildModel>()
            .Name("ParentGrid")
            .Columns(columns =>
            {
                columns.Add().Field(p => p.Id).Width(80).Hidden(false);
                columns.Add().Field(p => p.ItemId).Width(80).Hidden(true);
                columns.Add().Field(c => c.Name).Title("Name").Width(140).Template("#= getIndentedName(Name, Id) #");
                columns.Add().Field(e => e.AssetCode).Title("{_AssetCode_}").Width(60);
                columns.Add().Field(e => e.Weight).Title("Weight").Format("{0:n3}").Width(40).Hidden(false);
                columns.Add().Field(e => e.Dimension).Title("Dimension").Width(100).Hidden(false);
                columns.Add().Command(c => 
                { 
                    c.Edit().Text("Edit").ClassName("k-grid-edit");
                    c.Destroy().Text("Delete").ClassName("k-grid-delete");
                }).Title("Actions").Width(80);
            })
            .Editable(editable => editable.Move(move => move.Reorderable(true)).Mode(TreeListEditMode.PopUp)
                .TemplateName("ParentPopupEditor"))
            .Toolbar(toolbar =>
            {
                toolbar.Create().Text("Add New {_ParentItem_}");
                toolbar.Custom().Template(
                    "<div>" +
                    "<input id='toolbarComboBox' style='width: 300px;' />" +
                    "</div>"
                );
                toolbar.Search();
            })
            .DataSource(dataSource => dataSource
                .Read(read => read.Action("GetParentAndChildItems", "ParentChild").Data("parentSearchData"))
                .Create(update => update.Action("AddNewRecord", "ParentChild").Type(HttpVerbs.Post))
                .Update(u => u.Action("UpdateRecord", "ParentChild").Type(HttpVerbs.Post))  //.Data("saveFormData"))
                .Destroy(update => update.Action("DeleteRecord", "ParentChild"))
                .ServerOperation(false)
                .PageSize(20)
                .Model(m =>
                {
                    m.Id(f => f.Id);
                    m.ParentId(f => f.ParentId);
                    m.Expanded(true);
                    m.Field(f => f.ItemId);
                    m.Field(f => f.AssetName);
                    m.Field(f => f.AssetCode);
                    m.Field(f => f.Weight);
                    m.Field(f => f.Dimension);
                })
            )
            .Pageable(x => x.PageSizes(new int[] { 20, 50, 100, 200, 500 }).Refresh(true).Input(true))
            .Sortable()
            .Selectable()
            .Events(e => e.DataBound("dataBound").Save("onEditorDataSave").DragEnd("onDragEnd"))//.DragStart("onDragStart").DragEnd("onDragEnd")
        )
    </div>

    <!-- Assignable Assets -->
    <div style="width: 40%; height: 100%; float: right;">
        <h2>Assignable {_Asset_}s</h2>
        @(Html.Kendo().Grid<ItemDto>()
            .Name("AssetGrid")
            .HtmlAttributes(new { style = "height:100%; width:100%;" })
            .Columns(columns =>
            {
                //columns.Template(@<text> </text>).Draggable(true).Width(30);
                columns.Template("").Draggable(true);
                columns.Bound(a => a.Id).Title("Id").Width(60).HtmlAttributes(new { @class = "idColStyle" });
                columns.Bound(a => a.Title).Title("{_AssetName_}").Width(150);
                columns.Bound(a => a.ItemTypeName).Title("{_AssetType_}").Width(100);
                columns.Bound(a => a.LocationName).Title("Destination {_Location_}").Width(110);
            })
            .ToolBar(toolbar =>
            {
                toolbar.Custom().ClientTemplate(Html.Kendo().Template().AddComponent(c => c
                    .TextBox().Name("toolbarTextBox")
                    .Placeholder("Filter by {_AssetName_}/{_AssetType_}...")
                    .HtmlAttributes(new { style = "float: right; width: 300px;" })
                    .Events(ev => ev.Change("toolbarTextBoxChanged"))
                ));
                toolbar.Search();
            })
            .DataSource(dataSource => dataSource
                .Ajax()
                .PageSize(20)
                .ServerOperation(false)
                .Model(m => m.Id("Id")) //Ensure that the Model identifier ("Id") is defined.
                .Read(read => read.Action("GetAssignableAssets", "ParentChild").Data("childrenSearchData"))
            )
            .Pageable()
            .Sortable()
            .Selectable()
            )
    </div>
</div>


JS Code:

$(document).ready(function () {
    var treeList = $("#ParentGrid").data("kendoTreeList");
    if (treeList) {
        treeList.dataSource.bind("requestEnd", function (e) {
            if (e.response) {
                if (e.type === "create") {
                    console.log("call requestEnd type: create");
                    treeList.dataSource.read(); // Refresh immediately
                } else if (e.type === "update") {
                    console.log("call requestEnd type: update");
                    setTimeout(function () {
                        treeList.dataSource.read(); // Refresh after 1 second
                    }, 200); // 1000 milliseconds = 1 second
                }
            }
        });
    }
});

function onDragEnd(e) {
    var draggedItem = e.source;         // The dragged item
    var newParent = e.destination;      // The new parent (if changed)
    var newOrder = e.position;  // The new order in the parent

    // Prepare data for backend
    var updateData = {
        sourceId: draggedItem.id,
        destId: newParent ? newParent.id : null,
        destParentId: newParent ? newParent.id : null,
        //sourceItemId = draggedItem.ItemId,
        //destItemId = newParent ? newParent.ItemId : null,
        order: newOrder
    };

    // Make an AJAX call to update the hierarchy/order in the backend
    $.ajax({
        url: "/ParentChild/Reorder", //"/ParentChild/Reorder",
        type: "POST",
        data: {           //{destId: updateData.destId, sourceId: updateData.sourceId, order: updateData.order},
            destId: e.destination.Id,
            sourceId: e.source.Id,
            destParentItemId: e.destination.ParentItemId,
            order: e.position
        },
        //contentType: "application/json",
        success: function () {
            // Optionally refresh the TreeList
            $("#ParentGrid").data("kendoTreeList").dataSource.read();
        },
        error: function () {
            $("#ParentGrid").data("kendoTreeList").dataSource.read();
            alert("Reorder failed (Can't make child asset as parent)");
        }
    });
    console.log("Drag operation ended!", e);
}

// Initialize ParentGrid rows as drop targets
window.initializeDropTargets = function () {
    var draggedItem = null;

    // Make Rows Draggable
    $("#AssetGrid").on("mousedown", "tr", function () {
        var grid = $("#AssetGrid").data("kendoGrid");
        var dataItem = grid.dataItem($(this));
        draggedItem = dataItem; // Track the dragged item's data
        console.log("AssetGrid -> mousedown", draggedItem);
    });

    // Track dragged item from ParentGrid
    $("#ParentGrid").on("mousedown", "tr", function () {
        var parentGrid = $("#ParentGrid").data("kendoTreeList");
        draggedItem = parentGrid.dataItem($(this));
        console.log("ParentGrid -> mousedown", draggedItem);
    });

    $("#ParentGrid").kendoDropTargetArea({
        filter: "tbody tr",
        group: "assetGroup", // Match the draggable group
        drop: function (e) {
            var parentGrid = $("#ParentGrid").data("kendoTreeList"); // Get the Kendo Grid instance
            var dropTargetRow = $(e.dropTarget);    //.closest("#ParentGrid tr.k-table-row.k-master-row"); // The row where the item was dropped
            var targetItem = parentGrid.dataItem(dropTargetRow); // Target row data

            console.log("Dragged Item:", draggedItem.Id);
            console.log("Drop Target:", e.dropTarget);
            console.log("Drop Target Row:", dropTargetRow);
            console.log("Target Item:", targetItem.Id);

            if (targetItem && draggedItem) {
                //alert("Item '" + draggedItem.Title + "' dropped on Parent '" + targetItem.Name + "'");

                // Add AJAX call here to save assignment in the database
                $.ajax({
                    url: "/ParentChild/AssignAsset",
                    method: "POST",
                    data: { parentId: targetItem.Id, itemId: draggedItem.Id, parentItemId: targetItem.ParentItemId },
                    success: function (response) {
                        parentGrid.dataSource.read();
                        $("#AssetGrid").data("kendoGrid").dataSource.read();
                        console.log("AssignAsset ended from kendoDropTargetArea -> drop");
                        //parentGrid.refresh();
                        //alert("Assignment successful!");
                    },
                    error: function () {
                        alert("Error while assigning asset (Can't assign children to child asset).");
                    }
                });
            }
        },
        dragend: function (e) {
            var draggedItem = e.source; // The dragged item
            var newParent = e.destination; // The new parent (if changed)
            var newOrder = e.destinationIndex; // The new order in the parent

            // Prepare data for backend
            var updateData = {
                id: draggedItem.id,
                parentId: newParent ? newParent.id : null,
                order: newOrder
            };

            // Make an AJAX call to update the hierarchy/order in the backend
            $.ajax({
                url: "/ParentChild/Reorder",
                type: "POST",
                data: JSON.stringify(updateData),
                contentType: "application/json",
                success: function () {
                    // Optionally refresh the TreeList
                    $("#TreeList").data("kendoTreeList").dataSource.read();
                    console.log("AssignAsset ended from kendoDropTargetArea -> dragend -> Reorder");
                },
                error: function () {
                    alert("Reorder failed");
                }
            });
        }
    });

    $("#AssetGrid").kendoDropTarget({
        filter: "tbody tr",
        group: "gridGroup", // Match the draggable group
        drop: function (e) {
            var parentGrid = $("#ParentGrid").data("kendoTreeList"); // Get the Kendo Grid instance
            var dropTargetRow = $(e.dropTarget);    //.closest("#ParentGrid tr.k-table-row.k-master-row"); // The row where the item was dropped
            var targetItem = parentGrid.dataItem(dropTargetRow); // Target row data

            console.log("Dragged Item:", draggedItem.Id);
            console.log("Drop Target:", e.dropTarget);
            console.log("Drop Target Row:", dropTargetRow);
            console.log("Target Item:", targetItem.Id);

            if (targetItem && draggedItem) {
                //alert("Item '" + draggedItem.Title + "' dropped on Parent '" + targetItem.Name + "'");

                // Add AJAX call here to save assignment in the database
                $.ajax({
                    url: "/ParentChild/UnAssignAsset",
                    method: "POST",
                    data: { parentId: targetItem.Id, itemId: draggedItem.Id, parentItemId: targetItem.ParentItemId },
                    success: function (response) {
                        parentGrid.dataSource.read();
                        $("#AssetGrid").data("kendoGrid").dataSource.read();
                        console.log("AssignAsset ended from kendoDropTargetArea -> drop");
                        //parentGrid.refresh();
                        //alert("Assignment successful!");
                    },
                    error: function () {
                        alert("Error while assigning asset (Can't assign children to child asset).");
                    }
                });
            }
        }
    });
};


$(document).ready(function () {
    // Make rows in the AssetGrid draggable
    $("#AssetGrid").kendoDraggable({
        filter: "tbody > tr", // Target rows in the grid
        hint: function (element) {
            return $("<div class='k-card k-card-type'><b>" + $(element).find("td:nth-child(2)").text() + "</b></div>");
        },
        group: "assetGroup"
    });

    var treeList = $("#ParentGrid").data("kendoTreeList");
    // Configure drag-and-drop from TreeList to Grid
    treeList.wrapper.kendoDraggable({
        filter: "tr",
        hint: function (element) {
            var item = treeList.dataItem(element);
            console.log("treeList.wrapper.kendoDraggable -> ", item);
            return element;
        },
        group: "gridGroup"         
    });
    window.initializeDropTargets();
});

Ivaylo
Telerik team
 answered on 16 Jun 2025
Narrow your results
Selected tags
Tags
+? more
Top users last month
Jay
Top achievements
Rank 3
Bronze
Iron
Iron
yw
Top achievements
Rank 2
Iron
Iron
Stefan
Top achievements
Rank 2
Iron
Iron
Iron
Kao Hung
Top achievements
Rank 1
Iron
Bohdan
Top achievements
Rank 2
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Top users last month
Jay
Top achievements
Rank 3
Bronze
Iron
Iron
yw
Top achievements
Rank 2
Iron
Iron
Stefan
Top achievements
Rank 2
Iron
Iron
Iron
Kao Hung
Top achievements
Rank 1
Iron
Bohdan
Top achievements
Rank 2
Iron
Iron
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?