Telerik Forums
Kendo UI for jQuery Forum
10 answers
388 views

Hey,

 

I'm working on a web-app that utilizes Kendo UI Grid & AngularJS.

I'm not trying to do anything crazy, just basic use of displaying results in a grid.

In my testing environment, I load approx 1,800 rows, 11 columns (the loading process loads all rows at once, no client/server paging - just saying ;)).

Once the data is loaded onto the grid, the app becomes unusable, everything is practically frozen. 

 

Are there any known performance issues? are there any guidelines I should follow using Kendo UI Grid  + AngularJS?

I noticed the javascript memory of the app starts at 220M and rising constantly when trying to filter/sort/etc'.

 

In anyway, here's the code for the controller.

Would appreciate the help.

001.define(['app'], function(app) {
002.    app.controller('MainCtrl', function ($scope, $http, $compile, $routeParams, $modal, $timeout, $q, MainService, LoginService) {
003. 
004.        /* ========================================== */
005.        /*           GENERAL INITIALIZATIONS          */
006.        /* ========================================== */
007. 
008.        // Set the culture
009.        kendo.culture("he-IL");
010. 
011.        // Define scope variables
012.        $scope.VM = {};
013.        $scope.VM.isInitialized = false;
014.        $scope.VM.filter = {};
015.        $scope.VM.editor = {};
016.        $scope.VM.collections = {};
017.        $scope.VM.kendoGrid = null;
018. 
019.        // Define the view permissions
020.        $scope.VM.permissions = {
021.            allow_edit: true,
022.            allow_sign: true,
023.            allow_cancel: true
024.        };
025. 
026.        /* ========================================== */
027.        /*        INITIALIZING THE COLLECTIONS        */
028.        /* ========================================== */
029. 
030.        /* The list of all suppliers */
031.        $scope.VM.getSuppliers = function() {
032.            MainService.getSuppliers().then(function(data) {
033.                var suppliers = [];
034.                data.forEach(function (supplier) {
035.                    suppliers.push({ value: supplier.name, text: supplier.name});
036.                });
037.                $scope.VM.collections.suppliers = suppliers;
038.            });
039.        } ();
040.        $scope.VM.collections.suppliers = [];
041.        /* The list of all expensesCause */
042.        $scope.VM.getExpensesCause = function() {
043.            MainService.getExpensesCause().then(function(data) {
044.                var expenses_cause = [];
045.                data.forEach(function (cause) {
046.                    expenses_cause.push({ value: cause.expense_name, text: cause.expense_name});
047.                });
048.                $scope.VM.collections.expensesCause = expenses_cause;
049.            });
050.        } ();
051.        $scope.VM.collections.expensesCause = [];
052.        /* The list of all subExpensesCause */
053.        $scope.VM.getSubExpensesCause = function() {
054.            MainService.getSubExpensesCause().then(function(data) {
055.                var sub_expenses_cause = [];
056.                data.forEach(function (cause) {
057.                    sub_expenses_cause.push({ value: cause.sub_expense_name, text: cause.sub_expense_name});
058.                });
059.                $scope.VM.collections.subExpensesCause = sub_expenses_cause;
060.            });
061.        } ();
062.        $scope.VM.collections.subExpensesCause = [];
063. 
064.        /* ========================================== */
065.        /*      INITIALIZING THE DEFAULT FILTER       */
066.        /* ========================================== */
067. 
068.        $scope.VM.filter.status = "active";
069.        $scope.VM.filter.from_date = moment().subtract(2, "month").toDate();
070.        $scope.VM.filter.to_date = moment().toDate();
071. 
072.        /* ========================================== */
073.        /*            INITIALIZING THE GRID           */
074.        /* ========================================== */
075. 
076.        $scope.VM.dataSource = new kendo.data.DataSource({
077.            schema: {
078.                model: {
079.                    // TODO: change id to date_created:id
080.                    id: "date_created_id",
081.                    fields: {
082.                        date_created: {
083.                            editable: false,
084.                            type: "date"
085.                        },
086.                        project_name: {
087.                            editable: false
088.                        },
089.                        supplier_name: {
090.                            editable: true,
091.                            validation: {
092.                                required: true
093.                            }
094.                        },
095.                        info: {
096.                            editable: true
097.                        },
098.                        expense_cause: {
099.                            editable: true,
100.                            nullable: true
101.                        },
102.                        sub_expense_cause: {
103.                            editable: true,
104.                            nullable: true
105.                        },
106.                        cheque_number: {
107.                            editable: false
108.                        },
109.                        amount: {
110.                            editable: false
111.                        },
112.                        sig1: {
113.                            editable: false
114.                        },
115.                        sig2: {
116.                            editable: false
117.                        },
118.                        cheque_status: {
119.                            editable: false
120.                        }
121.                    }
122.                },
123.                data: "data"
124.            },
125.            //serverPaging: true,
126.            //serverSorting: true,
127.            autoSync: true,
128.            transport: {
129.                read: function(e) {
130.                    // Save the 'e' for future reference
131.                    $scope.VM.readOptions = e;
132. 
133.                    // Start the spinner
134.                    kendo.ui.progress($("div[kendo-grid]"), true);
135. 
136.                    var from_date = $scope.VM.filter.from_date;
137.                    var to_date = $scope.VM.filter.to_date;
138.                    MainService.getCheques(from_date, to_date).then(function(data) {
139.                        e.success(data);
140. 
141.                        // Stop the spinner
142.                        kendo.ui.progress($("div[kendo-grid]"), false);
143.                    });
144.                },
145.                update: function(e) {
146.                    // Save the 'e' for future reference
147.                    $scope.VM.updateOptions = e;
148. 
149.                    MainService.updateCheque(e.data).then(function(data) {
150.                        e.success(data);
151.                    });
152.                },
153.                create: function(e) {
154.                    // Save the 'e' for future reference
155.                    $scope.VM.insertOptions = e;
156. 
157.                    MainService.addCheque(e.data).then(function(data) {
158.                        e.success(data);
159.                    });
160.                },
161.                destroy: function(e) {
162. 
163.                }
164.            },
165.            aggregate: [
166.                { field: "amount", aggregate: "sum" }
167.            ],
168.        });
169.        $scope.VM.projectDS = new kendo.data.DataSource({
170.            data: []
171.        });
172.        $scope.VM.supplierDS = new kendo.data.DataSource({
173.            data: []
174.        });
175.        $scope.VM.infoDS = new kendo.data.DataSource({
176.            data: []
177.        });
178.        $scope.VM.expenseCauseDS = new kendo.data.DataSource({
179.            data: []
180.        });
181.        $scope.VM.subExpenseCauseDS = new kendo.data.DataSource({
182.            data: []
183.        });
184.        $scope.VM.chequeNumberDS = new kendo.data.DataSource({
185.            data: []
186.        });
187.        $scope.VM.amountDS = new kendo.data.DataSource({
188.            data: []
189.        });
190. 
191.        /* The grid definition */
192.        $scope.VM.gridOptions = {
193.            height: 630,
194.            filterable: {
195.                mode: "row",
196.                operators: {
197.                    string: {
198.                        eq: "שווה ",
199.                        neq: "לא שווה",
200.                        startswith: "מתחיל ב",
201.                        contains: "מכיל",
202.                        doesnotcontain: "לא מכיר",
203.                        endswith: "מסתיים ב"
204.                    }
205.                }
206.            },
207.            scrollable: true,
208.            sortable: true,
209.            selectable: "multiple, row",
210.            editable: true,
211.            resizable: true,
212.            reorderable: true,
213.            //groupable: true,
214.            toolbar: [
215.                { name: "excel", text: " ייצוא לאקסל" },
216.                //{ name: "save", text: "שמור"}
217.            ],
218.            excel: { fileName: "results.xlsx" },
219.            dataSource: $scope.VM.dataSource,
220.            columns: [
221.                //{ field: "cheque_id", title: "מזהה צ'ק" },
222.                //{
223.                //    headerTemplate: "<input type='checkbox' class='checkbox checkAll' ng-click='VM.selectAll($event)' />",
224.                //    template: "<input type='checkbox' class='checkbox checkRow' ng-click='VM.selectRow($event)' />",
225.                //    width: "26px"
226.                //},
227.                {
228.                    field: "date_created",
229.                    title: "תאריך",
230.                    template: "<div ng-bind='dataItem.date_created | date: \"dd/MM/yyyy\"' title='{{ dataItem.date_created | date: \"dd/MM/yyyy\" }}'></div>",
231.                    filterable: false
232.                },
233.                {
234.                    field: "project_name",
235.                    title: "פרויקט",
236.                    template: "<div ng-bind='dataItem.project_name' title='{{ dataItem.project_name }}'></div>",
237.                    filterable: {
238.                        cell: {
239.                            dataSource: $scope.VM.dataSource,
240.                            operator: "contains"
241.                        }
242.                    }
243.                },
244.                {
245.                    field: "supplier_name",
246.                    title: "מוטב",
247.                    template: "<div ng-bind='dataItem.supplier_name' title='{{ dataItem.supplier_name }}'></div>",
248.                    filterable: {
249.                        cell: {
250.                            dataSource: $scope.VM.dataSource,
251.                            operator: "contains"
252.                        }
253.                    },
254.                    editor: function(container, options) {
255.                        //container.append(
256.                        //    "<select kendo-combo-box "+
257.                        //        "k-data-text-field=\"'text'\" "+
258.                        //        "k-data-value-field=\"'value'\" "+
259.                        //        "k-filter='contains' "+
260.                        //        "k-auto-bind='false' "+
261.                        //        "k-data-source='VM.collections.suppliers' "+
262.                        //        "data-bind='value:"+options.field+"'>"+
263.                        //    "</select>");
264.                        container.append(
265.                            "<input kendo-auto-complete " +
266.                                "k-data-text-field=\"'text'\" "+
267.                                "k-data-value-field=\"'value'\" "+
268.                                "k-auto-bind='false' "+
269.                                "k-value-primitive='true' "+
270.                                "k-data-source='VM.collections.suppliers' "+
271.                                "data-bind='value:"+options.field+"'/>");
272.                    }
273.                },
274.                {
275.                    field: "info",
276.                    title: "פרטים" ,
277.                    template: "<div ng-bind='dataItem.info' title='{{ dataItem.info }}'></div>",
278.                    filterable: {
279.                        cell: {
280.                            dataSource: $scope.VM.dataSource,
281.                            operator: "contains"
282.                        }
283.                    },
284.                    width: "250px"
285.                },
286.                {
287.                    field: "expense_cause",
288.                    title: "סעיף הוצאה",
289.                    template: "<div ng-bind='dataItem.expense_cause' title='{{ dataItem.expense_cause }}'></div>",
290.                    filterable: {
291.                        cell: {
292.                            dataSource: $scope.VM.dataSource,
293.                            operator: "contains"
294.                        }
295.                    },
296.                    editor: function(container, options) {
297.                        //container.append(
298.                        //    "<select kendo-combo-box "+
299.                        //        "k-data-text-field=\"'text'\" "+
300.                        //        "k-data-value-field=\"'value'\" "+
301.                        //        "k-filter='contains' "+
302.                        //        "k-auto-bind='false' "+
303.                        //        "k-data-source='VM.collections.expensesCause' "+
304.                        //        "data-bind='value:"+options.field+"'>"+
305.                        //    "</select>");
306.                        container.append(
307.                            "<input kendo-auto-complete " +
308.                                "k-data-text-field=\"'text'\" "+
309.                                "k-data-value-field=\"'value'\" "+
310.                                "k-auto-bind='false' "+
311.                                "k-value-primitive='true' "+
312.                                "k-data-source='VM.collections.expensesCause' "+
313.                                "k-rebind='VM.collections.expensesCause' "+
314.                                "data-bind='value:"+options.field+"'/>");
315.                    }
316.                },
317.                {
318.                    field: "sub_expense_cause",
319.                    title: "תת סעיף הוצאה",
320.                    template: "<div ng-bind='dataItem.sub_expense_cause' title='{{ dataItem.sub_expense_cause }}'></div>",
321.                    filterable: {
322.                        cell: {
323.                            dataSource: $scope.VM.dataSource,
324.                            operator: "contains"
325.                        }
326.                    },
327.                    editor: function(container, options) {
328.                        //container.append(
329.                        //    "<select kendo-combo-box "+
330.                        //        "k-data-text-field=\"'text'\" "+
331.                        //        "k-data-value-field=\"'value'\" "+
332.                        //        "k-filter='contains' "+
333.                        //        "k-auto-bind='false' "+
334.                        //        "k-data-source='VM.collections.subExpensesCause' "+
335.                        //        "data-bind='value:"+options.field+"'>"+
336.                        //    "</select>");
337.                        container.append(
338.                            "<input kendo-auto-complete " +
339.                                "k-data-text-field=\"'text'\" "+
340.                                "k-data-value-field=\"'value'\" "+
341.                                "k-auto-bind='false' "+
342.                                "k-value-primitive='true' "+
343.                                "k-data-source='VM.collections.subExpensesCause' "+
344.                                "k-rebind='VM.collections.subExpensesCause' "+
345.                                "data-bind='value:"+options.field+"'/>");
346.                    }
347.                },
348.                {
349.                    field: "cheque_number",
350.                    title: "מספר צ'ק",
351.                    template: "<div ng-bind='dataItem.cheque_number' title='{{ dataItem.cheque_number }}'></div>",
352.                    filterable: {
353.                        cell: {
354.                            dataSource: $scope.VM.dataSource,
355.                            operator: "startswith"
356.                        }
357.                    }
358.                },
359.                {
360.                    field: "amount",
361.                    title: "סכום" ,
362.                    template: "<div ng-bind='dataItem.amount | currency: \"₪\"' title='{{ dataItem.amount | currency: \"₪\" }}'></div>",
363.                    format: "{0:c0}",
364.                    footerTemplate: "<div>{{ translation.TEXT_AMOUNT_SUM }}: #= kendo.toString(sum, 'c0') #</div>",
365.                    width: "180px"
366.                },
367.                {
368.                    field: "sig1",
369.                    title: "חתימה 1",
370.                    template: function(dataItem) {
371.                        var template;
372.                        var chequeId = dataItem.uid;
373. 
374.                        // TODO: need to convert date from string to actual date
375. 
376.                        template =  "<div ng-mouseover=\"(loggedInUser.signer == 1) && VM.showQuickSign(1, '"+chequeId+"')\" ng-mouseleave=\"(loggedInUser.signer == 1) && VM.hideQuickSign(1, '"+chequeId+"')\" title=\"{{ (dataItem.sig1_signAt) ? ((convertStringToDate(dataItem.sig1_signAt)) | date: 'HH:mm:ss dd/MM/yyyy') : '' }}\">" +
377.                                        "{{ dataItem.sig2_user || ' ' }}" +
378.                                        "<div class='quicksign bubble bubble-sig1-"+ chequeId +" bottom'>" +
379.                                            "<div class='quicksign-user'>{{ loggedInUser.full_name }}</div>" +
380.                                            "<div class='quicksign-amount'>{{ dataItem.amount | currency: '₪' }}</div>" +
381.                                            "<div class='quicksign-sign' ng-show='VM.isAllowSign() && !VM.isSigned(this.dataItem)'><button class='k-button' ng-click='VM.sign(this.dataItem)'>{{ translation.CMD_SIGN }}</button></div>" +
382.                                            "<div class='quicksign-unsign' ng-show='VM.isAllowSign() && VM.isSigned(this.dataItem)'><button class='k-button' ng-click='VM.unsign(this.dataItem)'>{{ translation.CMD_UNSIGN }}</button></div>" +
383.                                        "</div>" +
384.                                    "</div>";
385. 
386.                        return template;
387.                    },
388.                    filterable: false
389.                },
390.                {
391.                    field: "sig2",
392.                    title: "חתימה 2",
393.                    template: function(dataItem) {
394.                        var template;
395.                        var chequeId = dataItem.uid;
396. 
397.                        // TODO: need to convert date from string to actual date
398. 
399.                        template =  "<div ng-mouseover=\"(loggedInUser.signer == 2) && VM.showQuickSign(2, '"+chequeId+"')\" ng-mouseleave=\"(loggedInUser.signer == 2) && VM.hideQuickSign(2, '"+chequeId+"')\" title=\"{{ (dataItem.sig2_signAt) ? ((convertStringToDate(dataItem.sig2_signAt)) | date: 'HH:mm:ss dd/MM/yyyy') : '' }}\">" +
400.                                        "{{ dataItem.sig2_user || ' ' }}" +
401.                                        "<div class='quicksign bubble bubble-sig2-"+ chequeId +" bottom'>" +
402.                                            "<div class='quicksign-user'>{{ loggedInUser.full_name }}</div>" +
403.                                            "<div class='quicksign-amount'>{{ dataItem.amount | currency: '₪' }}</div>" +
404.                                            "<div class='quicksign-sign' ng-show='VM.isAllowSign() && !VM.isSigned(this.dataItem)'><button class='k-button' ng-click='VM.sign(this.dataItem)'>{{ translation.CMD_SIGN }}</button></div>" +
405.                                            "<div class='quicksign-unsign' ng-show='VM.isAllowSign() && VM.isSigned(this.dataItem)'><button class='k-button' ng-click='VM.unsign(this.dataItem)'>{{ translation.CMD_UNSIGN }}</button></div>" +
406.                                        "</div>" +
407.                                    "</div>";
408. 
409.                        return template;
410.                    },
411.                    filterable: false
412.                },
413.                {
414.                    field: "cheque_status",
415.                    title: "סטאטוס",
416.                    template: function(dataItem) {
417.                        var result = "";
418.                        var status = $scope.translationAPI.translateStatus(dataItem.cheque_status);
419.                        var css_class = dataItem.cheque_status;
420. 
421.                        result += "<div title='"+status+"' class='"+css_class+"'>";
422.                        result += status;
423.                        result += "</div>";
424. 
425.                        return result;
426.                    },
427.                    filterable: false
428.                }
429.            ],
430. 
431.            // Events
432.            dataBound: function(e) {
433.                $scope.VM.isInitialized = true;
434.            }
435.        };
436. 
437.        /* ========================================== */
438.        /*                  Methods                   */
439.        /* ========================================== */
440. 
441.        ///////////////////////////////////// Common
442.        // Gets a reference to the grid
443.        $scope.VM.getKendoGrid = function() {
444.            if (!$scope.VM.kendoGrid) {
445.                var grid = $("div[kendo-grid]");
446.                $scope.VM.kendoGrid = grid.getKendoGrid();
447.            }
448. 
449.            return $scope.VM.kendoGrid;
450.        };
451. 
452.        ///////////////////////////////////// Permissions
453.        // Check if the user is allowed to sign
454.        $scope.VM.isAllowSign = function() {
455.            return $scope.VM.permissions.allow_sign;
456.        };
457.        // Check if the user is allowed to unsign
458.        $scope.VM.isAllowUnSign = function() {
459.            return $scope.VM.permissions.allow_sign;
460.        };
461.        // Check if the user is allowed to edit existing items
462.        $scope.VM.isAllowEdit = function() {
463.            return $scope.VM.permissions.allow_edit;
464.        };
465.        // Check if the user is allowed to add new items
466.        $scope.VM.isAllowAdd = function() {
467.            return $scope.VM.permissions.allow_edit;
468.        };
469.        // Check if the user is allowed to cancel cheques
470.        $scope.VM.isAllowCancel = function() {
471.            return $scope.VM.permissions.allow_cancel;
472.        };
473. 
474.        ///////////////////////////////////// Helper methods
475.        // Check if at-least one row selected
476.        $scope.VM.isEntitySelected = function() {
477.            return ($scope.VM.getSelectedRowsCount() > 0);
478.        };
479.        // Check if exactly one row selected
480.        $scope.VM.isOneEntitySelected = function() {
481.            return ($scope.VM.getSelectedRowsCount() == 1);
482.        };
483.        // Check if the cheque is already signed
484.        $scope.VM.isSigned = function(dataItem) {
485.            if ($scope.loggedInUser.signer == 1)
486.                return dataItem.sig1_user && dataItem.sig1_signAt;
487.            else if ($scope.loggedInUser.signer == 2)
488.                return dataItem.sig2_user && dataItem.sig2_signAt;
489.            else
490.                return false;
491.        };
492.        // Get the number of rows in the grid
493.        $scope.VM.getRowsCount = function() {
494.            var isInitialized = $scope.VM.isInitialized;
495.            if (!isInitialized)
496.                return 0;
497. 
498.            var grid = $scope.VM.getKendoGrid();
499.            if (!grid)
500.                return 0;
501. 
502.            var results = grid.dataItems();
503.            if (!results)
504.                return 0;
505. 
506.            return results.length;
507.        };
508.        // Get the number of selected rows from the grid
509.        $scope.VM.getSelectedRowsCount = function() {
510.            var isInitialized = $scope.VM.isInitialized;
511.            if (!isInitialized)
512.                return 0;
513. 
514.            var grid = $scope.VM.getKendoGrid();
515.            if (!grid)
516.                return 0;
517. 
518.            var results = grid.select();
519.            if (!results)
520.                return 0;
521. 
522.            return results.length;
523.        };
524.        // Get the selected row
525.        $scope.VM.getSelectedRow = function() {
526.            var grid = $scope.VM.getKendoGrid();
527.            if (!grid)
528.                return;
529. 
530.            var results = grid.select();
531.            if (!results)
532.                return;
533. 
534.            return grid.dataItem(results[0]);
535.        };
536.        // Get the number of results by statys
537.        $scope.VM.getStatusCount = function(status) {
538.            var grid = $scope.VM.getKendoGrid();
539.            if (!grid)
540.                return;
541. 
542.            var results = grid.dataSource.data();
543.            if (!results)
544.                return;
545. 
546.            var count = 0;
547.            if (status === "all") {
548.              count = results.length;
549.            } else if (status === "active") {
550.                angular.forEach(results, function(value,key) {
551.                    if (value.is_canceled == "N")
552.                        count++;
553.                });
554.            } else {
555.                angular.forEach(results, function(value,key) {
556.                    if (value.cheque_status == status)
557.                        count++;
558.                });
559.            }
560. 
561.            return count;
562.        };
563. 
564.        ///////////////////////////////////// Commands
565.        // Opens the entity detail view
566.        $scope.VM.openEntityModal = function(state) {
567.            var instance = $modal.open({
568.                templateUrl: 'addNewModal.html',
569.                controller: 'AddNewCtrl',
570.                size: 'lg',
571.                resolve: {
572.                    entity: function(){
573.                        var grid = $scope.VM.getKendoGrid();
574.                        var results = grid.select();
575.                        return grid.dataItem(results[0]);
576.                    },
577.                    state: function() {
578.                        return state;
579.                    },
580.                    translation: function() {
581.                        return $scope.translation;
582.                    },
583.                    translationAPI: function() {
584.                        return $scope.translationAPI;
585.                    },
586.                    permissions: function() {
587.                        return $scope.VM.permissions;
588.                    },
589.                    loggedInUser: function() {
590.                        return $scope.loggedInUser;
591.                    }
592.                }
593.            });
594. 
595.            instance.result.then(function(entity) {
596.                if (entity) {
597.                    if (state) {
598.                        $scope.VM.addNew(entity);
599.                    }
600.                    else {
601.                        $scope.VM.update(entity);
602.                    }
603. 
604.                    // Save the changes
605.                    $scope.VM.dataSource.sync();
606.                }
607.            });
608.        };
609.        // Add a new entity
610.        $scope.VM.addNew = function(entity){
611.            $scope.VM.dataSource.add(entity)
612.        };
613.        // Update the entity
614.        $scope.VM.update = function(entity){
615. 
616.        };
617.        // Sign a cheque
618.        $scope.VM.sign = function(dataItem) {
619.            if ($scope.loggedInUser.signer == 1) {
620.                dataItem.sig1_user = $scope.loggedInUser.full_name;
621.                dataItem.sig1_signAt = moment().toDate();
622.            }
623.            else {
624.                dataItem.sig2_user = $scope.loggedInUser.full_name;
625.                dataItem.sig2_signAt = moment().toDate();
626.            }
627. 
628.            // Save the changes
629.            $scope.VM.dataSource.sync();
630.        };
631.        // Sign all selected cheques
632.        $scope.VM.signAll = function() {
633.            var isInitialized = $scope.VM.isInitialized;
634.            if (!isInitialized)
635.                return;
636. 
637.            var grid = $scope.VM.getKendoGrid();
638.            if (!grid)
639.                return;
640. 
641.            var results = grid.select();
642.            if (!results)
643.                return;
644. 
645.            for (i=0; i<results.length; i++) {
646.                $scope.VM.sign(grid.dataItem(results[i]));
647.            }
648.        };
649.        // Sign a cheque
650.        $scope.VM.unsign = function(dataItem) {
651.            if ($scope.loggedInUser.signer == 1) {
652.                dataItem.sig1_user = "";
653.                dataItem.sig1_signAt = "";
654.            }
655.            else {
656.                dataItem.sig2_user = "";
657.                dataItem.sig2_signAt = "";
658.            }
659. 
660.            // Save the changes
661.            $scope.VM.dataSource.sync();
662.        };
663.        // Sign all selected cheques
664.        $scope.VM.unsignAll = function() {
665.            var isInitialized = $scope.VM.isInitialized;
666.            if (!isInitialized)
667.                return;
668. 
669.            var grid = $scope.VM.getKendoGrid();
670.            if (!grid)
671.                return;
672. 
673.            var results = grid.select();
674.            if (!results)
675.                return;
676. 
677.            for (i=0; i<results.length; i++) {
678.                $scope.VM.unsign(grid.dataItem(results[i]));
679.            }
680.        };
681.        // Cancel the cheque
682.        $scope.VM.cancelAction = function(entity) {
683.            var entity = $scope.VM.getSelectedRow();
684. 
685.            entity.is_canceled = "Y";
686. 
687.            /* Send the new entity to the server for cancel */
688.            MainService.modifyCancellation(entity).then(function(data) {
689. 
690.            });
691.        };
692.        // Undo canceled cheque
693.        $scope.VM.undoCancelAction = function(entity) {
694.            var entity = $scope.VM.getSelectedRow();
695. 
696.            entity.is_canceled = "N";
697. 
698.            /* Send the new entity to the server for cancel */
699.            MainService.modifyCancellation(entity).then(function(data) {
700. 
701.            });
702.        };
703.        // Get all cheques from within the dates range
704.        $scope.VM.getCheques = function(e) {
705.            $scope.VM.dataSource.read($scope.VM.readOptions);
706.        };
707.        // Refresh the data, if any changes has been made
708.        var _chequeFlowInProgress = false;
709.        $scope.VM.getChequesFlow = function() {
710.            (function tick() {
711.                var project = $scope.VM.filter.project || "";
712.                var from_date = $scope.VM.filter.from_date;
713.                var to_date = $scope.VM.filter.to_date;
714. 
715.                if (_chequeFlowInProgress)
716.                    return;
717. 
718.                MainService.getChequesFlow(project, from_date, to_date).then(function(data) {
719.                    _chequeFlowInProgress = true;
720. 
721.                    var index, jndex;
722.                    for (index=0; index<data.length; index++) {
723.                        var action = data[index].type;
724.                        var flag = false;
725. 
726.                        var grid = $scope.VM.getKendoGrid();
727.                        if (!grid)
728.                            return;
729. 
730.                        var results = grid.dataItems();
731.                        if (!results)
732.                            return;
733. 
734.                        for (jndex=0; jndex<results.length && !flag; jndex++){
735.                            var currRow = results[jndex];
736.                            switch (action) {
737.                                case "update": {
738.                                    if (data[index]["date_created:id"] == currRow["date_created:id"]) {
739.                                        currRow.action = data[index].action;
740.                                        currRow.project_name = data[index].project_name;
741.                                        currRow.expense_cause = data[index].expense_cause;
742.                                        currRow.sub_expense_cause = data[index].sub_expense_cause;
743.                                        currRow.info = data[index].info;
744.                                        currRow.supplier_name = data[index].supplier_name;
745.                                        currRow.supplier_address = data[index].supplier_address;
746.                                        currRow.amount = data[index].amount;
747.                                        currRow.cheque_number = data[index].cheque_number;
748.                                        currRow.date_payment = data[index].date_payment;
749.                                        currRow.sig1_user = data[index].sig1_user;
750.                                        currRow.sig1_signAt = data[index].sig1_signAt;
751.                                        currRow.sig2_user = data[index].sig2_user;
752.                                        currRow.sig2_signAt = data[index].sig2_signAt;
753.                                        currRow.cheque_status = data[index].cheque_status;
754.                                        currRow.date_created = data[index].date_created;
755.                                        currRow.date_uploaded = data[index].date_uploaded;
756.                                        currRow.date_updated = data[index].date_updated;
757.                                        currRow.tax_deduction_percentage = data[index].tax_deduction_percentage;
758.                                        currRow.tax_deduction_sum = data[index].tax_deduction_sum;
759.                                        currRow.is_canceled = data[index].is_canceled;
760.                                        currRow.date_canceled = data[index].date_canceled;
761. 
762.                                        // Mark iteration as completed
763.                                        flag = true;
764.                                    }
765.                                    break;
766.                                }
767.                                case "insert": {
768.                                    if (data[index]["date_created:id"] == currRow["date_created:id"]) {
769.                                        // Mark iteration as completed
770.                                        flag = true;
771.                                    }
772.                                    break;
773.                                }
774.                                default: {
775.                                    if (action)
776.                                        console.error("Can't load entity from flow, unknown state '"+action+"'");
777.                                    else
778.                                        console.error("Can't load entity from flow, the 'type' is missing");
779.                                }
780.                            }
781.                        }
782. 
783.                        if (!flag) {
784.                            if (action == "insert") {
785.                                // TODO: insert the item to the grid
786.                                grid.dataSource.add(data[index]);
787.                            }
788.                        }
789.                    };
790. 
791.                    _chequeFlowInProgress = false;
792.                });
793. 
794.                var timer = $timeout(tick, 1000);
795.                $scope.$on("$destroy", function(event) {
796.                    $timeout.cancel(timer);
797.                });
798.            })();
799.        }();
800. 
801.        ///////////////////////////////////// Presentation
802.        // Responsible for filtering the grid by the status field
803.        $scope.VM.changeStatus = function(e, status) {
804.            e.preventDefault();
805. 
806.            $scope.VM.filter.status = status;
807.            switch (status) {
808.                case "all": {
809.                    $scope.VM.dataSource.filter({} );
810.                    break;
811.                }
812.                case "active": {
813.                    $scope.VM.dataSource.filter({ field: "is_canceled", operator: "eq", value: "N"} );
814.                    break;
815.                }
816.                case "unsigned":
817.                case "pending":
818.                case "signed": {
819.                    $scope.VM.dataSource.filter({ field: "cheque_status", operator: "eq", value: status} );
820.                    break;
821.                }
822.            }
823.        };
824.        // Save the position of the mouse
825.        $(document).mousemove(function(e) {
826.            window.x = e.pageX;
827.            window.y = e.pageY;
828.        });
829.        // Show the quicksign panel
830.        $scope.VM.showQuickSign = function(sig, chequeId) {
831.            var handle = $(".bubble-sig"+sig+"-"+chequeId);
832.            var isVisible = $(".bubble-sig"+sig+"-"+chequeId+":visible");
833. 
834.            if (isVisible.length > 0)
835.                return;
836. 
837.            var grid = $("div[kendo-grid]");
838.            var gridHalfPosition = grid.offset().top + (grid.height() / 2);
839. 
840.            if (window.y < gridHalfPosition) {
841.                handle.removeClass("bottom");
842.                handle.addClass("top");
843.            }
844.            else {
845.                handle.removeClass("top");
846.                handle.addClass("bottom");
847.            }
848. 
849.            handle.show();
850.        };
851.        // Hide the quicksign panel
852.        $scope.VM.hideQuickSign = function(sig, chequeId) {
853.            var handle = $(".bubble-sig"+sig+"-"+chequeId);
854.            handle.hide();
855.        };
856.    });
857. 
858.});

