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 culture009. kendo.culture("he-IL");010. 011. // Define scope variables012. $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 permissions020. $scope.VM.permissions = {021. allow_edit: true,022. allow_sign: true,023. allow_cancel: true024. };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:id080. id: "date_created_id",081. fields: {082. date_created: {083. editable: false,084. type: "date"085. },086. project_name: {087. editable: false088. },089. supplier_name: {090. editable: true,091. validation: {092. required: true093. }094. },095. info: {096. editable: true097. },098. expense_cause: {099. editable: true,100. nullable: true101. },102. sub_expense_cause: {103. editable: true,104. nullable: true105. },106. cheque_number: {107. editable: false108. },109. amount: {110. editable: false111. },112. sig1: {113. editable: false114. },115. sig2: {116. editable: false117. },118. cheque_status: {119. editable: false120. }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 reference131. $scope.VM.readOptions = e;132. 133. // Start the spinner134. 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 spinner142. kendo.ui.progress($("div[kendo-grid]"), false);143. });144. },145. update: function(e) {146. // Save the 'e' for future reference147. $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 reference155. $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: false232. },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 date375. 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: false389. },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 date398. 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: false412. },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: false428. }429. ],430. 431. // Events432. dataBound: function(e) {433. $scope.VM.isInitialized = true;434. }435. };436. 437. /* ========================================== */438. /* Methods */439. /* ========================================== */440. 441. ///////////////////////////////////// Common442. // Gets a reference to the grid443. $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. ///////////////////////////////////// Permissions453. // Check if the user is allowed to sign454. $scope.VM.isAllowSign = function() {455. return $scope.VM.permissions.allow_sign;456. };457. // Check if the user is allowed to unsign458. $scope.VM.isAllowUnSign = function() {459. return $scope.VM.permissions.allow_sign;460. };461. // Check if the user is allowed to edit existing items462. $scope.VM.isAllowEdit = function() {463. return $scope.VM.permissions.allow_edit;464. };465. // Check if the user is allowed to add new items466. $scope.VM.isAllowAdd = function() {467. return $scope.VM.permissions.allow_edit;468. };469. // Check if the user is allowed to cancel cheques470. $scope.VM.isAllowCancel = function() {471. return $scope.VM.permissions.allow_cancel;472. };473. 474. ///////////////////////////////////// Helper methods475. // Check if at-least one row selected476. $scope.VM.isEntitySelected = function() {477. return ($scope.VM.getSelectedRowsCount() > 0);478. };479. // Check if exactly one row selected480. $scope.VM.isOneEntitySelected = function() {481. return ($scope.VM.getSelectedRowsCount() == 1);482. };483. // Check if the cheque is already signed484. $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. else490. return false;491. };492. // Get the number of rows in the grid493. $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 grid509. $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 row525. $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 statys537. $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. ///////////////////////////////////// Commands565. // Opens the entity detail view566. $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 changes605. $scope.VM.dataSource.sync();606. }607. });608. };609. // Add a new entity610. $scope.VM.addNew = function(entity){611. $scope.VM.dataSource.add(entity)612. };613. // Update the entity614. $scope.VM.update = function(entity){615. 616. };617. // Sign a cheque618. $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 changes629. $scope.VM.dataSource.sync();630. };631. // Sign all selected cheques632. $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 cheque650. $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 changes661. $scope.VM.dataSource.sync();662. };663. // Sign all selected cheques664. $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 cheque682. $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 cheque693. $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 range704. $scope.VM.getCheques = function(e) {705. $scope.VM.dataSource.read($scope.VM.readOptions);706. };707. // Refresh the data, if any changes has been made708. 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 completed763. flag = true;764. }765. break;766. }767. case "insert": {768. if (data[index]["date_created:id"] == currRow["date_created:id"]) {769. // Mark iteration as completed770. flag = true;771. }772. break;773. }774. default: {775. if (action)776. console.error("Can't load entity from flow, unknown state '"+action+"'");777. else778. 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 grid786. 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. ///////////////////////////////////// Presentation802. // Responsible for filtering the grid by the status field803. $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 mouse825. $(document).mousemove(function(e) {826. window.x = e.pageX;827. window.y = e.pageY;828. });829. // Show the quicksign panel830. $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 panel852. $scope.VM.hideQuickSign = function(sig, chequeId) {853. var handle = $(".bubble-sig"+sig+"-"+chequeId);854. handle.hide();855. };856. });857. 858.});