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.
});