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

Kendo Grid - Custom Editor - Combobox - inconsistant behaviour

4 Answers 486 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Matthew
Top achievements
Rank 1
Matthew asked on 08 Aug 2012, 12:45 PM
Im having trouble with the combobox as a custom editor. Populating the values are fine, however when selected the entire object (from the combobox) of the row is put into the bound field. This displays itself as [object Object]
Ive copied the column from the demo http://demos.kendoui.com/web/grid/editing-custom.html as is acting the same strange way that my own field does.
[update solving problems while going along]

Ive had similar problems before but just changed how it was populated. This works fine:
var proxyDropDownEditor = function(container, options){
    var data = [
        { text: "none" },
        { text: "HTTP" },
        { text: "CONNECT"},
        { text: "best" }
    ];
    $('<input data-bind="value:' + options.field + '"/>')
        .appendTo(container)
        .kendoDropDownList({
            dataTextField: "text",
            dataValueField: "text",
            dataSource: data
        });   
};

This is the one I need working:
The editor of the cueCollection is:
function cueCollectionEditor(container, options){
    var dataSource = new kendo.data.DataSource({
        type: "json",
        transport: {
            read: "/OrchardLocal/Nyx/EditCueCollection/List?ContentId=29"
        },
        schema: {
            model: {
                id: "Id"
            }
        }
    });
    $('<input data-text-field="Name" data-value-field="Id" data-bind="value:' + options.field + '"/>')
        .appendTo(container)
        .kendoDropDownList({
            autoBind: false,
            dataSource: dataSource
    });
 
    //$('<input name="' + options.field + '"/>')
    //    .appendTo(container)
    //    .kendoDropDownList({
    //        autoBind: false,
    //        dataTextField: "id",
    //        dataValueField: "id",
    //        dataSource: options
    //});   
}

but it currently has two problems. Clicking on any item it will select correctly and display correctly (in edit row) until finishing with row and clicking update. The first time this it is done the row will display "[object Object]" with the save method showing me the values of the model:
Category
    Object { __metadata={...}, CategoryID=4, CategoryName="Dairy Products", more...}
