Arvind Chourasiya
Arvind Chourasiya

Reputation: 17422

Dropdown is not showing up in Kendo grid inline editing mode

I would like to show a Kendo dropdown in a Kendo grid cell when user click on it to Edit.

This is my code index.cshtml file grid code

@(Html.Kendo().Grid<SvwDesignMaterialSystemAttributeDto>()
        .Name("DesignMaterialSystemAttribute")
        .Columns(columns =>
        {
            columns.Bound(m => m.MaxAcceptableValue).Hidden();

            columns.Bound(m => m.MaxAcceptableText).ClientTemplate(
                "# if (MaxAcceptableText) { #"
                    + "#=formatValueInUnit(MaxAcceptableText, UnitTypeCode)#" + " "
                + "# } #").Title("Max").Width(100);

        })
    .ToolBar(toolbar =>
    {
        toolbar.Save();
    })
    .Editable(editable => editable.Mode(GridEditMode.InCell)).Pageable().Sortable()
    .Events(e => e.Edit("onEdit"))

    .Events(events => events.DataBound("function"))
    .DataSource(dataSource => dataSource
        .Ajax()
        .Batch(true)
        .ServerOperation(true)
        .Model(model =>
        {
            model.Id(m => m.DesignMaterialSystemAttributeId);
            .....
        })
        .Events(events => events.DataBound(
                    @<text>
                    function (e) {
                        if ($('#DesignMaterialSystemAttribute').data('kendoGrid').dataSource.data().length == 0) {
                            $("#DesignMaterialSystemAttribute").find('tbody')
                                .append('<tr class="kendo-data-row"><td colspan="6" style="text-align: center"><b>No Results Found!</b></td></tr>');
                        }
                    }
                    </text>
        ))
        .AutoBind(true)
)

This is edit click event inside tag the same file index.cshtml

<script id="myscript" type="text/javascript">

function onEdit(e)
{ 
    var field = e.sender.columns[e.container.index()].field;
    if (e.model.UnitTypeCode === "UNIT_LOOKUP_COMBOBOX") {

       var input = $("<input id='products'/>")    

       $(document).ready(function() {
            $("#products").kendoDropDownList({
                dataTextField: "ProductName",
                dataValueField: "ProductID",
                dataSource: {
                    transport: {
                        read: {
                            dataType: "jsonp",
                            url: "https://demos.telerik.com/kendo-ui/service/Products",
                        }
                    }
                }
            });
        });             

        var temp = $("#products");
        e.container.append(input);
        input.focus();

        temp.remove();
        kendo.bind(e.container, e.model);
    }
}

</script>    

I have taken above code kendo Kendo dropdown example. When I click on cell it just shows Textbox (input) on the grid cell in edit mode not dropdown.

enter image description here

This is how I want to do dropdown in grid inline editing.

In the first link there are few kendo styles being used, I added those and got warning in console regarding kendo subscription. Seems those styles are new release 2023.1.117. I dont want update kendo subscription. I just want to go with current subscription.

How can I add Kendo dropdown to grid inline editing mode ?

Edit 1:

Here in the second if condition I need dropdown, by following 2nd approach how can I do it

 <script id="myscript" type="text/javascript">
    
    function onEdit(e)
    {
        var field = e.sender.columns[e.container.index()].field;
        if (e.model.UnitTypeCode === "Integer") {
          //other editor control
        }
        if (e.model.UnitTypeCode === "UNIT_LOOKUP_COMBOBOX") {
        
          //here I need dropdown editor
        
        }
        if (e.model.UnitTypeCode === "Float") {
        //other editor control
        }
    }
</script>

Edit 2 I am able to do it with HTML dropdown but not kendo

 if (e.model.UnitTypeCode === "UNIT_LOOKUP_COMBOBOX") {

                var dataItem = $("#DesignMaterialSystemAttribute").data("kendoGrid").dataSource.get(e.model.DesignMaterialSystemAttributeId);
                var unitCodeTypeRow = dataItem.UnitLookupCodeType;
                var maxAcceptableValueRow = dataItem.MaxAcceptableText;

                var input = $("<select style='outline:none; width:100%' name='MaxAcceptableName' data-value-update='MaxAcceptableText' data-bind='text: MaxAcceptableText' id='MaxAcceptableId'></select > ")
                var dataDdl = null;
                var maxAcceptableText = null;
                var maxAcceptableValue = null;

                var grid = $("#DesignMaterialSystemAttribute").data("kendoGrid");
                var data = grid.dataSource.data();
                var gridRowTr = grid.dataItem($(e.container).closest("tr"));
                var currentRowIndex = data.indexOf(gridRowTr);

                jQuery(document).ready(function () {

                    var lookUpCodeUrl = '@Url.Action("GetCodesList", "LookupCode")';

                    $.ajax({
                        type: "POST",
                        url: lookUpCodeUrl,
                    })
                        .success(function (responseData) {

                            dataDdl = responseData;
                            var selectedCellItemValue = data[currentRowIndex].MaxAcceptableValue;
                            var cellItemIndex = responseData.findIndex(x => x.CodeLovId == selectedCellItemValue);
                            if (cellItemIndex !== -1) {
                                responseData.unshift(...responseData.splice(cellItemIndex, 1));
                            }

                            $("#MaxAcceptableId").empty();
                            $.each(responseData, function (i, v) {
                                $("#MaxAcceptableId").append($('<option/>', {
                                    value: v.CodeLovId,
                                    text: v.Description
                                }));
                            })
                        })

                }(jQuery));

                $('tr').off('td').off('change').on('change', '#MaxAcceptableId', function () {
                    maxAcceptableText = $(this).find('option:selected').text();
                    maxAcceptableValue = $(this).find('option:selected').val();
                    var oldModel = e.sender.dataSource._pristineForModel(e.model);
                    if (maxAcceptableValue != "" & maxAcceptableValue != undefined) {
                        data[currentRowIndex].set("MaxAcceptableValue", maxAcceptableValue);
                        if (data[currentRowIndex].MaxAcceptableValue == oldModel.MaxAcceptableValue) {
                            e.model.dirty = false;
                            e.container.removeClass("k-dirty-cell");
                        }
                    }
                    if (maxAcceptableText != "" & maxAcceptableText != undefined) {
                        data[currentRowIndex].set("MaxAcceptableText", maxAcceptableText);
                        if (data[currentRowIndex].MaxAcceptableText == oldModel.MaxAcceptableText) {
                            e.model.dirty = false;
                            e.container.removeClass("k-dirty-cell");
                        }
                    }
                });

                

                $("#DesignMaterialSystemAttribute").bind("change", function (args) {

                    var selectedCellItemValue = data[currentRowIndex].MaxAcceptableValue;
                    var cellItemIndex = dataDdl.findIndex(x => x.CodeLovId == selectedCellItemValue);
                    if (cellItemIndex !== -1) {
                        dataDdl.unshift(...dataDdl.splice(cellItemIndex, 1));
                    }

                    $("#MaxAcceptableId").empty();
                    $.each(dataDdl, function (i, v) {
                        $("#MaxAcceptableId").append($('<option/>', {
                            value: v.CodeLovId,
                            text: v.Description
                        }));
                    })
                });

                var temp = $("#MaxAcceptableText");
                e.container.append(input);
                input.focus();

                temp.remove();
                kendo.bind(e.container, e.model);
            }

Upvotes: 1

Views: 1048

Answers (1)

Aleksandar
Aleksandar

Reputation: 1359

In regards to the Editors and editor templates there is a slight difference in how the Grid works depending on whether the HTML wrappers or Kendo UI is used.

When using the HTML wrappers (UI for ASP.NET Core or UI for ASP.NET MVC) the editors used are those located in the ~/Viwes/Shared/EditorTemplates folder. Those templates are serialized and passed as a columns.editor as a string and this way define the Editor when the cell enters edit mode. You can specify the editor to be used via the EditorTemplateName configuration.

Initializing the Grid using Kendo UI you can set the editor to the desired widget (or use a function that returns the editor) and use editorOptions to provide additional configuration options.

Now, to create a custom editor when you us HTML helpers, for example a DropDownList for a column, rather than a TextBox follow the example on custom editing and the docs. Basically you have to:

  1. Decorate the model property with [UIHint] attribute:

     [UIHint("ClientCategory")]
     public CategoryViewModel Category {get;set;}
    
  2. Create the custom editor and place it in ~/Views/Shared/EditorTemplates folder

    @model Kendo.Mvc.Examples.Models.CategoryViewModel
    
    @(Html.Kendo().DropDownListFor(m => m)
         .DataValueField("CategoryID")
         .DataTextField("CategoryName")
         .BindTo((System.Collections.IEnumerable)ViewData["categories"]) //You can also bind to a DataSource, it's not mandatory to use local data
    )
    
  3. Add the column definition:

    columns.Bound(p => p.Category).ClientTemplate("#=Category.CategoryName#").Width(180);
    

    The ClientTemplate configuration is used to show a property of the CategoryViewModel, as otherwise you will see [Object object] on the Grid

Now, if for some reason you do not want to use an EditorTemplate from the EditorTemplates folder and desire to use a JS function to initialize an editor for a column you can define a function that returns the editor and on document.ready use the setOptions method of the Grid to override the options and set the function to the columns.editor configuration - example

@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.ProductViewModel>()
.Name("grid")
.AutoBind(false)
.Columns(columns => {
    columns.Bound(p => p.ProductName);
    ...
    columns.Command(command => command.Destroy()).Width(150);
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
...
)

<script type="text/javascript">
 function productNameEditor(container, options) {
        $('<input required name="' + options.field + '"/>')
            .appendTo(container)
            .kendoDropDownList({
                autoBind:false,
                dataTextField: "ProductName",
                dataValueField: "ProductName",
                dataSource: {
                    transport: {
                        read: {
                            dataType: "json",
                            url: "@Url.Action("RemoteDataSource_GetProducts", "DropDownList")",
                        }
                    }
                }
            });
    }
    $("document").ready(function(){
        var grid = $("#grid").getKendoGrid();
        var options = grid.options;
        options.columns[0].editor = productNameEditor;
        grid.setOptions(options);
        grid.dataSource.read();
    })
</script>

Edit:

To extend on the second approach - using a conditional editor for each column is also possible and you can call a function which based on the conditions you have will return the desired editor.

Iterate all the columns and assign the editor to the function returning the desired editor. options.field represents the field for which the editor will be generated when you click on a cell, and you can access the model that is being edited via options.model :

   $("document").ready(function(){
        var grid = $("#grid").getKendoGrid();
        var options = grid.options;
        options.columns.forEach((itm)=>itm.editor = chooseEditor)
        grid.setOptions(options);
        grid.dataSource.read();
      })

   function chooseEditor(container, options) {
    switch (options.field) {
        case "ProductName":
            if(options.model.ProductID % 2 == 0){
                dropdownEditor(container, options);
            } else {
                textEditor(container, options);
            }
            break;
        case "UnitPrice":
            currencyEditor(container, options);
            break;
        case "UnitsInStock":
            numericEditor(container, options);
            break;
        case "OrderDate":
            dateEditor(container, options);
            break;
        case "Discontinued":
            booleanEditor(container, options);
            break;
        default:
            textEditor(container, options);
            break;
     }
   }

The functions will return the respective editor, for example:

  function textEditor(container, options) {
    $('<input type="text" name="' + options.field + '"/>')
    .appendTo(container)
    .kendoTextBox()  
  }

  function numericEditor(container, options) {
    $('<input name="' + options.field + '"/>')
    .appendTo(container)
    .kendoNumericTextBox()
}

So based on the above, in this updated example clicking on cells in the ProductName column will render either a DropDownList or a TextBox.

Upvotes: 1

Related Questions