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

How do I set model values from detailTemplate?

2 Answers 588 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Shea
Top achievements
Rank 1
Shea asked on 29 Oct 2013, 12:10 AM
I have a kendo grid (batch editable) with a detailTemplate. My detail template has two drop down lists (SubItem, and SubItemSerial). The SubItem is not showing the correct value when template is expanded.  Also when the value is changed on first drop down, in the change event, I set() the correct value on the grid's model. But as soon as I do this, the detail template closes right away, which I don't want to happen.

I am assuming that people often want to set a value from a detail template, but I could not find a good example. Here is what I have so far:
001.function MrItemsGrid(mr_ID, grid_id, is_editable, default_billable) {
002.    var self = this;
003.    self.mr_ID = mr_ID;
004.    self.GRID_ID = '#' + grid_id;
005.    self.HANDLER_URL = "/MaterialRequestItem";
006.    self.IS_EDITABLE = is_editable;
007.    self.DEFAULT_BILLABLE = default_billable;
008. 
009.    self.mr_source = new kendo.data.DataSource({
010.        batch: true,
011.        filter: [],
012.        serverPaging: true,
013.        serverSorting: true,
014.        serverFiltering: true,
015.        serverGrouping: true,
016.        serverAggregates: true,
017.        type: "aspnetmvc-ajax",
018.        pageSize: 50,
019.        schema: {
020.            data: "Data",
021.            total: "Total",
022.            errors: "Errors",
023.            model: {
024.                id: "MaterialRequestItemId",
025.                fields: {
026.                    MaterialRequestItemId: { type: "string" },
027.                    MaterialRequisitionId: { type: "string", defaultValue: self.mr_ID },
028. 
029.                    ItemID: { type: "number", defaultValue: 0 },
030.                    ItemName: { type: "string", defaultValue: "" },
031. 
032.                    SubItemId: { type: "number", defaultValue: 0 },
033.                    SubItemName: { type: "string", defaultValue: "" },
034. 
035.                    SubItemSerialId: { type: "number", defaultValue: 0 },
036.                    SubItemSerialNumber: { type: "string", defaultValue: "" },
037. 
038.                    BusinessPartnerID: { type: "number", defaultValue: 0 },
039.                    BusinessPartnerName: { type: "string", defaultValue: "" },
040. 
041.                    Description: { type: "string" },
042. 
043.                    Price: { type: "number", defaultValue: 0 },
044.                    Quantity: { type: "number", defaultValue: 0, validation: { required: true, min: 0 } },
045.                    Total: { type: "number", defaultValue: 0 },
046.                },
047.            }
048.        },
049. 
050.        transport: {
051.            prefix: "",
052.            read: {
053.                url: self.HANDLER_URL + "/Read?mrId=" + self.mr_ID,
054.                type: "GET",
055.                cache: false,
056.            },
057.            update: {
058.                url: self.HANDLER_URL + "/Update",
059.                type: "PUT",
060.            },
061.            create: {
062.                url: self.HANDLER_URL + "/Create",
063.                type: "POST",
064.            },
065.            destroy: {
066.                url: self.HANDLER_URL + "/Destroy",
067.                type: "DELETE",
068.            }
069.        },
070. 
071.        error: GridCommon.showCallBackError
072.    });
073. 
074.    self.items_src = new kendo.data.DataSource({
075.        transport: {
076.            read: {
077.                url: self.HANDLER_URL + "/GetItems",
078.                dataType: "json",
079.                type: "GET"
080.            }
081.        },
082.        error: GridCommon.showCallBackError
083.    });
084. 
085.    self.vendors_src = new kendo.data.DataSource({
086.        transport: {
087.            read: {
088.                url: self.HANDLER_URL + "/GetVendors",
089.                dataType: "json",
090.                type: "GET"
091.            }
092.        },
093.        error: GridCommon.showCallBackError
094.    });
095. 
096.    self.itemDropDownEditor = function(container, options) {
097. 
098.        $('<input required data-text-field="ExtendedItemName" data-value-field="ItemName" data-bind="value:' + options.field + '"/>')
099.            .appendTo(container)
100.            .kendoComboBox({
101.                autoBind: false,
102.                serverFiltering: false,
103.                select: "",
104.                optionLabel: { ExtendedItemName: "", ItemID: 0 },
105.                dataSource: self.items_src,
106.                filter: "contains",
107.                change: function(e) {
108.                    options.model.set('ItemID', e.sender.dataItem().ItemID);
109.                }
110.            });
111.    };
112. 
113.    self.vendorDropDownEditor = function (container, options) {
114. 
115.        $('<input required data-text-field="BusinessPartnerName" data-value-field="BusinessPartnerName" data-bind="value:' + options.field + '"/>')
116.            .appendTo(container)
117.            .kendoComboBox({
118.                autoBind: false,
119.                filter: "contains",
120.                select: "",
121.                serverFiltering: false,
122.                optionLabel: { BusinessPartnerName: "", BusinessPartnerID: 0 },
123.                dataSource: self.vendors_src,
124.                change: function(e) {
125.                    options.model.set('VendorId', e.sender.dataItem().BusinessPartnerID);
126.                }
127.            });
128.    };
129. 
130.    self.updateTotal = function (e) {
131.        var r = e.values.Price ? e.values.Price : e.model.Price;
132.        var q = e.values.Quantity ? e.values.Quantity : e.model.Quantity;
133.        e.model.set('Total', q * r);
134.    }
135. 
136.    self.init = function () {
137. 
138.        var tools = null;
139.        var row_commands = null;
140.        if (self.IS_EDITABLE) {
141.            tools = [
142.                { name: "save", text: "Save" },
143.                { name: "create", text: "Add" },
144.                { name: "cancel", text: "Cancel" }
145.            ];
146.            row_commands = [{
147.                name: "destroy",
148.                template: '<a href="##" class="k-grid-delete"></a>'
149.            }]
150.        } else {
151.            $(self.GRID_ID).addClass('readonly');
152.        }
153.        $(self.GRID_ID).kendoGrid({
154.            toolbar: tools,
155.            save: self.updateTotal,
156.            detailTemplate: kendo.template($("#SubItem").html()),
157.            detailInit: self.detailInit,
158.            dataBound: function () {
159.//              this.expandRow(this.tbody.find("tr.k-master-row").first());
160.            },
161. 
162.            columns: [
163.                { field: "ItemName", title: "Item Type", editor: self.itemDropDownEditor },
164.                { field: "BusinessPartnerName", title: "Vendor", editor: self.vendorDropDownEditor },
165.                { field: "Description" },
166.                { field: "Price", title: "Price", format: "{0:c}", width: 90, editor: GridCommon.notEditable },
167.                { field: "Quantity", title: "QTY", width: 65, editor: GridCommon.numberEditor },
168. 
169.                { field: "Total", editor: GridCommon.notEditable, format: "{0:c}", width: 95 },
170.                { command: row_commands, width: 40 }
171.            ],
172. 
173.            pageable: true,
174.            scrollable: true,
175.            editable: self.IS_EDITABLE,
176.            navigatable: true,
177.            sortable: true,
178.            batch: true,
179. 
180.            dataSource: self.mr_source,
181.            saveChanges: GridCommon.saveAll
182.        });
183.    }
184.     
185.    self.items_src = new kendo.data.DataSource({
186.        transport: {
187.            read: {
188.                url: "/EquipmentEntry/GetItems",
189.                dataType: "json",
190.                type: "GET"
191.            }
192.        },
193. 
194.        error: GridCommon.showCallBackError
195.    });
196.     
197.    self.tempSubItemId = null;
198. 
199.    self.detailInit = function (context) {
200.        var detailRow = context.detailRow;
201.        var masterRow = context.masterRow;
202.        var mrModel = context.data;
203.        var grid = this;
204.        var viewCollection = grid.dataSource.view();
205. 
206.        var subItemContainer = detailRow.find(".sub-item");
207.        var subItemSerialContainer = detailRow.find(".sub-item-serial");
208. 
209.        $('<input required data-text-field="ExtendedItemName" data-value-field="ExtendedItemName" data-bind="value: ?ItemID" data-mr-sub-uid="'+ mrModel.uid +'"/>')
210.            .appendTo(subItemContainer)
211.            .kendoDropDownList({
212.                autoBind: false,
213.                dataTextField: "ExtendedItemName",
214.                dataValueField: "ItemID",
215.                dataSource: self.items_src,
216.                optionLabel: { ExtendedItemName: GridCommon.emptyText, ItemID: 0 },
217.                change: function (ee) {
218.                    var ds = $(self.GRID_ID).data('kendoGrid').dataSource;
219.                    var mrUid = ee.sender.element.data('mr-sub-uid');
220.                    var mr = grid.dataSource.getByUid(mrUid);
221.                    var newItem = ee.sender.dataItem();
222.                    mr.set('SubItemId', newItem.ItemID);
223.                    mr.set('SubItemName', newItem.ItemName);
224.                    //self.tempSubItemId = ee.sender.dataItem().ItemID;
225.                }
226.            });
227. 
228. 
229.        $('<input required data-text-field="Description" data-value-field="Description" data-bind="value:SubItemSerialId"/>')
230.            .appendTo(subItemSerialContainer)
231.            .kendoDropDownList({
232.                autoBind: false,
233.                dataTextField: "Description",
234.                dataValueField: "ItemSerialID",
235.                optionLabel: { Description: GridCommon.emptyText, ItemSerialID: 0 },
236.                dataBound: function () {
237.                    if (this.dataSource.data().length == 0) {
238.                        this.enable(false);
239. 
240.                        this.text("No items found");
241.                    }
242.                },
243.                dataSource: {
244.                    transport: {
245.                        read: {
246.                            url: "/EquipmentEntry/GetSerials",
247.                            dataType: "json",
248.                            type: "GET",
249.                            data: function () {
250.                                return {
251.                                    itemid: self.tempSubItemId,
252.                                    exclude_List: "0"
253.                                };
254.                            }
255.                        }
256.                    },
257. 
258.                    error: GridCommon.showCallBackError
259.                }
260.            });
261.    }
262.}
Any ideas?