T. Tsonev
Telerik team
 answered on 13 May 2015
1 answer
297 views

Hey,

Got a problem with the scheduler when updating events via the drag and drop functionality which is replicable on the this demo - http://demos.telerik.com/kendo-ui/scheduler/move-resize

 

If you try move an event with multiple series and select "Do it for entire series". It will then remove all of the other events.

 

My problem is very similar, I have a scheduler with a list of attendees, an event can have multiple attendees but when dragging and dropping the scheduler only passes 1 attendee.

 

I'm not sure how to fix this problem so any help would be much appreciated.

Thanks

Vladimir Iliev
Telerik team
 answered on 13 May 2015
1 answer
116 views

I am using a multi select to display products a client have and want him/her to be able to select from all available products. The problem is, Only when I specify the collection of user's products in MultiSelectFor(m=>m.Products) and also .BindFor(Model.Products), only then I get the list of products selected in the multiselect. Bu I want MultiSelectFor(m=>m.Products) where products contains all user's products and when I call an action method, I want that property to contain the updated product list, i,e products currently selected in the Multiselect, i,e a user can remove or add to the products in the Products collection.

Georgi Krustev
Telerik team
 answered on 13 May 2015
1 answer
220 views

For a few reasons, we do not use the built in templates, we use our own modals.  This is working just fine, except for recurring events.  I can create them just fine, except for two issues:

 