cueCollection
    Object { Id=4, Name="Carousel 2"
dirty:
    false
proxyType:
    "best"
other fields are excluded as they are just general columns and are working as expected. Im expecting the category to be populated as "Dairy Products" and cueCollection to be "4".

These are the columns:
{ field: "cueCollection", title: "Cues", editor: cueCollectionEditor
    //template: kendo.template($("#cueCollectionColumnTemplate").html())
},
{ field: "Category", width: "150px", editor: categoryDropDownEditor },
{ field: "proxyType", title: "Proxy Type", editor: proxyDropDownEditor },
{ command: ["edit", "destroy"], title: " ", width: "210px" }

Schema
schema: {
    model: {
        id: "title",
        fields: {
            title: { type : "string", nullable: false },
            proxyType: { type: "string", defaultValue: "best" },
            position : { type: "number", defaultValue: 0 },
            cueCollection: { type: "number" },//changing the type to number removed the viewmodel from being returned 
            Category: { type: "string" }    //changing the type to string fixed it from being a object returned to the correct value
        }
    }
}
changing the field type of "Category" to a string seemed to have fixed its return value from the edit row. cueCollection was not so lucky.

the ajax response for the dropdown list is nothing too special:
[{"Id":2,"Name":"collection1"},{"Id":4,"Name":"collection2"}]

Overall my aim would be to add the entire json object into the column: {"Id":2,"Name":"collection1"}
as it would be easier to navigate and understand in its future context. Seeing that this is what it is giving me lets roll with it, although im expecting just the id field.

Back on track:
lets skip trying to get just the id, as the object looks far more exciting.
datasource - schema - model - cueCollection
lets give it a default so that creating a new row doesnt break so easily.
cueCollection: { defaultValue: { Id:0, Name: "" } },
combobox data result
[{"Id":2,"Name":"collection1"},{"Id":4,"Name":"collection2"}]

selecting the first item and clicking on the update row it will appear as undefined (one of the problems i had earlier but hadnt really noted).
selecting the second will populate cueCollection as expected (as observed). Clicking update will set the field as [object][object] so lets add a client template.
...
function templateCollection(mModel){
        if(!mModel)
            return "none selected";
        return mModel.Name;
    }
</script>   
<script id="cueCollectionColumnTemplate" type="text/x-kendo-tmpl">
    #: templateCollection(cueCollection) #
</script>
how the column looks in the grid definition:
{ field: "cueCollection", title: "Cues",
    editor: cueCollectionEditor,
    template: kendo.template($("#cueCollectionColumnTemplate").html())
},

current problems:
selecting the first item doesn't work. Lets try adding the option label to see if it is just that first field.
$('<input data-bind="value:' + options.field + '"/>')
    .appendTo(container)
    .kendoDropDownList({
        dataTextField: "Name",
        dataValueField: "Id",
        autoBind: false,
        dataSource: dataSource,
        optionLabel: "Select..."
});
... *scratches head* ... selecting any item is causing problems now. As it has now decided on binding the "Id" value and now losing the object. This is turning into one of those get what you want at the wrong time scenarios.

Interesting. Adding in the option-label fixed the data bind issue, but broke how I was now expecting it. So now I need the data row value instead of a data field value.

Ok now quite confused. It is now selecting the object again.
Ive changed the editor to:
var hiddenBox = $('<input type="hidden" data-bind="value:' + options.field + '"/>').appendTo(container);
var box = $('<input data-bind="value:' + options.field + '"/>')
    .appendTo(container);
 
var kendoDropDown = box.kendoDropDownList({
        dataTextField: "Name",
        dataValueField: "Id",
        autoBind: false,
        dataSource: dataSource,
        optionLabel: "Select..."
});

however the action of the dropdown has gone back to selecting the object over the Id

Can anyone describe what is going on with the dropdown. Static datasources seem to bind perfectly well, but ajax based data sources seem to be giving me the run around. It seems a little random now when it wants to select the Id or select the Object.

Any insight would be wonderful as I've spent far too long trying to get the dropdown to act consistently.

Thanks,
Matt

4 Answers, 1 is accepted

Sort by
0
Matthew
Top achievements
Rank 1
answered on 08 Aug 2012, 02:48 PM
Updating to one of the latest builds for the web js changes things a little as well.
v2012.2.803
Bound to the cueCollection field:
Id
    2
Name
    "collection1"
_events
    Object { get=[1], change=[1]}
uid
    "a968a83d-c0b6-41de-9006-db8ba5b1774c"
...
__proto__
    Object { init=function(), shouldSerialize=function(), toJSON=function(), more...}
...

v2012.2.710
Id 
    2
Name
    "collection1"

Ok, my assumption of how it is stored vs how it comes back out of the grid is a little incorrect.
This appears to be what the grid thinks the output should be (based on the dataSource change event):
"[{\"title\":\"test\",\"proxyType\":\"best\",\"position\":0,\"cueCollection\":4}]"
Retrieved using:
function processGrid(e) {
    var a = e.sender.view();
    var d = JSON.stringify(a);
    $("#Raw").val(d);
}

I would prefer the last bit of the output (cueCollection) as: { Id: x, Name: "abcd..." } however it looks like the data binding part is working (on the id), where the grid (editing) model a little more free/flexible than I had originally thought.

im guessing the observable model can be thought of by: model.get("cueCollection") wiring off to the 'id' of one of viewmodels above? 
It looks like I need to do some more reading in the MVVM and datasource part of the documentation.
0
Daniel
Telerik team
answered on 13 Aug 2012, 02:54 PM
Hello Matthew,

Basically, if the Grid is bound to an object or a property which value is null, the whole item will be returned as result when saving the value from the DropDownList editor. In case you want to bind to a value property, the field should not be Nullable in order to avoid getting the object when creating a new record. 
I am not sure if I understand correctly the difference in the latest build but there was a bug which caused the value not to saved correctly after the first update. If this is not the problem you are experiencing and updating did not resolve the problem, please send a sample project so I can check what exactly goes wrong.

Kind regards,
Daniel
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Some
Top achievements
Rank 1
answered on 28 Aug 2012, 10:27 AM
Daniel,
Can you guys put a notification somewhere in huge blinking letters that if the field that is being bound to the dropdown is nullable and you click "Add" no matter what value is selected it will always bind to [object, object] and the default value will become irrelevant?  That has been my experience so far and after 15 - 20 hours of troubleshooting (majority of the time spent searching the forums for a solution and trying various things) only now through a google search not a search of your forums am I finding the solution (make the field not nullable) to a known issue.  I love this product but these types of issues are extremely frustrating and go a long way in making a person not want to use this otherwise fantastic product.

Thanks,
Nick
0
Matthew
Top achievements
Rank 1
answered on 28 Aug 2012, 11:19 AM
I started a nice example of this and its conditions, but the browser crashed and i couldn't be bothered to re-write it at 2am. But I strongly concur with Nick. The two instances do need a better example put forth. Both in the grid, and in the drop down list section (and possibly combobox) where one is binding to remote data and the value is needed -- whether it is the entire object ie
{ id: 1, name: "condition", description:"this is a required item" }
or just the value 'id' which will often be more the desired case for the majority I believe.

The same binding pattern is applied to both form binding as well as the grid. So others with the same problem may benefit as well, so the example may be good in the mvvm section as well which I use the two modes most now. Creating a form, the main model would something like this scenario:

I need to return / create a model that can be submitted to a external service, or added directly into a datasource and that can deal with sending it off. The model will have two sources of information and submitted back to one. Ie the service will know the company but will need the extra data of the other source. 

(function(Models){
    //main view model for the form
    Models.companyRequirement = function(requirement, company){
        requirement || (requirement = Models.requirement());
        company || (company = Models.company());
        var model = {
            requirement: null, //this will store an object. data-text-field="name" data-value-field="id" bindings on the element become equality conditions to rebind to a datasource
            companyId: 0 // //this will store a single value defined by data-value-field 
        };
         
        return model;
    };
     
    //single item of a dropdown which will become part of a datasource
    Models.company = function(){
        var model = {
            id : 0,
            name: ""
        };
         
        return model;
    };
    Models.requirement = function(){
        var model = {
            id: 0,
            name: "",
            description: ""
        };
         
        return model
    };
}(Demo.Models));

this would be an example of my form. Making the two input fields into drop down lists. The companyId is only needed as a foreign key, the requirement would be the extra model of information that would be needed.
<div id="form">
 
<input data-text-field="name" data-value-field="id" data-bind="value:companyId" data-role="dropdownlist"/>
<input data-text-field="name" data-value-field="id" data-bind="value:requirement" data-role="dropdownlist"/>
 
    <button>Submit</button>
</div>

the model would be created/fetched (selected from a datasource), and then bound to the form element.

The final output would be as follows based on the model definition. The difference in behaviour while quite useful it is only useful if it is expected which it isn't really suggested by the demos or documentation.
{
    requirement: { id: 1, name: "condition", description:"this is a required item" }, //the object of the drop down
    companyId: 5    //the single 'value' of the drop down
};

I hope this is useful for others that casually stumble upon this mode and hadn't noticed the very small differences between the two fields and its effect on value selection.

And displaying correctly in a grid. I would recommend creating a client template and showing the appropriate field(s) in the way you would want if you are capturing an object.

Thanks, Matt
ps. I made the example in notepad++ so please excuse any mistakes above.
Tags
Grid
Asked by
Matthew
Top achievements
Rank 1
Answers by
Matthew
Top achievements
Rank 1
Daniel
Telerik team
Some
Top achievements
Rank 1
Share this question
or