2 Answers, 1 is accepted

Sort by
0
Petur Subev
Telerik team
answered on 30 Oct 2013, 01:37 PM
Hello Shea,

I am not sure why exactly "SubItemId" is not bound successfully, and we need a project to investigate further.

 Regarding the second question - this rebinding of the outer Grid is expected, because the 'change' event of the inner Grid is actually the 'change' event of the master Grid (you are using the same dataSource). The Grid will automatically respond to that change and refresh itself, thus the expanded details will become collapsed.

You can try to again re-open the collapsed detailView, similar way to the approach used in this JsBin.

Kind Regards,
Petur Subev
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Accepted
Shea
Top achievements
Rank 1
answered on 30 Oct 2013, 01:57 PM
I did get this working. I had to manually do the cascading, though it is a a bit of a mess. It is part of a very large project, so I don't have time to bundle up just the relevant code. But here is the JS for what I got working. I am sure there is a cleaner way to do it, but this is what I ended up with:

001.function MrItemsGrid(mr_ID, grid_id, is_editable, default_billable) {
002.    var self = this;
003.    self.mr_ID = mr_ID;
004.    self.GRID_ID = '#' + grid_id;
005.    self.HANDLER_URL = "/MaterialRequestItem";
006.    self.IS_EDITABLE = is_editable;
007.    self.DEFAULT_BILLABLE = default_billable;
008. 
009.    self.mr_source = new kendo.data.DataSource({
010.        batch: true,
011.        filter: [],
012.        serverPaging: true,
013.        serverSorting: true,
014.        serverFiltering: true,
015.        serverGrouping: true,
016.        serverAggregates: true,
017.        type: "aspnetmvc-ajax",
018.        pageSize: 50,
019.        schema: {
020.            data: "Data",
021.            total: "Total",
022.            errors: "Errors",
023.            model: {
024.                id: "MaterialRequestItemId",
025.                fields: {
026.                    MaterialRequestItemId: { type: "string" },
027.                    MaterialRequisitionId: { type: "string", defaultValue: self.mr_ID },
028. 
029.                    ItemID: { type: "number", defaultValue: 0 },
030.                    ItemName: { type: "string", defaultValue: "" },
031. 
032.                    SubItemId: { type: "number", defaultValue: null },
033.                    SubItemName: { type: "string", defaultValue: "" },
034. 
035.                    SubItemSerialId: { type: "number", defaultValue: null },
036.                    SubItemSerialNumber: { type: "string", defaultValue: "" },
037. 
038.                    BusinessPartnerID: { type: "number", defaultValue: null },
039.                    BusinessPartnerName: { type: "string", defaultValue: "" },
040. 
041.                    Description: { type: "string" },
042. 
043.                    Price: { type: "number", defaultValue: 0 },
044.                    Quantity: { type: "number", defaultValue: 0, validation: { required: true, min: 0 } },
045.                    Total: { type: "number", defaultValue: 0 },
046.                },
047.            }
048.        },
049. 
050.        transport: {
051.            prefix: "",
052.            read: {
053.                url: self.HANDLER_URL + "/Read?mrId=" + self.mr_ID,
054.                type: "GET",
055.                cache: false,
056.            },
057.            update: {
058.                url: self.HANDLER_URL + "/Update",
059.                type: "PUT",
060.            },
061.            create: {
062.                url: self.HANDLER_URL + "/Create",
063.                type: "POST",
064.            },
065.            destroy: {
066.                url: self.HANDLER_URL + "/Destroy",
067.                type: "DELETE",
068.            }
069.        },
070. 
071.        error: GridCommon.showCallBackError
072.    });
073. 
074.    self.items_src = new kendo.data.DataSource({
075.        transport: {
076.            read: {
077.                url: GridCommon.ITEMS_HANDLER_URL + "/GetItems",
078.                dataType: "json",
079.                type: "GET"
080.            }
081.        },
082.        error: GridCommon.showCallBackError
083.    });
084. 
085.    self.items_with_serials_src = new kendo.data.DataSource({
086.        transport: {
087.            read: {
088.                url: GridCommon.ITEMS_HANDLER_URL + "/GetItems?withSerials=true",
089.                dataType: "json",
090.                type: "GET"
091.            }
092.        },
093. 
094.        error: GridCommon.showCallBackError
095.    });
096. 
097.    self.vendors_src = new kendo.data.DataSource({
098.        transport: {
099.            read: {
100.                url: GridCommon.BP_HANDLER_URL + "/GetVendors",
101.                dataType: "json",
102.                type: "GET"
103.            }
104.        },
105.        error: GridCommon.showCallBackError
106.    });
107. 
108.    self.itemDropDownEditor = function(container, options) {
109. 
110.        $('<input required data-text-field="ExtendedItemName" data-value-field="ItemName" data-bind="value:' + options.field + '"/>')
111.            .appendTo(container)
112.            .kendoComboBox({
113.                autoBind: false,
114.                serverFiltering: false,
115.                select: "",
116.                optionLabel: { ExtendedItemName: "", ItemID: 0 },
117.                dataSource: self.items_src,
118.                filter: "contains",
119.                change: function(e) {
120.                    options.model.set('ItemID', e.sender.dataItem().ItemID);
121.                }
122.            });
123.    };
124. 
125.    self.vendorDropDownEditor = function (container, options) {
126. 
127.        $('<input required data-text-field="BusinessPartnerName" data-value-field="BusinessPartnerName" data-bind="value:' + options.field + '"/>')
128.            .appendTo(container)
129.            .kendoComboBox({
130.                autoBind: false,
131.                filter: "contains",
132.                select: "",
133.                serverFiltering: false,
134.                optionLabel: { BusinessPartnerName: "", BusinessPartnerID: 0 },
135.                dataSource: self.vendors_src,
136.                change: function(e) {
137.                    options.model.set('VendorId', e.sender.dataItem().BusinessPartnerID);
138.                }
139.            });
140.    };
141. 
142.    self.updateTotal = function (e) {
143.        var r = e.values.Price ? e.values.Price : e.model.Price;
144.        var q = e.values.Quantity ? e.values.Quantity : e.model.Quantity;
145.        e.model.set('Total', q * r);
146.    }
147. 
148.    self.init = function () {
149. 
150.        var tools = null;
151.        var row_commands = null;
152.        if (self.IS_EDITABLE) {
153.            tools = [
154.                { name: "save", text: "Save" },
155.                { name: "create", text: "Add" },
156.                { name: "cancel", text: "Cancel" }
157.            ];
158.            row_commands = [{
159.                name: "destroy",
160.                template: '<a href="##" class="k-grid-delete"></a>'
161.            }]
162.        } else {
163.            $(self.GRID_ID).addClass('readonly');
164.        }
165.        $(self.GRID_ID).kendoGrid({
166.            toolbar: tools,
167.            save: self.updateTotal,
168.            detailTemplate: kendo.template($("#SubItem").html()),
169.            detailInit: self.detailInit,
170.            dataBound: function () {
171.//              this.expandRow(this.tbody.find("tr.k-master-row").first());
172.            },
173. 
174.            columns: [
175.                { field: "ItemName", title: "Item Type", editor: self.itemDropDownEditor },
176.                { field: "BusinessPartnerName", title: "Vendor", editor: self.vendorDropDownEditor },
177.                { field: "Description" },
178.                { field: "Price", title: "Price", format: "{0:c}", width: 90, editor: GridCommon.notEditable },
179.                { field: "Quantity", title: "QTY", width: 65, editor: GridCommon.numberEditor },
180. 
181.                { field: "Total", editor: GridCommon.notEditable, format: "{0:c}", width: 95 },
182.                { command: row_commands, width: 40 }
183.            ],
184. 
185.            pageable: true,
186.            scrollable: true,
187.            editable: self.IS_EDITABLE,
188.            navigatable: true,
189.            sortable: true,
190.            batch: true,
191. 
192.            dataSource: self.mr_source,
193.            saveChanges: GridCommon.saveAll,
194.            remove: GridCommon.saveOnDelete
195.        });
196.    }
197.     
198.    self.tempSubItemId = null;
199. 
200.    self.detailInit = function (context) {
201.        var mrModel = context.data;
202. 
203.        var detailRow = context.detailRow;
204.        var subItemContainer = detailRow.find(".sub-item");
205.        var subItemSerialContainer = detailRow.find(".sub-item-serial");
206.        var passThrough = detailRow.find("input[name=PassThrough]");
207. 
208.        $(passThrough).prop('disabled', !self.IS_EDITABLE);
209.        $(passThrough).prop('checked', mrModel.PassThrough);
210.        passThrough.change(function (e) {
211.            mrModel.PassThrough = $(this).prop('checked');
212.            mrModel.dirty = true;
213.        });
214. 
215.        $('<input required data-text-field="ExtendedItemName" data-value-field="ItemID" />')
216.            .appendTo(subItemContainer)
217.            .kendoComboBox({
218.                autoBind: false,
219.                dataTextField: "ExtendedItemName",
220.                dataValueField: "ItemID",
221.                dataSource: self.items_with_serials_src,
222.                filter: "contains",
223.                value: mrModel.SubItemId,
224.                text: mrModel.SubItemName,
225.                enable: self.IS_EDITABLE,
226.                optionLabel: { ExtendedItemName: "", ItemID: 0 },
227.                //optionLabel: { ExtendedItemName: GridCommon.emptyText, ItemID: 0 },
228.                //dataBound: function (ee) {
229.                //    this.value(0);
230.                //    if (this.dataSource.data().length === 0) {
231.                //        this.enable(false);
232.                //        this.text("No items with serial #'s found");
233.                //        console.log("No items with serial #'s found")
234.                //    } else {
235.                //        console.log('has ' + this.dataSource.data().length + ' items.')
236.                //        this.enable(true);
237.                //        this.text(GridCommon.emptyText);
238.                //    }
239.                //},
240.                change: function (ee) {
241.                    var newItem = ee.sender.dataItem();
242.                    if (!newItem)
243.                    {
244.                        return;
245.                    }
246. 
247.                    mrModel.SubItemId = newItem.ItemID;
248.                    mrModel.SubItemName = newItem.ItemName;
249.                    mrModel.dirty = true;
250. 
251.                    mrModel.SubItemSerialId = null;
252.                    mrModel.SubItemSerialNumber = null;
253. 
254.                    //var serialDropDown = ee.sender.element.parent().parent().parent().find('.sub-item-serial').find('input').data('kendoComboBox');
255.                    var serialDropDown = ee.sender.element.parent().parent().parent().find('.sub-item-serial').find('input[data-role=combobox]').data('kendoComboBox');
256.                    serialDropDown.dataSource.read();
257.                    serialDropDown.select(0);
258.                }
259.            });
260. 
261. 
262.        $('<input required data-text-field="Description" data-value-field="ItemSerialId" />')
263.            .appendTo(subItemSerialContainer)
264.            .kendoComboBox({
265.                enable: self.IS_EDITABLE,
266.                text: mrModel.SubItemSerialNumber,
267.                value: mrModel.SubItemSerialId,
268.                filter: "contains",
269.                autoBind: true,
270.                dataTextField: "Description",
271.                dataValueField: "ItemSerialID",
272.                optionLabel: { Description: "", ItemSerialID: 0 },
273.                //optionLabel: { Description: GridCommon.emptyText, ItemSerialID: 0 },
274.                //dataBound: function (ee) {
275.                //    this.value(0);
276.                //    if (this.dataSource.data().length === 0) {
277.                //        this.enable(false);
278.                //        this.text("No items found");
279.                //        console.log("no items")
280.                //    } else {
281.                //        console.log('has ' + this.dataSource.data().length + ' serials.')
282.                //        this.enable(true);
283.                //        this.text(GridCommon.emptyText);
284.                //    }
285.                //},
286.                dataSource: {
287.                    transport: {
288.                        read: {
289.                            url: GridCommon.ITEMS_HANDLER_URL + "/GetSerials",
290.                            dataType: "json",
291.                            type: "GET",
292.                            data: function () {
293.                                console.log("Reading serials for subItemId = " + mrModel.SubItemName);
294.                                return {
295.                                    itemid: mrModel.SubItemId,
296.                                    exclude_List: "0"
297.                                };
298.                            }
299.                        }
300.                    },
301. 
302.                    error: GridCommon.showCallBackError
303.                },
304.                change: function (ee) {
305.                    var newItem = ee.sender.dataItem();
306.                    if (!newItem) {
307.                        return;
308.                    }
309.                    mrModel.SubItemSerialId = newItem.ItemSerialID;
310.                    mrModel.SubItemSerialNumber = newItem.Description;
311.                    mrModel.dirty = true;
312.                }
313.            });
314.    }
315.}
If there are any obvious lines I can change to make things better, then please let me know.
Tags
Grid
Asked by
Shea
Top achievements
Rank 1
Answers by
Petur Subev
Telerik team
Shea
Top achievements
Rank 1
Share this question
or