1) if i create an event with an id, it throws an error

2) if i create without an id, it saves, but only the first instance is considered recurring, the rest show up, but are not considered recurring.

A simple dojo, i believe copied from an example here:

http://dojo.telerik.com/@TrikinCurt/atoZU

Vladimir Iliev
Telerik team
 answered on 13 May 2015
5 answers
589 views

Hi Guys

Sorry , new to this drag and drop stuff!

 

How do I get KendoDraggable for dragging just the column Header in a Grid?

 I found a fiddle  Original Fiddlefor dragging the table rows to a target.. the kendoDraggable is like this.

$("tr", grid.tbody).kendoDraggable({
  hint: function (e) {
    var item = $('<div class="k-grid k-widget" style="background-color: lightblue; color: black;"><table><tbody><tr>' + e.html() + '</tr></tbody></table></div>');
    return item;
  }
});

 

 Original Fiddle

 So I tried changing this to 

$("tr", grid.thead).kendoDraggable({
  hint: function (e) {
    var item = $('<div class="k-link" style="background-color: lightblue; color: black;"><table><thead><tr>' + e.html() + '</tr></thead></table></div>');
    return item;
  }

 

My Attempt Fiddle

But this drags all the text from all the Column headers.  I just want to know the column that they dragged to the target.

I'm not sure what data I can get on the drop.. text and maybe the column index or something?

 

Many thanks

 

Rob

Rob
Top achievements
Rank 2
Iron
Veteran
Iron
 answered on 12 May 2015
33 answers
232 views
Anyone using KendoUI mobile listview to build an app running on the three major device types? (iOS, Android, Windows Phone 8.x)

At the moment we are frustrated about the poor Windows Phone 8.x performance. The listview is pretty much unuseable. Terrible slow scrolling. No feedback on pressed rows an so on. 

We are using version of KendoUI. (2014.2.716)

The only device where it runs perfect is an iPhone. But if we only want to target iOS devices, we would go for a native application! ;-)
Constantinos Petridis
Top achievements
Rank 2
Iron
Iron
 answered on 12 May 2015
17 answers
728 views

Hi,

I was told to ask here. Enums seem not to be supported by kendo's datasource in conjunction with OData v4 and MVC.

E.g. if I have a nullable enum property on an entity, the following issues arise:

1) The grid won't display values for such types.

