@tavanasystem/tips-mat-table
v1.1.5
Published
tips-mat-table is an Angular component for presenting large and complex data with a lightning fast performance (at least 10x faster) and excellent level of control over the presentation.
Downloads
7
Readme
Tips Mat Table
Dynamic Table built with Angular Material.
Online Demo
Version(1.1.4): Checkout this Repo!
Checkout this Demo! in stackblitz.com
Table of Contents
| No. | Questions | | --- | ----------------------------------------------------------------------------- | | 1 | Getting Started | | 2 | Inputs | | 3 | Outputs | | 4 | How to add international | | 5 | Table Events | | 6 | Form Field Cell | | 7 | Button Group Cell | | 8 | Toolbar Buttons | | 9 | additional Setting with TableSetting | | 10 | Pagination | | 11 | Advance and Simple Filter | | 12 | Releases |
Getting Started
A full demo can be found on the github repository.
Install with npm:
npm i @tavanasystem/tips-mat-table
After installation include TipsMatTableModule
in your module imports:
import { TipsMatTableModule } from '@tavanasystem/tips-mat-table';
...
imports: [
TipsMatTableModule
],
...
Column types are defined as follow:
export interface AbstractField {
index?: number;
name: string; // The key of the data
type?: "text" | "number" | "date" | "category"; // Type of data in the field
width?: number; // width of column
header?: string; // The title of the column
print?: boolean; // disply in printing view by defualt is true
isKey?: boolean;
inlineEdit?: boolean;
display?: "visible" | "hiden" | "prevent-hidden"; // Hide and visible this column
sticky?: "start" | "end" | "none"; // sticky this column to start or end
filter?: "client-side" | "server-side" | "none";
sort?: "client-side" | "server-side" | "none";
cellClass?: string; // Apply a class to a cell, class name must be in the data
footerClass?: string;
cellStyle?: any;
footerStyle?: any;
classNames?: string;
rowClass?: string | AtClassFunc;
customSortFunction?: AtSortFunc<R>;
customFilterFunction?: AtSortFunc<R>;
toPrint?: ToPrint;
toExport?: ToExport;
inputFieldConfig?: InputFieldConfig;
btnGroupConfig?: BtnGroupConfig;
footerFn?: string | ((allData?: any[]) => string);
}
Source data must be an BehaviorSubject:
let data = [
{ "row": 1, "name": "Element #4", "weight": "65 KG", "color": "Magenta", "brand": "Zanjan Benz", "type": "Van" }, ...];
this.dataSource = new BehaviorSubject<any[]>(data);
and for updating data just next
your new data
let newData = [
{ "row": 2, "name": "Element #5", "weight": "75 KG", "color": "Magenta", "brand": "Zanjan Benz2", "type": "Van" }, ...];
this.dataSource.next(newData);
In the HTML add the selector:
<tips-mat-table
tableName="Tips Mat Table"
[columns]="fields"
[dataSource]="dataSource$"
[pending]="pending"
[tableSetting]="tableSetting"
[rowContextMenuItems]="contextMenuItems"
[rowActionMenuItems]="contextMenuItems"
[toolbarItems]="toolbarItems"
[pagination]="pagination"
[rowSelectionMode]="rowSelectionMode"
[rowSelectionModel]="selectionModel"
[expandComponent]="expandComponentRef"
(onTableEvent)="tableEvent($event)"
>
</tips-mat-table>
Inputs:
columns
= Column definitions
dataSource
= Table data in BehaviorSubject
pending
= pending progress on table
rowSelectionMode
= active selection row ('single' | 'multi' | 'none')
rowSelectionModel
= new SelectionModel() from Angular Material Select
pagination
= configuration for pagination. eg: { pageIndex: 0, pageSize: 10, pageSizeOptions: [ 5, 10, 100, 1000], length:30 }
tableSetting
= many general setting of table include styles and features configuration
rowContextMenuItems
= a menu that shown in right click
rowActionMenuItems
= a menu that shown in end of the row in ActionMenu
toolbarItems
= at the footer of table, with right configuration it can be very usefull
expandComponent
= you can use this to show your extra data bitween two row as expanded
Outputs:
onTableEvent
= all the events of table witch included in TableEvents enum can be listen from this event
export interface ContextMenuItem {
name: string;
text: string;
color?: ThemePalette | string;
icon?: string;
disabled?: boolean | ((row: any) => boolean);
visible?: boolean | ((row: any) => boolean);
divider?: boolean;
styles?: any;
keyboardKey?: string; //Ctrl+ ( keyboard key like KeyS = 's')
}
this.rowActionMenuItems = [
{
name: "Edit",
text: "Edit",
color: "primary",
icon: "edit",
disabled: (row) => row.valid, //it also can be just a value or like this a function
visible: true, //it also can be just a value or like this a function
},
{
name: "Delete",
text: "Delete Record",
color: "warn",
icon: "delete",
disabled: false, //it also can be just a value or like this a function
visible: true, //it also can be just a value or like this a function
},
];
For more examples run the demo application.
How to add international
to support new language you must declare new class and implement LanguagePack for example this is persian language:
import { MatPaginatorIntl } from "@angular/material/paginator";
import {
FilterLabels,
LanguagePack,
MenuLabels,
TableLabels,
} from "@tavanasystem/tips-mat-table";
export class PersionLanguage implements LanguagePack {
constructor() {}
menuLabels: MenuLabels = {
saveData: "ذخیره داده ها ",
columnSetting: "تنظیمات ستون ها ",
saveTableSetting: "ذخیره تنظیمات جدول",
clearFilter: "فیلتر را پاک کنید",
jsonFile: "Json فایل",
csvFile: "CSV فایل",
printTable: "چاپ جدول",
filterMode: "نوع فیلتر",
filterLocalMode: "محلی",
filterServerMode: "سرور",
sortMode: "حالت مرتب سازی",
sortLocalMode: "سمت کاربر",
sortServerMode: "سمت سرور",
printMode: "حالت چاپ",
printYesMode: "بله",
printNoMode: "خیر",
pinMode: "حالت پین ",
pinNoneMode: "هیچ کدام",
pinStartMode: "شروع",
pinEndMode: "پایان",
};
paginatorLabels: MatPaginatorIntl = {
changes: null,
itemsPerPageLabel: "ایتم های هر صفحه:",
nextPageLabel: "صفحه بعدی:",
previousPageLabel: "صفحه قبلی:",
firstPageLabel: "اولین صفحه:",
lastPageLabel: "آخرین صفحه:",
getRangeLabel: (page: number, pageSize: number, length: number) => {
if (length === 0 || pageSize === 0) {
return `0 از ${length}`;
}
length = Math.max(length, 0);
const startIndex = page * pageSize;
const endIndex =
startIndex < length
? Math.min(startIndex + pageSize, length)
: startIndex + pageSize;
return `${startIndex + 1} - ${endIndex} از ${length}`;
},
};
tableLabels: TableLabels = {
NoData: "هیچ رکوردی پیدا نشد",
};
filterLabels: FilterLabels = {
Clear: "پاک کردن",
Search: "جستجو",
And: "و",
Or: "یا",
/* Text Compare */
Text: "متن",
TextContains: "دربرگرفتن",
TextEmpty: "خالی بودن",
TextStartsWith: "شروع شدن با",
TextEndsWith: " پایان گرفتن با",
TextEquals: "مساوی بودن",
TextNotEmpty: "خالی نبودن",
/* Number Compare */
Number: "تعداد",
NumberEquals: "مساوی",
NumberNotEquals: "مساوی نبودن",
NumberGreaterThan: " بزرگ تر از",
NumberLessThan: "کم تر از ",
NumberEmpty: "خالی بودن",
NumberNotEmpty: "خالی نبودن",
/* Category List Compare */
CategoryContains: "در برگرفتن",
CategoryNotContains: "در بر نگرفتن",
/* Boolean Compare */
/* Date Compare */
};
}
and passed this class to grid so :
providers: [{ provide: TableIntl, useFactory: languageIntl }];
And
export function languageIntl() {
return new PersionLanguage();
}
Table Events
you can use this switch to handle all events from onTableEvent (remove those you dont need :))
export enum TableEvents {
MasterSelectionChange = "MasterSelectionChange",//depricated
RowSelectionChange = "RowSelectionChange",
RowActionMenu = "RowActionMenu",
ReloadData = "ReloadData",
RowClick = "RowClick",
CellClick = "CellClick",
DblRowClick = "DblRowClick",
DblCellClick = "DblCellClick",
BeforContextMenuOpen = "BeforContextMenuOpen",
BeforActionMenuOpen = "BeforActionMenuOpen",
ContextMenuClick = "ContextMenuClick",
SortChanged = "SortChanged",
FormFieldCellEvent = "FormFieldCellEvent",
validatonChange = "validatonChange",
settingChange = "settingChange",
ToolbarItemEvent = "ToolbarItemEvent",
PaginationEvent = "PaginationEvent",
BtnGroupCellEvent = "BtnGroupCellEvent",
SimpleFilterEvent = "SimpleFilterEvent",
FooterCellClick = "FooterCellClick",
ExportData = "ExportData",
FilterClear = "FilterClear",
CtrlKeydown = "CtrlKeydown",
}
Form Field Cell
you can also add rows with a inline form or just edit a cell with giving this config to you column definition
export interface InputFieldConfig {
// neccesseries
id: string;
fieldType: FormElementType;
//view related
icon?: string;
label?: string;
class?: string;
styles?: any;
appearance?: MatFormFieldAppearance;
floatLabel?: FloatLabelType;
hideRequiredMarker?: boolean;
hideClearBtn?: boolean;
convertor?: (id: any, row?: any, column?: any) => string;
hasSeperator?: boolean;
seperator?: string;
hasMask?: boolean;
mask?: string;
maskPatterns?: any;
enableCellEditMode?: boolean;
//validators
min?: any;
max?: any;
inputType?: InputType;
customValidator?: (row: any) => ValidatorFn;
//field states
disabled?: boolean;
required?: boolean;
readonly?: boolean;
defaultValue?: any;
//messages
hint?: string;
error?: string;
placeholder?: string;
//events
blur?: (event: any) => void;
click?: (event: any) => void;
input?: (event: any) => void;
keyup?: (event: any) => void;
change?: (event: any) => void;
onResetValue?: (row?: any) => void;
onSuffixIconClick?: (row?: any, column?: any) => void;
//for select field
options?: Observable<Partial<{ value?: any, label?: string }>[]>;
onSelectItem?: (item: any, row?: any) => void;
onDataListChanged?: (list?: any[], row?: any) => void;
hasInitSelection?: boolean;
multiple?: boolean;
valueKey?: string; //default: value
labelKey?: string; //default: label
disableKey?: string; //default: disable
// + for auto-complete field
endTyping?: (searched: any, pageIndex?: number, row?: any) => void;
NoInitEndTyping?: boolean;
// + for multi-column-autocomplete
columnsConfig?: ColumnConfig[];
footerActions?: {
icon: string,
closeAfter?: boolean,
color?: ThemePalette | string,
disabled?: boolean | ((mainRow?: any) => boolean),
}[];
onRowEvent?: (event: any, row?: any) => void;
onFooterEvent?: (event: any, searched?: string) => void;
appendNewData?: (searched?: string, pageSize?: number, row?: any) => void;
refreshData?: (row?: any) => void;
NoDataLabel?: string;
selectHeightFn?: (data: any[], row?: any, column?: any) => string;
appendedOptions?: Observable<Partial<{ value?: any, label?: string }>[]>;
// + for duplicate-mc
secondSelectConfig?: InputFieldConfig;
secondSelectControlConfig?: {
icon?: string | ((row?: any, col?: any) => string),
svgIcon?: string | ((row?: any, col?: any) => string),
switchFn?: (row?: any, column?: any) => 1 | 2,
onSwitchEvent?: (type: 1 | 2, row?: any, column?: any) => void,
};
// for checkbox
checkboxLabelPosition?: "before" | "after";
onCheckChange?: (event: any) => void;
// for input-select
defaultInputSelectMode?: "input" | "select";
// for input
inputSuffixIcon?: string | ((row?: any, col?: any) => string);
}
and for Multi Column Auto Complete :
export interface ColumnConfig {
id: string;
title: string;
width?: string;
rowActions?: {
icon: string,
color?: ThemePalette | string,
disabled?: boolean | ((option?: any) => boolean),
}[];
}
this is all the types that we support until now
export type FormElementType =
| "input"
| "select"
| "auto-complete"
| "datepicker"
| "checkbox"
| "mc-auto-complete"
| "duplicate-mc"
| "input-select";
Button Group Cell
you can have one cell with many mat-icon-button to do some actions on row, it will give you the event with row and action
export interface BtnGroupConfig {
click?: (event: any) => void;
btnConfigs?: CellBtnConfig[];
}
export interface CellBtnConfig {
id: string;
tooltip?: string;
showMode?: "edit" | "show" | "always";
color?: ThemePalette | string;
icon?: string;
svgIcon?: string;
styles?: any;
disabledFn?: boolean | ((row: any) => boolean);
hideFn?: boolean | ((row: any) => boolean);
keyboardKey?: string; //Ctrl+ ( keyboard key like KeyS = 's')
}
Toolbar Buttons
you can have one diffrent types of buttons with custom styles and config
export interface ToolbarItem {
id: any;
tooltip?: string; //used as title too
disabled?: boolean | ((item?: ToolbarItem) => boolean);
hidden?: boolean | ((item?: ToolbarItem) => boolean);
styles?: any | ((item?: ToolbarItem) => any);
icon?: string;
svgIcon?: string;
color?: ThemePalette | string;
menuitems?: ToolbarMenuitemConfig[];
keyboardKey?: string; //Ctrl+ ( keyboard key like KeyS = 's')
btnType?:
| "mat-button"
| "mat-raised-button"
| "mat-flat-button"
| "mat-stroked-button"
| "mat-icon-button"
| "mat-fab"
| "mat-menu"
| "mat-mini-fab"; //default
}
export interface ToolbarMenuitemConfig {
id: any;
title: string;
hide?: boolean | (() => boolean);
disable?: boolean | (() => boolean);
icon?: string;
disableIcon?: string;
styles?: any | (() => any);
}
additional Setting with TableSetting
you can customize your table on many aspects to suit your needs and desires with the Power implemented in TableSetting
export interface TableSetting {
direction?: Direction;
columnSetting?: AbstractField[];
visibaleActionMenu?: VisibleActionMenu;
stickyActionMenu?: boolean;
visibleTableMenu?: boolean;
alternativeRowStyle?: any;
normalRowStyle?: any;
rowStyle?: any;
cellStyle?: any;
footerStyle?: any;
enableContextMenu?: boolean;
headerStyles?: DmtHeaderStyles;
ActionMenuMode?: "hover" | "menu";
tableBackgroundColor?: string;
paginatorLabels?: DmtpaginatorLabels;
defaultWidth?: number;
minWidth?: number;
headerHeight?: number;
rowHeight?: number;
showNoData?: boolean;
showReload?: boolean;
printConfig?: PrintConfig;
tableName?: string;
showPagination?: boolean;
expandContainerStyle?: any;
selectOnRowClick?: boolean;
toolbarStyles?: any;
hasFooter?: boolean;
tableNoDataMessage?: string;
serverSort?: boolean;
exportMode?: "SERVER" | "CLIENT";
hasFilterOnAllColumns?: boolean;
highlightMoveActive?: boolean;
shortkeyActive?: boolean;
SelectNoDataLabel?: string;
}
and you can specifically style headers with DmtHeaderStyles
export interface DmtHeaderStyles {
headerFontSize?: string;
headerColor?: string;
headerJustify?:
| "center"
| "flex-start"
| "flex-end"
| "space-between"
| string;
headerBackgroundColor?: string;
extraStyles?: any;
}
Pagination
like mat-paginator you can have pagination object like this:
export interface TablePagination {
length?: number;
pageIndex?: number;
pageSize?: number;
pageSizeOptions?: number[];
}
and you can also customize labels too:
export interface DmtpaginatorLabels {
itemsPerPageLabel: string;
nextPageLabel: string;
previousPageLabel: string;
firstPageLabel: string;
lastPageLabel: string;
toLabel: string;
fromLabel: string;
}
Advance and Simple Filter
you have notice the filter on headers , now we add simple filter witch just have one field and give you the data on what user has entered (of course we are still developing it!)
export interface TableField<R extends TableRow> extends AbstractField {
...
footerFn?: string | ((allData?: any[]) => string);
fliterMode?: "simple" | "advance"; //'advance' is default!
simpleFilterModeConfig?: SimpleFilterModeConfig;
convertor?: (id: any, row?: any, column?: any) => string;
}
export interface SimpleFilterModeConfig {
fieldType?: "input" | "checkbox-list" | "switch"; //'input' is default!
placeholder?: string;
defaultValue?: any;
switchTitle?: string;
disabledFn?: (column: any) => boolean;
options?: Partial<{ id: number | string; value: any; label: string }>[];
}
Releases
(from v1.1.3)
v1.1.4 :
Menu type in toolbar
- if you wnat menu in footer toolbar you can set
btnType
tomat-menu
inToolbarItem
like this:
this.toolbar = [
{
...
btnType: "mat-menu",
}
and after that, you can add your options in menuitems
like this:
this.toolbar = [
{
...
btnType: "mat-menu",
menuitems: [
{
id: "1",
title: "item 1",
},
{
id: "2",
title: "item 2",
},
{
id: "3",
title: "item 3",
},
],
}
]
also this might help you in your config :
export interface ToolbarMenuitemConfig {
id: any;
title: string;
hide?: boolean | (() => boolean);
disable?: boolean | (() => boolean);
icon?: string;
disableIcon?: string;
styles?: any | (() => any);
}
- now you dont need to do some hard styling or using
::ng-deep
to style table header , simply you just need add your style object in tableSetting like this:
tableSetting: TableSetting = {
...//other setting
headerStyles: {
...//other header styles
extraStyles: {
fontWeight: "900",
backgroundColor: "white",
"box-shadow": "-10px 2px 10px #ddd",
...//other styles
},
},
...
}
v1.1.5 :
- fix toolbar menu open position (2022/1/23)
- fix color type to take custom ThemePalette
- set pageIndex default value to 1 in endTyping