blob: 5db05b69e9298c363249a3ab6d873b224fc059bb [file] [log] [blame]
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.
*
* data = [
* { uiData: ['root', 'Admin', 'enabled' ] },
* { 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 '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();
/**
* 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;
})
}
if (this.rowActionsEnabled) {
// If table actions are enabled push an empty
// string to the header array to account for additional
// table actions cell
this.header.push({label: '', sortable: false});
}
if (this.expandable) {
// If table is expandable, push an empty string to the
// header array to account for additional expansion cell
this.header.unshift({label: '', sortable: 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.onEmitTableAction = (action, row) => {
if (action !== undefined && row !== undefined) {
const value = {action, row};
this.emitAction({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);
}
};
/**
* 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;
// Check for undefined 'uiData' property for each item in data array
this.data = this.data.map((row) => {
if (row.uiData === undefined) {
row.uiData = [];
}
return row;
})
prepTable();
};
/**
* onChanges Component lifecycle hook
* Check for changes in the data array and apply
* default or active sort if one is defined
*/
this.$onChanges = (onChangesObj) => {
const dataChange = onChangesObj.data;
if (dataChange) {
if (this.activeSort !== undefined || this.defaultSort !== undefined) {
this.activeSort = this.defaultSort !== undefined ? this.defaultSort :
this.activeSort;
sortData();
}
}
}
};
/**
* 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
emitAction: '&'
}
})
})(window.angular);