angular4-collapsible
Version:
Angular 2 / 4 Materialize CSS collapsible components
496 lines (431 loc) • 18 kB
text/typescript
import {
Component,
OnInit, OnChanges, SimpleChanges,
Input, HostBinding, HostListener,
ElementRef, ContentChildren, QueryList, AfterContentInit
} from '@angular/core';
import { CollapsibleTableRowComponent } from './collapsible-table-row.component';
import { CollapsibleService } from './collapsible.service';
export class CollapsibleTableComponent implements OnInit, OnChanges, AfterContentInit {
// component options
//
// makes the table bordered
bordered: boolean;
// makes the table bordered horizontally only
borderedHorizontally: boolean;
// makes the table bordered vertically only
borderedVertically: boolean;
// makes the table striped
striped: boolean;
// a color of an odd striped row
stripedOddColor: string;
// a text color of an odd striped row
stripedOddTextColor: string;
// a color of an even striped row
stripedEvenColor: string;
// a text color of an even striped row
stripedEvenTextColor: string;
// highlight table rows on mouse hover
highlight: boolean;
// a color of a highlighted row
highlightColor: string;
// a text color of a highlighted row
highlightTextColor: string;
// a color of an active row
activeColor: string;
// a text color of an active row
activeTextColor: string;
// center align all the text in the table
centered: boolean;
// makes the table horizontally scrollable on smaller screen widths
responsive: boolean;
// allows to select rows
select: boolean;
// allows to select multiple rows
selectMultipleRows: boolean;
// a color of a selected row
selectColor: string;
// a text color of a selected row
selectTextColor: string;
// allows deselecting selected rows
allowDeselectingRows: boolean;
// allows navigation between table rows using arrow keys
allowKeyboardNavigation = true;
// disables user select withing the table
noTextSelect: boolean;
fixedTableHeight = 'auto';
tabindex = 0;
selectedRows: Array<number> = [];
// specifies collapsible type. Can be either 'accordion' or 'expandable'
type: 'accordion' | 'expandable' = 'accordion';
collapsibleTableRows: QueryList<CollapsibleTableRowComponent>;
mouseDownHold = false;
constructor(
private el: ElementRef,
private collapsibleService: CollapsibleService) { }
ngOnInit() {
// console.debug(`CollapsibleTableComponent::ngOnInit()`);
}
ngAfterContentInit() {
// console.debug(`CollapsibleTableComponent::ngAfterContentInit()`);
// this.updateFixedTableHeight();
/*
console.debug(`CollapsibleTableComponent::ngOnInit()\n` +
`this = {\n` +
`bordered = ${this.bordered}\n` +
`borderedHorizontally = ${this.borderedHorizontally}\n` +
`borderedVertically = ${this.borderedVertically}\n` +
`striped = ${this.striped}\n` +
`stripedOddColor = ${this.stripedOddColor}\n` +
`stripedEvenColor = ${this.stripedEvenColor}\n` +
`highlight = ${this.highlight}\n` +
`highlightColor = ${this.highlightColor}\n` +
`highlightTextColor = ${this.highlightTextColor}\n` +
`activeColor = ${this.activeColor}\n` +
`activeTextColor = ${this.activeTextColor}\n` +
`centered = ${this.centered}\n` +
`responsive = ${this.responsive}\n` +
`select = ${this.select}\n` +
`selectColor = ${this.selectColor}\n` +
`selectTextColor = ${this.selectTextColor}\n` +
`selectMultipleRows = ${this.selectMultipleRows}\n` +
`noTextSelect = ${this.noTextSelect}\n` +
`}`);
*/
}
ngOnChanges(changes: SimpleChanges): void {
for (let change in changes) {
if (changes.hasOwnProperty(change)) {
if (this.collapsibleTableRows != null) {
switch (change) {
case 'striped':
case 'stripedOddColor':
case 'stripedOddTextColor':
case 'stripedEvenColor':
case 'stripedEvenTextColor':
this.updateTable('striped');
break;
case 'highlight':
case 'highlightColor':
case 'highlightTextColor':
this.updateTable('highlight');
break;
case 'activeColor':
case 'activeTextColor':
this.updateTable('active');
break;
case 'select':
case 'selectColor':
case 'selectTextColor':
case 'selectMultipleRows':
case 'allowDeselectingRows':
this.updateTable('select');
break;
}
}
// update collapsible table type in CollapsibleService
if (change === 'type') {
this.type = changes.type.currentValue;
this.collapsibleService.setType(this.type);
}
}
}
this.collapsibleService.setCollapsibleTable(this);
}
focus() {
this.el.nativeElement.focus();
}
addSelectedRow(index: number): void {
switch (true) {
case this.selectMultipleRows && this.selectedRows.indexOf(index) === -1:
this.selectedRows.push(index);
this.selectedRows.sort((a, b) => a - b);
break;
case !this.selectMultipleRows:
this.selectedRows = [];
this.deselectAllRows();
this.selectedRows.push(index);
this.selectedRows.sort((a, b) => a - b);
break;
}
}
removeSelectedRow(index: number): void {
if (this.selectedRows.indexOf(index) !== -1) {
this.selectedRows.splice(this.selectedRows.indexOf(index), 1);
}
}
clearSelectedRows() {
this.selectedRows = [];
}
deselectAllRows() {
this.collapsibleTableRows.forEach(row => {
row.selected = false;
row.updateRow();
});
}
selectRow(index: number) {
if (this.select) {
switch (true) {
case index === 0:
this.selectRow(1);
break;
case index === this.collapsibleTableRows.length:
this.selectRow(this.collapsibleTableRows.length - 1);
break;
case 0 < index && index <= this.collapsibleTableRows.length - 1:
// console.debug(`selectRow(${index})`);
this.addSelectedRow(index);
this.collapsibleTableRows.forEach((row, i) => {
if (index !== i) {
if (!this.selectMultipleRows) {
row.selected = false;
}
} else {
row.selected = true;
}
row.updateRow();
});
break;
}
}
}
selectRows(firstRowIndex: number, lastRowIndex: number) {
// console.debug(`selectRows(${firstRowIndex}, ${lastRowIndex})`);
if (this.selectMultipleRows &&
0 < firstRowIndex && firstRowIndex < lastRowIndex &&
lastRowIndex <= this.collapsibleTableRows.length - 1) {
this.clearSelectedRows();
this.collapsibleTableRows.forEach((row, i) => {
if (firstRowIndex <= i && i <= lastRowIndex) {
this.addSelectedRow(i);
row.selected = true;
} else {
row.selected = false;
}
row.updateRow();
});
}
}
toggleRowSelection(index: number) {
// console.debug(`toggleRowSelection(${index})`);
if (this.select &&
0 < index && index <= this.collapsibleTableRows.length - 1) {
this.collapsibleTableRows.forEach((row, i) => {
if (index === i) {
if (row.selected) {
this.removeSelectedRow(index);
} else {
this.addSelectedRow(index);
}
row.selected = !row.selected;
row.updateRow();
}
});
}
}
/*updateFixedTableHeight() {
this.fixedTableHeight = this.el.nativeElement.offsetHeight + 'px';
let elem: Element = this.el.nativeElement;
console.debug(`updateFixedTableHeight(): this.fixedTableHeight = ${this.fixedTableHeight}`);
let rowHeights = 0;
if (this.collapsibleTableRowComponent != null) {
this.collapsibleTableRowComponent.forEach(row => {
console.debug(row.getHeight());
});
}
}*/
updateStriped(row: CollapsibleTableRowComponent): void {
if (this.striped && row.isBodyRow) {
row.isParentStriped = true;
if (row.isOddRow) {
row.parentStripedRowBackgroundColor = this.stripedOddColor || CollapsibleTableRowComponent.DEFAULT_STRIPED_ODD_ROW_COLOR;
row.parentStripedRowTextColor = this.stripedOddTextColor || CollapsibleTableRowComponent.DEFAULT_ROW_TEXT_COLOR;
row.rowBackgroundColor = row.parentStripedRowBackgroundColor;
row.rowTextColor = row.parentStripedRowTextColor;
} else {
row.parentStripedRowBackgroundColor = this.stripedEvenColor || CollapsibleTableRowComponent.DEFAULT_STRIPED_EVEN_ROW_COLOR;
row.parentStripedRowTextColor = this.stripedEvenTextColor || CollapsibleTableRowComponent.DEFAULT_ROW_TEXT_COLOR;
row.rowBackgroundColor = row.parentStripedRowBackgroundColor;
row.rowTextColor = row.parentStripedRowTextColor;
}
} else {
row.isParentStriped = false;
row.rowBackgroundColor = undefined;
row.rowTextColor = undefined;
}
}
updateHighlight(row: CollapsibleTableRowComponent): void {
row.isParentHighlight = this.highlight;
row.parentHighlightRowBackgroundColor = this.highlightColor || CollapsibleTableRowComponent.DEFAULT_HIGHLIGHT_ROW_COLOR;
row.parentHighlightRowTextColor = this.highlightTextColor || CollapsibleTableRowComponent.DEFAULT_ROW_TEXT_COLOR;
}
updateActive(row: CollapsibleTableRowComponent): void {
row.activeRowBackgroundColor = this.activeColor || CollapsibleTableRowComponent.DEFAULT_ACTIVE_ROW_COLOR;
row.activeRowTextColor = this.activeTextColor || CollapsibleTableRowComponent.DEFAULT_ROW_TEXT_COLOR;
}
updateSelect(row: CollapsibleTableRowComponent): void {
row.parentAllowsSelect = this.select;
row.parentAllowsSelectMultipleRows = this.selectMultipleRows;
row.parentAllowsDeselectingRows = this.allowDeselectingRows;
if (row.selected) {
row.selectedRowBackgroundColor = this.selectColor || CollapsibleTableRowComponent.DEFAULT_SELECTED_ROW_COLOR;
row.selectedRowTextColor = this.selectTextColor || CollapsibleTableRowComponent.DEFAULT_ROW_TEXT_COLOR;
row.rowBackgroundColor = row.selectedRowBackgroundColor;
row.rowTextColor = row.selectedRowTextColor;
}
}
updateTable(change?: string): void {
if (this.collapsibleTableRows != null) {
if (change != null) {
switch (change) {
case 'striped':
// propagate changes to each of the CollapsibleTableRowComponent children
this.collapsibleTableRows.forEach(row => { this.updateStriped(row); });
break;
case 'highlight':
this.collapsibleTableRows.forEach(row => { this.updateHighlight(row); });
break;
case 'active':
this.collapsibleTableRows.forEach(row => { this.updateActive(row); });
break;
case 'select':
this.collapsibleTableRows.forEach(row => { this.updateSelect(row); });
break;
}
} else {
// propagate changes to each of the CollapsibleTableRowComponent children
this.collapsibleTableRows.forEach(row => {
this.updateStriped(row);
this.updateHighlight(row);
this.updateSelect(row);
this.updateActive(row);
});
}
}
}
keydown(event: KeyboardEvent) {
// console.debug(`keydown, ${event.which}`);
// select a row only if 'select' property is set to 'true'
if (this.select && this.allowKeyboardNavigation) {
enum Key {
arrowUp = 38,
arrowDown = 40,
home = 36,
end = 35
}
let index = 1;
if (Key[event.which] != null) {
event.preventDefault();
event.stopPropagation();
switch (event.which) {
case Key.arrowUp:
// select previous row
if (this.selectedRows.length > 0) {
index = this.selectedRows[this.selectedRows.length - 1];
index--;
}
break;
case Key.arrowDown:
// select next row
if (this.selectedRows.length > 0) {
index = this.selectedRows[this.selectedRows.length - 1];
index++;
}
break;
case Key.home:
index = 1;
break;
case Key.end:
index = this.collapsibleTableRows.length - 1;
break;
}
this.clearSelectedRows();
this.deselectAllRows();
this.selectRow(index);
this.updateTable();
}
}
}
mousedown() {
this.mouseDownHold = true;
}
mouseup() {
this.mouseDownHold = false;
}
}