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