Drag and drop between 2 grids, model in create method is empty

0 Answers 174 Views
Grid
Christine
Top achievements
Rank 2
Iron
Christine asked on 10 May 2021, 05:55 PM

Hi,

I am trying to Drag & Drop a data item from grid1 to grid2. The row should not be deleted in grid1.

After dropping the dataitem to grid2 I want to

  • call the Create method on the controller
  • check, if the operation is allowed  (there is a role / right model behind)
  • update my model, if allowed
  • rollback the change on the grid, if not allowed

I use TileLayout and kendoDraggable / kendoDropTarget.

On the frontend everything looks fine. But in the Create Method of the controller, I receive an empty model.

Any ideas, what I am doing wrong?

The model:

public class SignatureModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Img { get; set; }
    }

 

The controller:

public class LayerDefController : Controller
    {

        public ActionResult AllObjectTypes_Read([DataSourceRequest] DataSourceRequest request)
        {
            return Json(GetAllObjectTypes().ToDataSourceResult(request));
        }

        public ActionResult MyObjectTypes_Read([DataSourceRequest] DataSourceRequest request)
        {
            var all = GetAllObjectTypes();
            var my = all.Where(o => o.Id < 5);
            return Json(my.ToDataSourceResult(request));
        }

        public ActionResult MyObjectTypes_Update([DataSourceRequest] DataSourceRequest request)
        {
            var all = GetAllObjectTypes();
            var my = all.Where(o => o.Id < 5);
            return Json(my.ToDataSourceResult(request));
        }

         [HttpPost]
        public IActionResult MyObjectTypes_Create([DataSourceRequest] DataSourceRequest request, SignatureModel model)
        {
            // update model
            //_all.Add(model);
            return new StatusCodeResult(200);
        }

private IEnumerable<SignatureModel> GetAllObjectTypes()
        {
            var result = Enumerable.Range(0, 50).Select(i => new SignatureModel
            {
                Id = i,
                Name = "Signature " + i,

            });

            return result.ToList();
        }

   }

}

 

The cshtml:

<script id="sig-img-template" type="text/x-kendo-template">
    <div class='sig-img'
         style='background-image: url(@Url.Content("~/images/#: Id #.svg"));'></div>
    <div class='sig-title'>#: Name #</div>
</script>

<script id="my-sig-template" type="text/x-kendo-tmpl">
    <div class="signature">
        <img src="@Url.Content("~/images/")#:Id#.svg" alt="#:Name# image" />
        <h3>#:Name#</h3>
        <p>#:kendo.toString(Id, "c")#</p>
    </div>
</script>

<!-- container templates -->
<script id="all-sigtypes-template" type="text/x-kendo-template">
    <div id="all-sigs-container" style="height:100%;width:100%;">
        @(Html.Kendo().Grid<collact.admin.web.Models.SignatureModel>()
        .Name("AllSigsGrid")
        .Columns(columns => {
            columns.Bound(s => s.Id).Width(50).Title("ID");
            columns.Bound(s => s.Name).Width(200);
            columns.Bound(s => s.Id).ClientTemplateId("sig-img-template").Title("img");
        })
        .HtmlAttributes(new { style = "height: 90%;" })
        .Navigatable()
        .Sortable()
        .Groupable()
        .Filterable()
        .ToolBar(t => t.Search())
        .Scrollable()
        .Selectable(selectable => selectable
            .Mode(GridSelectionMode.Multiple))
        .PersistSelection(true)
        .Navigatable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .Model(model => model.Id(p => p.Id))
            .Read(read => read.Action("AllObjectTypes_Read", "LayerDef"))
         )
        .ToClientTemplate()
    )
    </div>
</script>

<script id="my-sigtypes-template" type="text/x-kendo-template">
    <div id="my-sigs-container" style="height:100%;width:100%;">
    @(Html.Kendo().Grid<collact.admin.web.Models.SignatureModel>()
        .Name("MySigsGrid")
        .Columns(columns => {
            columns.Bound(s => s.Id).ClientTemplateId("my-sig-template").Title("img");
    })
         .HtmlAttributes(new { style = "height: 90%;" })
         .DataSource(dataSource => dataSource
         .Ajax()
         .Model(m => m.Id(s => s.Id))
         .Read(read => read.Action("MyObjectTypes_Read", "LayerDef"))
         .Create(c => c.Action("MyObjectTypes_Create", "LayerDef"))
         .Update(update => update.Action("MyObjectTypes_Update", "LayerDef"))
         .PageSize(15)
        )
        .Pageable()
        .Scrollable()
        .ToClientTemplate()
    )

    </div>
</script>

<div id="tilelayout"></div>
@(Html.Kendo().TileLayout()
        .Name("tilelayout")
        .Columns(5)
        .RowsHeight("500px")
        .ColumnsWidth("285px")
        .Containers(c => {
            c.Add().Header(h => h.Text("Alle verfügbaren Objekttypen")).BodyTemplateId("all-sigtypes-template").ColSpan(2).RowSpan(2);
            c.Add().Header(h => h.Text("Ausgewählte Objekttypen")).BodyTemplateId("my-sigtypes-template").ColSpan(1).RowSpan(2);
        })
        .Resizable()
    )


