Foreignkey field get '[object object]' value when editRow with original field value is null.

16 posts, 0 answers
  1. MC
    MC avatar
    1 posts
    Member since:
    Dec 2012

    Posted 10 Jan 2013 Link to this post

    Hi,

    I have an issue that I use a dropdown list for my foreignkey field like demo : http://demos.kendoui.com/web/grid/foreignkeycolumn.html

    The difference is that the foreignkey field in my model which can be null some time if it is not related to anyone else. Then the issue for me is when I try to editRow with this foreignkey field's original value is null,  and I want to change to another value, this field will always get the value '[object object]'. I don't know why.

    See the floor field in the following code:

    <script>
        $(document).ready(function() {
            var template = kendo.template($("#detail_template").html());

            function show_menu_details(menuObj) {
                var tg = $("#details");
                tg.fadeOut(function(){
                    tg.html(template(menuObj));
                    tw = tg.find(".k-window");
                    
                    
                    tw.css({width:tg.innerWidth()-30, height:tg.innerHeight()-55, "margin-top": 20, "margin-left":15});
                });
                tg.fadeIn();
            }
            
            $("#horizontal").kendoSplitter({
                panes: [{collapsible: true, size: "180px"},
                        { collapsible: true} ],
                height: 690
            });
            
            function onChange(e){
                e.preventDefault();
                selectedObj = this.dataSource.getByUid(this.select().data('uid'))
                //console.log(selectedObj);//(this.dataSource.data());
                show_menu_details(selectedObj);
            }
            
            var statuses = [
                {value:'', text:'--'},
                {value:'Available', text:'Available'},
                {value:'Locked', text:'Locked'},
                {value:'Reserved', text:'Reserved'},
                {value:'Occupied', text:'Occupied'}];
            var floors = new Array();
            floors[0]={text:'--',value:''};
            _DS_Floor.fetch(function(data){
                $.each(data.items,function(index,obj){
                    floors[index+1] = {text: obj.name, value: obj.id};
                });
                
                var grid = $("#list").kendoGrid({
                    dataSource: _DS_Room,
                    selectable: "row",
                    filterable: true,
                    columnMenu: true,
                    pageable: {refresh:true},
                    editable: {mode:"popup",confirmation:"Sure to delete?"},
                    height: 688,
                    scrollable: {
                        virtual: true
                    },
                    sortable: true,
                    toolbar: kendo.template($("#toolbar_template").html()), 
                    columns: [//{field:'id',title:' ',width:40,template: '<input type="checkbox" id="#= id #" />'},
                              {field:'name',title:'Name'},
                              {field:'floor',title:'Floor',values:floors},
                              {field:'position',title:'Position'},
                              {field:'status',title:'Status',width:80,values:statuses}],//_Columns_Menu,//{ command: ['edit','destroy'], title: "", width: "200px" }
                    //change: onChange
                });
                
                grid.find("#btn-add").click(function(e){
                    e.preventDefault();
                    grid.data("kendoGrid").addRow();
                });
                
                grid.find("#btn-save").click(function(e){
                    e.preventDefault();
                    grid.data("kendoGrid").saveChanges();//editRow(grid.data("kendoGrid").select());
                });
                
                grid.find("#btn-remove").click(function(e){
                    e.preventDefault();
                    grid.data("kendoGrid").removeRow(grid.data("kendoGrid").select());
                });
                
                grid.find("#btn-cancel").click(function(e){
                    e.preventDefault();
                    grid.data("kendoGrid").cancelChanges();//removeRow(grid.data("kendoGrid").select());
                });
                
            });
            
        });
    </script>

    Thanks.
    --
  2. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 14 Jan 2013 Link to this post

    Hi,

    Basically the ForeingKeyColumn currently does not support null-able values out-of-the-box, however you can use the following solution which uses the Save event of the Grid to enable null values in that column:

     
    Save event handler:

    function onSave(e) {
        //If current value is null (replace EmployeeId with your property name)
        if (!e.model.EmployerId) {
            //change the model value
            e.model.EmployerId = 0;
            //get the currently selected value from the DDL
            var currentlySelectedValue = $(e.container.find('[data-role=dropdownlist]')[0]).data().kendoDropDownList.value();
            //set the value to the model
            e.model.set('EmployerId', currentlySelectedValue);
        }
    }


    Kind Regards,
    Vladimir Iliev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  3. Kendo UI is VS 2017 Ready
  4. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 28 Feb 2013 Link to this post

    I'm trying to get this working in a batch edit scenario, using the aspnet wrappers.

    I added this function which is called on the Save event on the grid.  However, if the first column I try to edit is not the FK column, then I get an error: Uncaught TypeError: Cannot read property 'kendoDropDownList' of null

    I modified the script as follows
    function gridSave(e) {
      if (!e.model.AliasId) {
        e.model.AliasId = 0;
        var ddlData = $(e.container.find("[data-role=dropdownlist]")[0]).data();
        if (ddlData) {
          var currentAlias = ddlData.kendoDropDownList.value();
          e.model.set("AliasId", currentAlias);
        }
        //var currentAlias = $(e.container.find("[data-role=dropdownlist]")[0]).data().kendoDropDownList.value();
        //e.model.set("AliasId", currentAlias);
      }
    }
    Now, if I edit the FK column, nothing happens. If I edit a different column first then I can successfully edit the FK column (as long as I pick something other than the first option, but that's another story).

    Is there a way to make this work in batch edit?  Should I abandon the FK column altogether and try to use a custom editor instead?

    Thanks,
    Nick


  5. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 28 Feb 2013 Link to this post

    Hi Nick,

     
    The example from my previous reply is valid only for InLine edit mode. To achieve the same behavior using InCell edit mode you should define custom editor template for current column which contains dropDownList with defined change event handler. Please check the example change event handler code below:

    function onDropDownChange(e) {
        //get the edited field name
        var fieldName = "EmployeeId";
        //find the closest row
        var currentRow = e.sender.wrapper.closest("tr");
        //find the grid
        var grid = e.sender.wrapper.closest(".k-grid").data("kendoGrid");
        //get the current row dataItem
        var currentDataItem = grid.dataItem(currentRow);
        //manually set the current value of the DropDownList to the field
        currentDataItem.set(fieldName, parseInt(e.sender.value()));
    }
    Kind Regards,
    Vladimir Iliev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  6. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 28 Feb 2013 Link to this post

    Bugger, that sends me back into the nightmare that is Editor Templates.  The ForeignKey columns had got me out of that hell quite nicely.

    Cheers.
  7. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 28 Feb 2013 Link to this post

    Ok, I've changed everything up so that my data viewmodel that was 
    public class MonitorViewModel {
      public virtual int Id { get; set; }
      public virtual int? AliasId { get; set; }
      ...
    }
    is now
    public class MonitorViewModel {
      public virtual int Id { get; set; }
      [UIHint("MonitorAlias")]
      public virtual AliasListItem Alias { get; set; }
      ...
    }
    I created my editor template and hooked it all up and it seems to work, although I still can't select the first item in the dropdown if the original value is null.

    Unfortunately this has broken the filtering on that column!   :(

    When this was a FK column, the filter nicely gave me a dropdown of the Aliases from the underlying page's viewmodel but now I just have a blank dropdown and nothing works.

    How can I restore filtering to this column?

    Thanks,
    Nick
  8. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 01 Mar 2013 Link to this post

    Hi Nick,


    I would suggest to leave your view model as it was - containing only the nullable "AliasId" and use ForeignKeyColumn with the workaround that I provided in my previous reply in order to edit the nullable property. For convenience I created small example of editing nullable property of the model using ForeignKeyColumn which you can use as a baseline and attached it to the current thread.

    Kind regards,
    Vladimir Iliev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  9. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 01 Mar 2013 Link to this post

    Hi Vladimir, 

    Using your project as a base I'm back to my first problem, the dropdown appears in the cell but the value does not persist.

    I modified the Index.cshtml file from your project to more closely resemble my own project and the same issues occur, namely
    1. If I select an employee and save changes, no value is persisted
    2. If I first edit the Order Description field, the error Uncaught TypeError: Cannot read property 'kendoDropDownList' of null

    I can make the changes persist by doing this:
    1. Edit the Order Description field (the change will not persist yet)
    2. Edit the Employee ID field
    3. Go back and re-edit the Order Description field
    4. Click the Save Changes button
    You have to repeat steps 1-3 for every record you want to edit.

    Modified page:
    @(Html.Kendo().Grid<ForeignKeyColumnDemo.Models.Order>()
        .Name("Grid")
        .Columns(columns => {
          columns.Bound(p => p.OrderID);
          columns.ForeignKey(p => p.EmployeeID, (System.Collections.IEnumerable)ViewData["employees"], "EmployeeID", "Name").EditorTemplateName("GridNullableForeignKey");
          columns.Bound(p => p.OrderDescription);
          columns.Bound(p => p.OrderDate).Format("{0:d}");
          //columns.Command(c => {
          //    c.Edit();
          //    c.Destroy();
          //});
        })
        .ToolBar(toolBar => {
          toolBar.Create();
          toolBar.Save();
        })
        .Editable(editable => editable.Mode(GridEditMode.InCell))  // I'm in batch edit mode.
        .Pageable()
        .Sortable()
        .Scrollable()
        .Filterable()
        .Events(e => e.Save("onSave"))
        .DataSource(dataSource => dataSource
            .Ajax()
            .ServerOperation(false)
            .Model(model => {
              model.Id(p => p.OrderID);
              model.Field(p => p.OrderID).Editable(false);
            })
            .Create(create => create.Action("Create", "Home"))
            .Destroy(destroy => destroy.Action("Delete", "Home"))
            .Read(read => read.Action("Read", "Home"))
            .Update(update => update.Action("Update", "Home"))
        )
    )
     
    <script>   
        function onSave(e) {
            //If current value is null
            if (!e.model.EmployeeID) {
                //change the model value
                e.model.EmployeeID = 0;
                //get the currently selected value from the DDL
                var currentlySelectedValue = $(e.container.find('[data-role=dropdownlist]')[0]).data().kendoDropDownList.value();
                //set the value to the model
                e.model.set('EmployeeID', currentlySelectedValue);
            }
        }
     
    </script>


  10. Dan
    Dan avatar
    2 posts
    Member since:
    Nov 2010

    Posted 04 Mar 2013 Link to this post

    Vladimir Iliev, I am having the same issue.  I downloaded the NullableForeignKeyColumnDemo-CRUD-1412.zip.

    However, I am trying to use
    .Editable(editable => editable.Mode(GridEditMode.InLine))  option in my grid.
    In the demo I switched from
    GridEditMode.InLine to GridEditMode.InCell and the downloaded demo no longer selects the employee. 

    What changes are necessary to make the NullableForeignKeyColumnDemo work using the
    GridEditMode.InCell option?  I am thinking I could apply those changes to my program to get it working.

     

  11. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 05 Mar 2013 Link to this post

    Hi Dan,


    You can modify the previous example to use the edit event of the grid (instead of save event) and use the following edit event handler to allow editing in inCell edit mode:

    function onEdit(e) {
        var dropDown = e.container.find("[data-role=dropdownlist]").data("kendoDropDownList");
        if (dropDown) {
            dropDown.bind("change", function (e) {
                var grid = e.sender.wrapper.closest(".k-grid").data("kendoGrid");
                var dataItem = grid.dataItem(e.sender.wrapper.closest("tr"));
                //If current value is null
                if (!dataItem.EmployeeID) {
                    //change the model value
                    dataItem.EmployeeID = 0;
                    //get the currently selected value from the DDL
                    var currentlySelectedValue = e.sender.value();
                    //set the value to the model
                    dataItem.set('EmployeeID', currentlySelectedValue);
                }
            })
        }
    }


    Kind Regards,
    Vladimir Iliev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  12. Dan
    Dan avatar
    2 posts
    Member since:
    Nov 2010

    Posted 05 Mar 2013 Link to this post

    Thank you Vladimir Iliev, for the code snippet.  I was able to get the inCell editing to work as long as the EmployeeID remained an integer data type.  

    When I change the Employee datatype to string and modified it's helper to be a string the item in the list would no longer be selected when it is originally null. 

    I don't think the following command returns a value when the data type is a string. 
    var currentlySelectedValue = e.sender.value();

    It may be somewhere else as my script debugging/tracing skills are weak.

    How do I get the incell editing to work when the list is a <string>,<string> combination?

    I have attached an updated version of the demo with a new field GLAccountID that is a string.  In this version the EmployeeID is integer and the GLAcocuntID is a string.  I converted the app to use CDN to make it small enough to upload.
  13. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 06 Mar 2013 Link to this post

    Sorry for the late post, other projects jumped in the way.

    That's sorted me out, thanks Vladimir  :D

    I now have the filtering working as expected, brilliant.

  14. Nick
    Nick avatar
    86 posts
    Member since:
    Mar 2008

    Posted 06 Mar 2013 Link to this post

    Darn, I spoke too fast.

    Since I have multiple FK columns in the grid, as soon as I edit one of the other columns the first column changes from null to the first record.

    Is there any way of determining which column is being edited and only setting the default value when you're changing that column?

    Cheers,
    Nick

    For reference my grid definition is:
    @(Html.Kendo().Grid<HomeMonitorViewModel>()
          .Name("MonitorGrid")
          .Columns(c => {
            c.Bound(m => m.Name);
            c.ForeignKey(m => m.AliasId, (System.Collections.IEnumerable)Model.Aliases, "Id", "Name").EditorTemplateName("MonitorAlias").EditorViewData(new { aliases = Model.Aliases });
            c.Bound(m => m.Category);
            c.Bound(m => m.Description);
            c.Bound(m => m.HostSystem);
            c.ForeignKey(m => m.Classification, Model.Classifications, "Value", "Text");
            c.ForeignKey(m => m.Source, Model.Sources, "Value", "Text");
            c.ForeignKey(m => m.Origin, Model.Origins, "Value", "Text");
          })
          .ToolBar(t => {
            if(User.IsInRole("EditMonitor")){
              t.Create();
              t.Save();
            }
          })
          .Editable(e => e.Mode(GridEditMode.InCell).Enabled(User.IsInRole("EditMonitor")))
          .Events(e=>e.Edit("onEdit"))
          .Pageable()
          .Sortable()
          .Filterable()
          .Navigatable()
          .DataSource(d => d
            .Ajax()
            .Batch(true)
            .Events(e => {
              e.Error("error_handler");
            })
            .Model(model => {
              model.Id(monitor => monitor.Id);
              model.Field(monitor => monitor.Category).Editable(false);
              model.Field(monitor => monitor.Classification).DefaultValue(1);
              model.Field(monitor => monitor.Source).DefaultValue(1);
              model.Field(monitor => monitor.Origin).DefaultValue(1);
            })
            .PageSize(20)
            .ServerOperation(true)
            .Read("MonitorGridRead", "Home")
            .Create("MonitorGridCreate", "Home")
            .Update("MonitorGridUpdate", "Home")
            .Destroy("MonitorGridDestroy", "Home")
            )
    )
  15. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 07 Mar 2013 Link to this post

    Hi Nick,

     
    Basically the example from my last reply always change the "EmployeeID" field, however you can modify it to get the currently edited field name from the input name attribute:

    var dropDown = e.container.find("[data-role=dropdownlist]").data("kendoDropDownList");
    if (dropDown) {
        //use dynamic field name
        var fieldName = dropDown.element.attr("name");

    @Dan - For string data type - when the field value comes from the server as "null" it cannot be bound correctly to the DropDownList as it expects empty string for null value (for string type). In this case you can remove the edit event handler and modify the server to return empty strings instead of null values.

     
    Kind Regards,
    Vladimir Iliev
    the Telerik team
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  16. Rayko
    Rayko avatar
    27 posts
    Member since:
    Jul 2012

    Posted 30 Aug 2013 Link to this post

    Based on the code library and the info about the data-value-primitive attribute I've created an editor template "GridNullableForeignKey" which is just a extension of the normal "GridForeignKey":
    @model object
                
    @(
     Html.Kendo().DropDownListFor(m => m)       
            .BindTo((SelectList)ViewData[ViewData.TemplateInfo.GetFullHtmlFieldName("") + "_Data"])
            .HtmlAttributes(new { data_value_Primitive = "true" })
            .OptionLabel("Choose option")
             
    )
    No further script blocks needed in the view.

  17. Vladimir Iliev
    Admin
    Vladimir Iliev avatar
    2172 posts

    Posted 30 Aug 2013 Link to this post

    Hi Rayko,

     
    You are correct, after introducing the "data-value-primitive" attribute the previous solutions are no longer needed. 

    Kind Regards,
    Vladimir Iliev
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Back to Top
Kendo UI is VS 2017 Ready