2) When editing or adding new records, the datasource becomes confused and sends always the value null to the server.

Workaround:

(told me by one of Telerik's supporters today)

a) Define as foreign key to a list of enum-name/display: E.g.: columns.ForeignKey(m => m.Gender, PickItemsHelper.ToSelectList<PersonGender>(includeNull: true, useNames: true));

b) Define as of type string in the schema -> model : model.Field("Gender", typeof(string));

 

This now works for (1) and (2). I consider this a temporary workaround for a non-implemented part of the OData v4 spec.

However, when applying the workaround an additional issue pops up:

3) When explicitly selecting the null value (i.e. when we have a nullable enum), the datasource now sends an empty string to the server, which rejects the request as invalid because it expects either an enum name or null.

 

Any clues how to work around issue (3)?

 

Best regards,

Kasimier Buchcik

Rosen
Telerik team
 answered on 12 May 2015
1 answer
123 views

I'm trying to work off the diagram sample app, it fits exactly what I need. However, what I need to do is add text to the shapes.

I'm having trouble figuring out how to add text to the shape objects as this is my first time using Kendo UI. Do I need to edit the kendo-all-min-js file or is this something I do on the html file?

 Any direction is much appreciated.

 

Thanks,

Daniel
Telerik team
 answered on 12 May 2015
