I have a remote datasource/grid with something like this as part of the datasource schema model:
model: {fields: {department_id: {type:"number"}, department: {type: "object"} ...
where the nested department object includes fields "id" and "prettyName". The grid uses incell editing and a "save" button on the toolbar. The columns include a field for the "department_id":
{field: 'deptID', title:"Department",
template: "#:department.prettyName#",
editor: function(container, options) {
$('<input required name="' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataSource: remoteDepartmentDatasource,
dataTextField: "prettyName",
dataValueField: "id", ...
}
This works to a point - the nested "department.prettyName" displays in the grid via the template, and with incell editing the dropdown list (which is fed records identical to the nested "department" object) correctly changes the "department_id" field to the id selected from the dropdown. But since the grid's display value "prettyName" is coming from the original nested "department" in the grid row's dataSource record, once the editor is exited the grid displays a stale value until the update is made to the server and the server returns an updated record, which isn't until the user decides to click "Save changes".
Is there any clean way to bind things to have BOTH the department_id AND the department object updated from the edit process's dropdown list? Or is there an event I could hook into, perhaps the dropdown's "close", where I would know enough to push the "department" object onto the record in the grid's dataSource?
8 Answers, 1 is accepted
In general, the MVVM value binding, used in the widget's editing, can update only one model field. I would suggest you check our "Editing Functionality" help topic for more details:
http://docs.telerik.com/kendo-ui/intro/widget-basics/editing
If you would like to update multiple model fields on widget change, then you will need to get access to the editor: then you can wire the change event of the widget and retrieve the current data item:
- http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#events-change
- http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#methods-dataItem
Regards,
Georgi Krustev
Telerik by Progress
Thanks. Even if I transfer the desired info, there's an issue with filtering. The column is defined to use a numeric field, for which the template displays the "department.prettyName" string. If I turn row filtering on for the column, I get a numeric filter for the id values, not a string one for the values output by the template. I see the Grid has a "columns.filterable.cell.template" setting which might be intended to override the filter entry; I'm going to look at that.
Your Grid "Editing custom editor" demo does something similar, but in reverse. The "products" datasource has a "CategoryID" field, and a "Category" object, which has attributes like CategoryName, CategoryID, and "Description". The example only defines and uses the "Category" object for the column, with a template that displays "Category.CategoryName". The DropDownList editor in this case updates the entire Category object, which makes the onscreen display change automatically without additional hacks. But the top level "CategoryID" field, which will be the database key in the "products" table, will NOT have changed (only Category.CategoryID will have). If an Update operation were done, a back end that assumes the key will be modified would not see any change in the category, unless it does some sort of inspection of the Category object? The demo avoids the question by not having any Update capability.
Our backend service in the "Editing custom editor" demo will use only the updated Category model. The "CategoyID" field is an artefact that is not used in this demo.
What I would suggest you is to utilize the "Editing custom editor" demo and use server filtering, which will help you perform the custom filtration task much easier (you have full control over the data layer I suppose).
If you still experience issues with this implementation, please provide a runnable demo that we can investigate locally.
Regards,
Georgi Krustev
Telerik by Progress
"Our backend service in the "Editing custom editor" demo will use only the updated Category model. The "CategoyID" field is an artefact that is not used in this demo."
Ah. For my purposes, I was extending some existing code, and was using the key field; the nested model info that was only a client-side display convenience. I won't fight city hall - I'm going to look at adjusting my back end to use the full nested deserializing stuff on the nested object.
Thanks for the help.
A related question about filtering in this situation, where a grid column is a nested object. Here's a copy of your "Editing custom editor" demo with the grid's "filterable" set to "row" with the "contains" operator. The "Product Name" column filters as expected, since it is a simple string. But the "Category" column is defined as the nested object ("Category"), which is not a string, and filtering fails.
It doesn't look like there's a way to specify that something other than the defined column should be filtered against (in this case, Category.CategoryName)? A hypothetical configuration option like "columns.filterable.filterField: 'Category.CategoryName' " would let some filtering be done with nested objects? There might also need to be a "columns.filterable.filterFieldType" so types like "string" or "number" could be specified, since I don't think the data model allows defining and typing nested fields.
Indeed, the grid would not be able to filter objects. It will need a specific field of primitive type.
The best solution in this case is to configure the column to use the primitive type, thus the filtering/sorting will work. The editing will be handled with a custom editor template, just like it is shown in the demo. The caveat here is to bind the DropDownList widget to the whole object and not to the column field:
http://dojo.telerik.com/IjiFE/3
With this setup, the grid will filter/sort specific primitive type and the DropDownList widget will update the whole object.
Regards,
Georgi Krustev
Telerik by Progress
Thanks - with everything else I was forgetting that the binding target was controlled by the "name" attribute of the input element, not the field defined for the column. This seems to work well. For anyone coming across this, Georgi's modified version is actually at:
http://dojo.telerik.com/IjiFE/5
One more filtering issue comes up when the object field is defined as "nullable" and has a null value. I can use the field's 'template' to display something appropriate, and the editor's DropDownList.optionLabel to handle and display when editing. But the filtering logic tries to pass "Category.CategoryName", and when Category is null, that obviously produces a "Cannot read property 'CategoryName' of null" Javascript error and shuts down. The demo has no nulls for Category, but if you add a new record to this modified version, leave the Category unchosen, and try and filter the Category column for, say "Con" you can see what happens.
I tried monkeying around with the grid's "filter" event handler, to alter the e.filter.filters "operator" to be a function of my own. But it looks like what is passed to the operator function is an already accessed "Category.CategoryName" value, so the error happens before I can hook in. It looks like this is done inside the Query.filter() logic, which might be tricky or inadvisable to try and replace.
Am I missing anything that might let the row filter work when null values are present?
Thank you for sharing the Dojo demo with the correct milestone.
With regards to the filtering issue, indeed, it will not work when the object of the nested field is null. The solutions in this case are:
- change the default of the Category field - http://dojo.telerik.com/eriLa/2
- change the column field to use "Category" and then filter the source manually in the filter event
The latter scenario is pretty close to the approach you've already tried. To overcome the value extraction issue in the filter.operator, you will need to use the top level model property. From there you will need to handle the filtering manually. Of course in this case, you will need to handle the row filter UI value setter manually.
The third option is to use server filtering. This, however, requires binding to a remote service, which I am not sure whether it matches your implementation.
Regards,
Georgi Krustev
Telerik by Progress