ui-grid.expandable.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. /*!
  2. * ui-grid - v4.4.6 - 2018-04-06
  3. * Copyright (c) 2018 ; License: MIT
  4. */
  5. (function () {
  6. 'use strict';
  7. /**
  8. * @ngdoc overview
  9. * @name ui.grid.expandable
  10. * @description
  11. *
  12. * # ui.grid.expandable
  13. *
  14. * <div class="alert alert-warning" role="alert"><strong>Alpha</strong> This feature is in development. There will almost certainly be breaking api changes, or there are major outstanding bugs.</div>
  15. *
  16. * This module provides the ability to create subgrids with the ability to expand a row
  17. * to show the subgrid.
  18. *
  19. * <div doc-module-components="ui.grid.expandable"></div>
  20. */
  21. var module = angular.module('ui.grid.expandable', ['ui.grid']);
  22. /**
  23. * @ngdoc service
  24. * @name ui.grid.expandable.service:uiGridExpandableService
  25. *
  26. * @description Services for the expandable grid
  27. */
  28. module.service('uiGridExpandableService', ['gridUtil', '$compile', function (gridUtil, $compile) {
  29. var service = {
  30. initializeGrid: function (grid) {
  31. grid.expandable = {};
  32. grid.expandable.expandedAll = false;
  33. /**
  34. * @ngdoc object
  35. * @name enableExpandable
  36. * @propertyOf ui.grid.expandable.api:GridOptions
  37. * @description Whether or not to use expandable feature, allows you to turn off expandable on specific grids
  38. * within your application, or in specific modes on _this_ grid. Defaults to true.
  39. * @example
  40. * <pre>
  41. * $scope.gridOptions = {
  42. * enableExpandable: false
  43. * }
  44. * </pre>
  45. */
  46. grid.options.enableExpandable = grid.options.enableExpandable !== false;
  47. /**
  48. * @ngdoc object
  49. * @name showExpandAllButton
  50. * @propertyOf ui.grid.expandable.api:GridOptions
  51. * @description Whether or not to display the expand all button, allows you to hide expand all button on specific grids
  52. * within your application, or in specific modes on _this_ grid. Defaults to true.
  53. * @example
  54. * <pre>
  55. * $scope.gridOptions = {
  56. * showExpandAllButton: false
  57. * }
  58. * </pre>
  59. */
  60. grid.options.showExpandAllButton = grid.options.showExpandAllButton !== false;
  61. /**
  62. * @ngdoc object
  63. * @name expandableRowHeight
  64. * @propertyOf ui.grid.expandable.api:GridOptions
  65. * @description Height in pixels of the expanded subgrid. Defaults to
  66. * 150
  67. * @example
  68. * <pre>
  69. * $scope.gridOptions = {
  70. * expandableRowHeight: 150
  71. * }
  72. * </pre>
  73. */
  74. grid.options.expandableRowHeight = grid.options.expandableRowHeight || 150;
  75. /**
  76. * @ngdoc object
  77. * @name expandableRowHeaderWidth
  78. * @propertyOf ui.grid.expandable.api:GridOptions
  79. * @description Width in pixels of the expandable column. Defaults to 40
  80. * @example
  81. * <pre>
  82. * $scope.gridOptions = {
  83. * expandableRowHeaderWidth: 40
  84. * }
  85. * </pre>
  86. */
  87. grid.options.expandableRowHeaderWidth = grid.options.expandableRowHeaderWidth || 40;
  88. /**
  89. * @ngdoc object
  90. * @name expandableRowTemplate
  91. * @propertyOf ui.grid.expandable.api:GridOptions
  92. * @description Mandatory. The template for your expanded row
  93. * @example
  94. * <pre>
  95. * $scope.gridOptions = {
  96. * expandableRowTemplate: 'expandableRowTemplate.html'
  97. * }
  98. * </pre>
  99. */
  100. if ( grid.options.enableExpandable && !grid.options.expandableRowTemplate ){
  101. gridUtil.logError( 'You have not set the expandableRowTemplate, disabling expandable module' );
  102. grid.options.enableExpandable = false;
  103. }
  104. /**
  105. * @ngdoc object
  106. * @name ui.grid.expandable.api:PublicApi
  107. *
  108. * @description Public Api for expandable feature
  109. */
  110. /**
  111. * @ngdoc object
  112. * @name ui.grid.expandable.api:GridRow
  113. *
  114. * @description Additional properties added to GridRow when using the expandable module
  115. */
  116. /**
  117. * @ngdoc object
  118. * @name ui.grid.expandable.api:GridOptions
  119. *
  120. * @description Options for configuring the expandable feature, these are available to be
  121. * set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
  122. */
  123. var publicApi = {
  124. events: {
  125. expandable: {
  126. /**
  127. * @ngdoc event
  128. * @name rowExpandedBeforeStateChanged
  129. * @eventOf ui.grid.expandable.api:PublicApi
  130. * @description raised when row is expanding or collapsing
  131. * <pre>
  132. * gridApi.expandable.on.rowExpandedBeforeStateChanged(scope,function(row){})
  133. * </pre>
  134. * @param {scope} scope the application scope
  135. * @param {GridRow} row the row that was expanded
  136. */
  137. rowExpandedBeforeStateChanged: function(scope, row){
  138. },
  139. /**
  140. * @ngdoc event
  141. * @name rowExpandedStateChanged
  142. * @eventOf ui.grid.expandable.api:PublicApi
  143. * @description raised when row expanded or collapsed
  144. * <pre>
  145. * gridApi.expandable.on.rowExpandedStateChanged(scope,function(row){})
  146. * </pre>
  147. * @param {scope} scope the application scope
  148. * @param {GridRow} row the row that was expanded
  149. */
  150. rowExpandedStateChanged: function (scope, row) {
  151. }
  152. }
  153. },
  154. methods: {
  155. expandable: {
  156. /**
  157. * @ngdoc method
  158. * @name toggleRowExpansion
  159. * @methodOf ui.grid.expandable.api:PublicApi
  160. * @description Toggle a specific row
  161. * <pre>
  162. * gridApi.expandable.toggleRowExpansion(rowEntity);
  163. * </pre>
  164. * @param {object} rowEntity the data entity for the row you want to expand
  165. */
  166. toggleRowExpansion: function (rowEntity) {
  167. var row = grid.getRow(rowEntity);
  168. if (row !== null) {
  169. service.toggleRowExpansion(grid, row);
  170. }
  171. },
  172. /**
  173. * @ngdoc method
  174. * @name expandAllRows
  175. * @methodOf ui.grid.expandable.api:PublicApi
  176. * @description Expand all subgrids.
  177. * <pre>
  178. * gridApi.expandable.expandAllRows();
  179. * </pre>
  180. */
  181. expandAllRows: function() {
  182. service.expandAllRows(grid);
  183. },
  184. /**
  185. * @ngdoc method
  186. * @name collapseAllRows
  187. * @methodOf ui.grid.expandable.api:PublicApi
  188. * @description Collapse all subgrids.
  189. * <pre>
  190. * gridApi.expandable.collapseAllRows();
  191. * </pre>
  192. */
  193. collapseAllRows: function() {
  194. service.collapseAllRows(grid);
  195. },
  196. /**
  197. * @ngdoc method
  198. * @name toggleAllRows
  199. * @methodOf ui.grid.expandable.api:PublicApi
  200. * @description Toggle all subgrids.
  201. * <pre>
  202. * gridApi.expandable.toggleAllRows();
  203. * </pre>
  204. */
  205. toggleAllRows: function() {
  206. service.toggleAllRows(grid);
  207. },
  208. /**
  209. * @ngdoc function
  210. * @name expandRow
  211. * @methodOf ui.grid.expandable.api:PublicApi
  212. * @description Expand the data row
  213. * @param {object} rowEntity gridOptions.data[] array instance
  214. */
  215. expandRow: function (rowEntity) {
  216. var row = grid.getRow(rowEntity);
  217. if (row !== null && !row.isExpanded) {
  218. service.toggleRowExpansion(grid, row);
  219. }
  220. },
  221. /**
  222. * @ngdoc function
  223. * @name collapseRow
  224. * @methodOf ui.grid.expandable.api:PublicApi
  225. * @description Collapse the data row
  226. * @param {object} rowEntity gridOptions.data[] array instance
  227. */
  228. collapseRow: function (rowEntity) {
  229. var row = grid.getRow(rowEntity);
  230. if (row !== null && row.isExpanded) {
  231. service.toggleRowExpansion(grid, row);
  232. }
  233. },
  234. /**
  235. * @ngdoc function
  236. * @name getExpandedRows
  237. * @methodOf ui.grid.expandable.api:PublicApi
  238. * @description returns all expandedRow's entity references
  239. */
  240. getExpandedRows: function () {
  241. return service.getExpandedRows(grid).map(function (gridRow) {
  242. return gridRow.entity;
  243. });
  244. }
  245. }
  246. }
  247. };
  248. grid.api.registerEventsFromObject(publicApi.events);
  249. grid.api.registerMethodsFromObject(publicApi.methods);
  250. },
  251. toggleRowExpansion: function (grid, row) {
  252. // trigger the "before change" event. Can change row height dynamically this way.
  253. grid.api.expandable.raise.rowExpandedBeforeStateChanged(row);
  254. /**
  255. * @ngdoc object
  256. * @name isExpanded
  257. * @propertyOf ui.grid.expandable.api:GridRow
  258. * @description Whether or not the row is currently expanded.
  259. * @example
  260. * <pre>
  261. * $scope.api.expandable.on.rowExpandedStateChanged($scope, function (row) {
  262. * if (row.isExpanded) {
  263. * //...
  264. * }
  265. * });
  266. * </pre>
  267. */
  268. row.isExpanded = !row.isExpanded;
  269. if (angular.isUndefined(row.expandedRowHeight)){
  270. row.expandedRowHeight = grid.options.expandableRowHeight;
  271. }
  272. if (row.isExpanded) {
  273. row.height = row.grid.options.rowHeight + row.expandedRowHeight;
  274. grid.expandable.expandedAll = service.getExpandedRows(grid).length === grid.rows.length;
  275. } else {
  276. row.height = row.grid.options.rowHeight;
  277. grid.expandable.expandedAll = false;
  278. }
  279. grid.api.expandable.raise.rowExpandedStateChanged(row);
  280. },
  281. expandAllRows: function(grid) {
  282. grid.renderContainers.body.visibleRowCache.forEach( function(row) {
  283. if (!row.isExpanded && !(row.entity.subGridOptions && row.entity.subGridOptions.disableRowExpandable)) {
  284. service.toggleRowExpansion(grid, row);
  285. }
  286. });
  287. grid.expandable.expandedAll = true;
  288. grid.queueGridRefresh();
  289. },
  290. collapseAllRows: function(grid) {
  291. grid.renderContainers.body.visibleRowCache.forEach( function(row) {
  292. if (row.isExpanded) {
  293. service.toggleRowExpansion(grid, row);
  294. }
  295. });
  296. grid.expandable.expandedAll = false;
  297. grid.queueGridRefresh();
  298. },
  299. toggleAllRows: function(grid) {
  300. if (grid.expandable.expandedAll) {
  301. service.collapseAllRows(grid);
  302. }
  303. else {
  304. service.expandAllRows(grid);
  305. }
  306. },
  307. getExpandedRows: function (grid) {
  308. return grid.rows.filter(function (row) {
  309. return row.isExpanded;
  310. });
  311. }
  312. };
  313. return service;
  314. }]);
  315. /**
  316. * @ngdoc object
  317. * @name enableExpandableRowHeader
  318. * @propertyOf ui.grid.expandable.api:GridOptions
  319. * @description Show a rowHeader to provide the expandable buttons. If set to false then implies
  320. * you're going to use a custom method for expanding and collapsing the subgrids. Defaults to true.
  321. * @example
  322. * <pre>
  323. * $scope.gridOptions = {
  324. * enableExpandableRowHeader: false
  325. * }
  326. * </pre>
  327. */
  328. module.directive('uiGridExpandable', ['uiGridExpandableService', '$templateCache',
  329. function (uiGridExpandableService, $templateCache) {
  330. return {
  331. replace: true,
  332. priority: 0,
  333. require: '^uiGrid',
  334. scope: false,
  335. compile: function () {
  336. return {
  337. pre: function ($scope, $elm, $attrs, uiGridCtrl) {
  338. uiGridExpandableService.initializeGrid(uiGridCtrl.grid);
  339. if (!uiGridCtrl.grid.options.enableExpandable) {
  340. return;
  341. }
  342. if (uiGridCtrl.grid.options.enableExpandableRowHeader !== false ) {
  343. var expandableRowHeaderColDef = {
  344. name: 'expandableButtons',
  345. displayName: '',
  346. exporterSuppressExport: true,
  347. enableColumnResizing: false,
  348. enableColumnMenu: false,
  349. width: uiGridCtrl.grid.options.expandableRowHeaderWidth || 40
  350. };
  351. expandableRowHeaderColDef.cellTemplate = $templateCache.get('ui-grid/expandableRowHeader');
  352. expandableRowHeaderColDef.headerCellTemplate = $templateCache.get('ui-grid/expandableTopRowHeader');
  353. uiGridCtrl.grid.addRowHeaderColumn(expandableRowHeaderColDef, -90);
  354. }
  355. },
  356. post: function ($scope, $elm, $attrs, uiGridCtrl) {
  357. }
  358. };
  359. }
  360. };
  361. }]);
  362. /**
  363. * @ngdoc directive
  364. * @name ui.grid.expandable.directive:uiGrid
  365. * @description stacks on the uiGrid directive to register child grid with parent row when child is created
  366. */
  367. module.directive('uiGrid', ['uiGridExpandableService', '$templateCache',
  368. function (uiGridExpandableService, $templateCache) {
  369. return {
  370. replace: true,
  371. priority: 599,
  372. require: '^uiGrid',
  373. scope: false,
  374. compile: function () {
  375. return {
  376. pre: function ($scope, $elm, $attrs, uiGridCtrl) {
  377. uiGridCtrl.grid.api.core.on.renderingComplete($scope, function() {
  378. //if a parent grid row is on the scope, then add the parentRow property to this childGrid
  379. if ($scope.row && $scope.row.grid && $scope.row.grid.options && $scope.row.grid.options.enableExpandable) {
  380. /**
  381. * @ngdoc directive
  382. * @name ui.grid.expandable.class:Grid
  383. * @description Additional Grid properties added by expandable module
  384. */
  385. /**
  386. * @ngdoc object
  387. * @name parentRow
  388. * @propertyOf ui.grid.expandable.class:Grid
  389. * @description reference to the expanded parent row that owns this grid
  390. */
  391. uiGridCtrl.grid.parentRow = $scope.row;
  392. //todo: adjust height on parent row when child grid height changes. we need some sort of gridHeightChanged event
  393. // uiGridCtrl.grid.core.on.canvasHeightChanged($scope, function(oldHeight, newHeight) {
  394. // uiGridCtrl.grid.parentRow = newHeight;
  395. // });
  396. }
  397. });
  398. },
  399. post: function ($scope, $elm, $attrs, uiGridCtrl) {
  400. }
  401. };
  402. }
  403. };
  404. }]);
  405. /**
  406. * @ngdoc directive
  407. * @name ui.grid.expandable.directive:uiGridExpandableRow
  408. * @description directive to render the expandable row template
  409. */
  410. module.directive('uiGridExpandableRow',
  411. ['uiGridExpandableService', '$timeout', '$compile', 'uiGridConstants','gridUtil','$interval', '$log',
  412. function (uiGridExpandableService, $timeout, $compile, uiGridConstants, gridUtil, $interval, $log) {
  413. return {
  414. replace: false,
  415. priority: 0,
  416. scope: false,
  417. compile: function () {
  418. return {
  419. pre: function ($scope, $elm, $attrs, uiGridCtrl) {
  420. gridUtil.getTemplate($scope.grid.options.expandableRowTemplate).then(
  421. function (template) {
  422. if ($scope.grid.options.expandableRowScope) {
  423. /**
  424. * @ngdoc object
  425. * @name expandableRowScope
  426. * @propertyOf ui.grid.expandable.api:GridOptions
  427. * @description Variables of object expandableScope will be available in the scope of the expanded subgrid
  428. * @example
  429. * <pre>
  430. * $scope.gridOptions = {
  431. * expandableRowScope: expandableScope
  432. * }
  433. * </pre>
  434. */
  435. var expandableRowScope = $scope.grid.options.expandableRowScope;
  436. for (var property in expandableRowScope) {
  437. if (expandableRowScope.hasOwnProperty(property)) {
  438. $scope[property] = expandableRowScope[property];
  439. }
  440. }
  441. }
  442. var expandedRowElement = angular.element(template);
  443. $elm.append(expandedRowElement);
  444. expandedRowElement = $compile(expandedRowElement)($scope);
  445. $scope.row.expandedRendered = true;
  446. });
  447. },
  448. post: function ($scope, $elm, $attrs, uiGridCtrl) {
  449. $scope.$on('$destroy', function() {
  450. $scope.row.expandedRendered = false;
  451. });
  452. }
  453. };
  454. }
  455. };
  456. }]);
  457. /**
  458. * @ngdoc directive
  459. * @name ui.grid.expandable.directive:uiGridRow
  460. * @description stacks on the uiGridRow directive to add support for expandable rows
  461. */
  462. module.directive('uiGridRow',
  463. ['$compile', 'gridUtil', '$templateCache',
  464. function ($compile, gridUtil, $templateCache) {
  465. return {
  466. priority: -200,
  467. scope: false,
  468. compile: function ($elm, $attrs) {
  469. return {
  470. pre: function ($scope, $elm, $attrs, controllers) {
  471. if (!$scope.grid.options.enableExpandable) {
  472. return;
  473. }
  474. $scope.expandableRow = {};
  475. $scope.expandableRow.shouldRenderExpand = function () {
  476. var ret = $scope.colContainer.name === 'body' && $scope.grid.options.enableExpandable !== false && $scope.row.isExpanded && (!$scope.grid.isScrollingVertically || $scope.row.expandedRendered);
  477. return ret;
  478. };
  479. $scope.expandableRow.shouldRenderFiller = function () {
  480. var ret = $scope.row.isExpanded && ( $scope.colContainer.name !== 'body' || ($scope.grid.isScrollingVertically && !$scope.row.expandedRendered));
  481. return ret;
  482. };
  483. /*
  484. * Commented out @PaulL1. This has no purpose that I can see, and causes #2964. If this code needs to be reinstated for some
  485. * reason it needs to use drawnWidth, not width, and needs to check column visibility. It should really use render container
  486. * visible column cache also instead of checking column.renderContainer.
  487. function updateRowContainerWidth() {
  488. var grid = $scope.grid;
  489. var colWidth = 0;
  490. grid.columns.forEach( function (column) {
  491. if (column.renderContainer === 'left') {
  492. colWidth += column.width;
  493. }
  494. });
  495. colWidth = Math.floor(colWidth);
  496. return '.grid' + grid.id + ' .ui-grid-pinned-container-' + $scope.colContainer.name + ', .grid' + grid.id +
  497. ' .ui-grid-pinned-container-' + $scope.colContainer.name + ' .ui-grid-render-container-' + $scope.colContainer.name +
  498. ' .ui-grid-viewport .ui-grid-canvas .ui-grid-row { width: ' + colWidth + 'px; }';
  499. }
  500. if ($scope.colContainer.name === 'left') {
  501. $scope.grid.registerStyleComputation({
  502. priority: 15,
  503. func: updateRowContainerWidth
  504. });
  505. }*/
  506. },
  507. post: function ($scope, $elm, $attrs, controllers) {
  508. }
  509. };
  510. }
  511. };
  512. }]);
  513. /**
  514. * @ngdoc directive
  515. * @name ui.grid.expandable.directive:uiGridViewport
  516. * @description stacks on the uiGridViewport directive to append the expandable row html elements to the
  517. * default gridRow template
  518. */
  519. module.directive('uiGridViewport',
  520. ['$compile', 'gridUtil', '$templateCache',
  521. function ($compile, gridUtil, $templateCache) {
  522. return {
  523. priority: -200,
  524. scope: false,
  525. compile: function ($elm, $attrs) {
  526. //todo: this adds ng-if watchers to each row even if the grid is not using expandable directive
  527. // or options.enableExpandable == false
  528. // The alternative is to compile the template and append to each row in a uiGridRow directive
  529. var rowRepeatDiv = angular.element($elm.children().children()[0]);
  530. var expandedRowFillerElement = $templateCache.get('ui-grid/expandableScrollFiller');
  531. var expandedRowElement = $templateCache.get('ui-grid/expandableRow');
  532. rowRepeatDiv.append(expandedRowElement);
  533. rowRepeatDiv.append(expandedRowFillerElement);
  534. return {
  535. pre: function ($scope, $elm, $attrs, controllers) {
  536. },
  537. post: function ($scope, $elm, $attrs, controllers) {
  538. }
  539. };
  540. }
  541. };
  542. }]);
  543. })();