This is a migrated thread and some comments may be shown as answers.

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

15 Answers 1095 Views
Grid
This is a migrated thread and some comments may be shown as answers.
MC
Top achievements
Rank 1
MC asked on 11 Jan 2013, 03:46 AM
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.
--

15 Answers, 1 is accepted

Sort by
0
Vladimir Iliev
Telerik team
answered on 14 Jan 2013, 12:31 PM
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!
0
Nick
Top achievements
Rank 1
answered on 28 Feb 2013, 11:56 AM
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


0
Vladimir Iliev
Telerik team
answered on 28 Feb 2013, 01:46 PM
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!
0
Nick
Top achievements
Rank 1
answered on 28 Feb 2013, 02:46 PM
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.
0
Nick
Top achievements
Rank 1
answered on 28 Feb 2013, 05:03 PM
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
0
Vladimir Iliev
Telerik team
answered on 01 Mar 2013, 06:36 AM
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!
0
Nick
Top achievements
Rank 1
answered on 01 Mar 2013, 11:41 AM
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>


0
Dan
Top achievements
Rank 1
answered on 04 Mar 2013, 07:02 PM

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.

 

0
Vladimir Iliev
Telerik team
answered on 05 Mar 2013, 06:22 AM
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!
0
Dan
Top achievements
Rank 1
answered on 05 Mar 2013, 05:27 PM
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.
0
Nick
Top achievements
Rank 1
answered on 06 Mar 2013, 01:16 PM
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.

0
Nick
Top achievements
Rank 1
answered on 06 Mar 2013, 01:52 PM
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")
        )
)
0
Vladimir Iliev
Telerik team
answered on 07 Mar 2013, 02:11 PM
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!
0
Rayko
Top achievements
Rank 1
answered on 30 Aug 2013, 11:55 AM
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.

0
Vladimir Iliev
Telerik team
answered on 30 Aug 2013, 12:34 PM
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!
Tags
Grid
Asked by
MC
Top achievements
Rank 1
Answers by
Vladimir Iliev
Telerik team
Nick
Top achievements
Rank 1
Dan
Top achievements
Rank 1
Rayko
Top achievements
Rank 1
Share this question
or