| window.angular && (function(angular) { |
| 'use strict'; |
| |
| /** |
| * |
| * bmcTable Component |
| * |
| * To use: |
| * |
| * The 'data' attribute should be an array of all row objects in the table. |
| * It will render each item as a <tr> in the table. |
| * Each row object in the data array should also have a 'uiData' |
| * property that should be an array of the properties that will render |
| * as each table cell <td>. |
| * Each row object in the data array can optionally have an |
| * 'actions' property that should be an array of actions to provide the |
| * <bmc-table-actions> component. |
| * Each row object can optionally have an 'expandContent' property |
| * that should be a string value and can contain valid HTML. To render |
| * the expanded content, set 'expandable' attribute to true. |
| * Each row object can optionally have a 'selectable' property. Defaults |
| * to true if table is selectable. If a particular row should not |
| * be selectable, set to false. |
| * |
| * data = [ |
| * { uiData: ['root', 'Admin', 'enabled' ], selectable: false }, |
| * { uiData: ['user1', 'User', 'disabled' ] } |
| * ] |
| * |
| * The 'header' attribute should be an array of all header objects in the |
| * table. Each object in the header array should have a 'label' property |
| * that will render as a <th> in the table. |
| * If the table is sortable, can optionally add 'sortable' property to header |
| * row object. If a particular column is not sortable, set to false. |
| * |
| * header = [ |
| * { label: 'Username' }, |
| * { label: 'Privilege' } |
| * { label: 'Account Status', sortable: false } |
| * ] |
| * |
| * The 'sortable' attribute should be a boolean value. Defaults to false. |
| * The 'default-sort' attribute should be the index value of the header |
| * obejct that should be sorted on inital load. |
| * |
| * The 'row-actions-enabled' attribute, should be a boolean value |
| * Can be set to true to render table row actions. Defaults to false. |
| * Row actions are defined in data.actions. |
| * |
| * The 'expandable' attribute should be a boolean value. If true each |
| * row object in data array should contain a 'expandContent' property |
| * |
| * The 'selectable' attribute should be a boolean value. |
| * If 'selectable' is true, include 'batch-actions' property that should |
| * be an array of actions to provide <table-toolbar> component. |
| * |
| * The 'size' attribute which can be set to 'small' which will |
| * render a smaller font size in the table. |
| * |
| */ |
| |
| const TableController = function() { |
| this.sortAscending = true; |
| this.activeSort; |
| this.expandedRows = new Set(); |
| this.selectedRows = new Set(); |
| this.selectHeaderCheckbox = false; |
| this.someSelected = false; |
| |
| let selectableRowCount = 0; |
| |
| /** |
| * Sorts table data |
| */ |
| const sortData = () => { |
| this.data.sort((a, b) => { |
| const aProp = a.uiData[this.activeSort]; |
| const bProp = b.uiData[this.activeSort]; |
| if (aProp === bProp) { |
| return 0; |
| } else { |
| if (this.sortAscending) { |
| return aProp < bProp ? -1 : 1; |
| } |
| return aProp > bProp ? -1 : 1; |
| } |
| }) |
| }; |
| |
| /** |
| * Prep table |
| * Make adjustments to account for optional configurations |
| */ |
| const prepTable = () => { |
| if (this.sortable) { |
| // If sort is enabled, check for undefined 'sortable' |
| // property for each item in header array |
| this.header = this.header.map((column) => { |
| column.sortable = |
| column.sortable === undefined ? true : column.sortable; |
| return column; |
| }) |
| } |
| }; |
| |
| /** |
| * Prep data |
| * When data binding changes, make adjustments to account for |
| * optional configurations and undefined values |
| */ |
| const prepData = () => { |
| selectableRowCount = 0; |
| this.data.forEach((row) => { |
| if (row.uiData === undefined) { |
| // Check for undefined 'uiData' property for each item in data |
| // array |
| row.uiData = []; |
| } |
| if (this.selectable) { |
| // If table is selectable check row for 'selectable' property |
| row.selectable = row.selectable === undefined ? true : row.selectable; |
| if (row.selectable) { |
| selectableRowCount++; |
| row.selected = false; |
| } |
| } |
| }); |
| if (this.sortable) { |
| if (this.activeSort !== undefined || this.defaultSort !== undefined) { |
| // apply default or active sort if one is defined |
| this.activeSort = this.defaultSort !== undefined ? this.defaultSort : |
| this.activeSort; |
| sortData(); |
| } |
| } |
| }; |
| |
| /** |
| * Select all rows |
| * Sets each selectable row selected property to true |
| * and adds index to selectedRow Set |
| */ |
| const selectAllRows = () => { |
| this.selectHeaderCheckbox = true; |
| this.someSelected = false; |
| this.data.forEach((row, index) => { |
| if (!row.selected && row.selectable) { |
| row.selected = true; |
| this.selectedRows.add(index); |
| } |
| }) |
| }; |
| |
| /** |
| * Deselect all rows |
| * Sets each row selected property to false |
| * and clears selectedRow Set |
| */ |
| const deselectAllRows = () => { |
| this.selectHeaderCheckbox = false; |
| this.someSelected = false; |
| this.selectedRows.clear(); |
| this.data.forEach((row) => { |
| if (row.selectable) { |
| row.selected = false; |
| } |
| }) |
| }; |
| |
| /** |
| * Callback when table row action clicked |
| * Emits user desired action and associated row data to |
| * parent controller |
| * @param {string} action : action type |
| * @param {any} row : user object |
| */ |
| this.onEmitRowAction = (action, row) => { |
| if (action !== undefined && row !== undefined) { |
| const value = {action, row}; |
| this.emitRowAction({value}); |
| } |
| }; |
| |
| /** |
| * Callback when batch action clicked from toolbar |
| * Emits the action type and the selected row data to |
| * parent controller |
| * @param {string} action : action type |
| */ |
| this.onEmitBatchAction = (action) => { |
| const filteredRows = this.data.filter((row) => row.selected); |
| const value = {action, filteredRows}; |
| this.emitBatchAction({value}); |
| }; |
| |
| /** |
| * Callback when sortable table header clicked |
| * @param {number} index : index of header item |
| */ |
| this.onClickSort = (index) => { |
| if (index === this.activeSort) { |
| // If clicked header is already sorted, reverse |
| // the sort direction |
| this.sortAscending = !this.sortAscending; |
| this.data.reverse(); |
| } else { |
| this.sortAscending = true; |
| this.activeSort = index; |
| sortData(); |
| } |
| }; |
| |
| /** |
| * Callback when expand trigger clicked |
| * @param {number} row : index of expanded row |
| */ |
| this.onClickExpand = (row) => { |
| if (this.expandedRows.has(row)) { |
| this.expandedRows.delete(row) |
| } else { |
| this.expandedRows.add(row); |
| } |
| }; |
| |
| /** |
| * Callback when select checkbox clicked |
| * @param {number} row : index of selected row |
| */ |
| this.onRowSelectChange = (row) => { |
| if (this.selectedRows.has(row)) { |
| this.selectedRows.delete(row); |
| } else { |
| this.selectedRows.add(row); |
| } |
| if (this.selectedRows.size === 0) { |
| this.someSelected = false; |
| this.selectHeaderCheckbox = false; |
| deselectAllRows(); |
| } else if (this.selectedRows.size === selectableRowCount) { |
| this.someSelected = false; |
| this.selectHeaderCheckbox = true; |
| selectAllRows(); |
| } else { |
| this.someSelected = true; |
| } |
| }; |
| |
| /** |
| * Callback when header select box value changes |
| */ |
| this.onHeaderSelectChange = (checked) => { |
| this.selectHeaderCheckbox = checked; |
| if (this.selectHeaderCheckbox) { |
| selectAllRows(); |
| } else { |
| deselectAllRows(); |
| } |
| }; |
| |
| /** |
| * Callback when cancel/close button closed |
| * from toolbar |
| */ |
| this.onToolbarClose = () => { |
| deselectAllRows(); |
| }; |
| |
| /** |
| * onInit Component lifecycle hook |
| * Checking for undefined values |
| */ |
| this.$onInit = () => { |
| this.header = this.header === undefined ? [] : this.header; |
| this.data = this.data == undefined ? [] : this.data; |
| this.sortable = this.sortable === undefined ? false : this.sortable; |
| this.rowActionsEnabled = |
| this.rowActionsEnabled === undefined ? false : this.rowActionsEnabled; |
| this.size = this.size === undefined ? '' : this.size; |
| this.expandable = this.expandable === undefined ? false : this.expandable; |
| this.selectable = this.selectable === undefined ? false : this.selectable; |
| prepTable(); |
| }; |
| |
| /** |
| * onChanges Component lifecycle hook |
| */ |
| this.$onChanges = (onChangesObj) => { |
| const dataChange = onChangesObj.data; |
| if (dataChange) { |
| prepData(); |
| deselectAllRows(); |
| } |
| }; |
| }; |
| |
| /** |
| * Register bmcTable component |
| */ |
| angular.module('app.common.components').component('bmcTable', { |
| template: require('./table.html'), |
| controller: TableController, |
| bindings: { |
| data: '<', // Array |
| header: '<', // Array |
| rowActionsEnabled: '<', // boolean |
| size: '<', // string |
| sortable: '<', // boolean |
| defaultSort: '<', // number (index of sort) |
| expandable: '<', // boolean |
| selectable: '<', // boolean |
| batchActions: '<', // Array |
| emitRowAction: '&', |
| emitBatchAction: '&' |
| } |
| }) |
| })(window.angular); |