1 answer
91 views

Hi.

I'm using "Drawing" API to generate PDF from HTML and I saw there are some limitations to use this API. Like the below.

"The content of the following elements is not rendered: <iframe>, <svg>, <input>, <textarea>, <select>." 

But I really need to render these elements above in PDF, actually need to generate PDF exactly the same UI as HTML has. so do you plan to support these elements in PDF or could you suggest any solution?

Thanks,

Jinseop.

Mihai
Telerik team
 answered on 12 May 2015
2 answers
105 views

Hello,

my grid uses a row template and now I want to activate the copy to excel feature. So, I set allowCopy to true, but when I copy some selected cells to an excel sheet, the values are not displayed in the correct cells (see the attached excel file).

Is it actually possible to use this feature with row templates?

Regards

Sebastian

Sebastian
Top achievements
Rank 1
 answered on 12 May 2015
Narrow your results
Selected tags
Tags
Grid
General Discussions
Charts
Data Source
Scheduler
DropDownList
TreeView
MVVM
Editor
Window
DatePicker
Spreadsheet
Upload
ListView (Mobile)
ComboBox
TabStrip
MultiSelect
AutoComplete
ListView
Menu
Templates
Gantt
Validation
TreeList
Diagram
NumericTextBox
Splitter
PanelBar
Application
Drag and Drop
Map
ToolTip
Calendar
PivotGrid
ScrollView (Mobile)
Toolbar
TabStrip (Mobile)
Slider
Button (Mobile)
Filter
SPA
Drawing API
Drawer (Mobile)
Globalization
LinearGauge
Sortable
ModalView
Hierarchical Data Source
Button
FileManager
MaskedTextBox
View
Form
NavBar
Notification
Switch (Mobile)
SplitView
ListBox
DropDownTree
PDFViewer
Sparkline
ActionSheet
TileLayout
PopOver (Mobile)
TreeMap
ButtonGroup
ColorPicker
Pager
Styling
Chat
MultiColumnComboBox
Dialog
DateRangePicker
Checkbox
Timeline
Drawer
DateInput
ProgressBar
MediaPlayer
ImageEditor
TextBox
OrgChart
Accessibility
Effects
PivotGridV2
Licensing
ScrollView
Switch
TextArea
BulletChart
QRCode
ResponsivePanel
Wizard
CheckBoxGroup
Localization
Barcode
Breadcrumb
Collapsible
MultiViewCalendar
Touch
RadioButton
Stepper
Card
ExpansionPanel
Rating
RadioGroup
Badge
Captcha
Heatmap
AppBar
Loader
Security
TaskBoard
Popover
DockManager
TimePicker
FloatingActionButton
CircularGauge
ColorGradient
ColorPalette
DropDownButton
TimeDurationPicker
ToggleButton
BottomNavigation
Ripple
SkeletonContainer
Avatar
Circular ProgressBar
FlatColorPicker
SplitButton
Signature
Chip
ChipList
VS Code Extension
AIPrompt
PropertyGrid
Sankey
Chart Wizard
OTP Input
SpeechToTextButton
InlineAIPrompt
StockChart
ContextMenu
DateTimePicker
RadialGauge
ArcGauge
AICodingAssistant
SmartPasteButton
PromptBox
SegmentedControl
+? more
Top users last month
Marco
Top achievements
Rank 4
Iron
Iron
Iron
Hiba
Top achievements
Rank 1
Iron
Rob
Top achievements
Rank 3
Bronze
Bronze
Iron
Max
Top achievements
Rank 1
Veteran
Iron
Alina
Top achievements
Rank 1
Want to show your ninja superpower to fellow developers?
Top users last month
Marco
Top achievements
Rank 4
Iron
Iron
Iron
Hiba
Top achievements
Rank 1
Iron
Rob
Top achievements
Rank 3
Bronze
Bronze
Iron
Max
Top achievements
Rank 1
Veteran
Iron
Alina
Top achievements
Rank 1
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?