<script>
    $(document).ready(function () {
        var grid1 = $("#AllSigsGrid").data("kendoGrid");
        var grid2 = $("#MySigsGrid").data("kendoGrid");
        var dataSource1 = grid1.dataSource;
        var dataSource2 = grid2.dataSource;

        $(grid1.element).kendoDraggable({
            filter: "tr",
            hint: function (e) {
                var item = $('<div class="k-grid k-widget" style="background-color: DarkOrange; color: black;"><table><tbody><tr>' + e.html() + '</tr></tbody></table></div>');
                return item;
            },
            group: "gridGroup1",
        });

        try {

            grid2.wrapper.kendoDropTarget({
                drop: function (e) {
                    var dataItem = dataSource1.getByUid(e.draggable.currentTarget.data("uid"));

                    console.log("dataItem: " + dataItem + ", ID = " + dataItem.get("Id"));
                    grid2.dataSource.add(dataItem);

                    $.each(grid2.dataSource.data(), function () {
                        console.log(this.Id);
                    })

                    grid2.dataSource.sync();
                    grid2.refresh();
                },
                group: "gridGroup1",
            });
        } catch (err) {
            console.log(err);
        }
    });
</script>

<style>
    .sig-img {
        display: inline-block;
        width: 40px;
        height: 40px;
        background-size: 40px 44px;
        background-position: center center;
        vertical-align: middle;
        line-height: 41px;
        box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2);
    }

    .sig-title {
        display: inline-block;
        vertical-align: middle;
        line-height: 41px;
        padding-left: 10px;
    }


    .signature {
        float: left;
        position: relative;
        width: 111px;
        height: 60px;
        margin: 0 5px;
        padding: 0;
    }

    .signature img {
        width: 50px;
        height: 50px;
    }

    .signature h3 {
        margin: 0;
        padding: 3px 5px 0 0;
        max-width: 96px;
        overflow: hidden;
        line-height: 1.1em;
        font-size: .9em;
        font-weight: normal;
        text-transform: uppercase;
        color: #999;
    }

    .signature p {
        visibility: hidden;
    }

    .signature:hover p {
        visibility: visible;
        position: absolute;
        width: 110px;
        height: 110px;
        top: 0;
        margin: 0;
        padding: 0;
        line-height: 110px;
        vertical-align: middle;
        text-align: center;
        color: #fff;
        background-color: rgba(0,0,0,0.75);
        transition: background .2s linear, color .2s linear;
        -moz-transition: background .2s linear, color .2s linear;
        -webkit-transition: background .2s linear, color .2s linear;
        -o-transition: background .2s linear, color .2s linear;
    }

    .placeholder {
        border: 1px dashed #ccc;
        background-color: #fff;
        color: #333;
    }

    .hint {
        opacity: 0.4;
    }
</style>

 

The images are just numbered svg-files.

Can anybody help, please?

Best regards

Christine

Aleksandar
Telerik team
commented on 13 May 2021, 11:29 AM

Hi Christine,

Reviewing the code I do not se anything obvious that might be causing the issue. Can you verify that the form data submitted to the endpoint contains the necessary model data? Also have you checked for any errors on the developer's console? 

Christine
Top achievements
Rank 2
Iron
commented on 13 May 2021, 12:37 PM

Hi Aleksandar

thank you for your answer.

The console shows no errors. I didn't manage to find out, why the model is empty.

As the role/right model behind it is quite complicated I changed the drop-function in that way:
- find out id of drop target
- call a method in the controller via ajax with ids of dragged item and drop target
- check if change is allowed for this combination of items
- change model if allowed
- return true or false
- reread the dataSource if the model was changed
- display information to user

BTW: Is a placeholder possible for kendoDropTarget (similar to sortable) ?

Best regards
Christine
Aleksandar
Telerik team
commented on 18 May 2021, 07:39 AM

It is still not clear to me whether the model is submitted to the remote endpoint when the dataSource fires a request to the endpoint handling creation of items. You can verify this in the network tab. Generally speaking in order for an item to be submitted to the create endpoint the id field will be used to determine if a model instance is new or existing. If the value of the specified field is equal to the default value that is specified through the fields configuration, the model is considered new. Is it possible that the items dropped to the grid are submitted to the update endpoint, in case they already have an id different than the default?

As for the placeholder configuration for the kendoDropTarget - such configuration is not available. Refer to the API section here for available configuration options:
https://docs.telerik.com/kendo-ui/api/javascript/ui/droptarget

https://docs.telerik.com/kendo-ui/api/javascript/ui/droptargetarea

https://docs.telerik.com/kendo-ui/controls/interactivity/draganddrop/overview

 

Christine
Top achievements
Rank 2
Iron
commented on 25 May 2021, 01:18 PM

I tested a little bit more.
If I have a dataitem with id = 0 in the grid I am dropping to, the create method is called with the dataitem belonging to id 0, but not with the dragged item.
If I have no dataitem with id = 0 in the datasource of the grid, the method is not called.

Thanks for the information about the placeholder.
Aleksandar
Telerik team
commented on 28 May 2021, 07:42 AM

In this case if you need to send the dropped items to the create endpoint I can suggest setting the ID of the dataItem, that is going to be added to the second Grid, to 0. 

drop: function (e) {
    var dataItem = dataSource1.getByUid(e.draggable.currentTarget.data("uid"));

    var newItem = dataItem;
    newItem.Id = 0;
    grid2.dataSource.add(newItem);

    grid2.dataSource.sync();
    grid2.refresh();
},

No answers yet. Maybe you can help?

Tags
Grid
Asked by
Christine
Top achievements
Rank 2
Iron
Share this question
or