@sedeh/flexible-table
TypeScript icon, indicating that this package has built-in type declarations

3.2.6 • Public • Published

Welcome to Flexible table!

Have you ever looked for a simple way of flushing your JSON data in a versatile table by passing in a few meta-data instructions just to get your data displayed the way you wanted with interactive components inside? AND how about adding graphics into the resulting table with some nifty formatting rules just by mapping your JSON data into table column headers! AND not paying a dime for it? Ha? Say it again!!

And all is done without writing much of any code!! On top of that, if you do not want to take time and write meta-data rules, FlexibleTable will generate the rules for you! You can feed any data to the table and see it tabulated!! without writing a single line of code!

FlexibleTable and LockTable are Angular based code. LockTable will allow you to lock/unlock columns. Both tables are fully configurable with pagination and ability to re-order table columns through drag/drop operation. You can insert a cusrtom content on top or bottom caption area in both tables usibng topCaption and bottomCaption as selectors.

NOTE Current version 3.2.6

Please send your requests or comments through Comments/Requests

View it in action on Live Demo

Get it from NPM

alt text

alt text

Features

  • Responsive
  • map any part of your data to a column in the table
  • Pagination enabled / disabled
  • Indexing enabled / disabled
  • Expand / Collapse rows
  • Configure any column to sort content
  • Configure any column to show / hide
  • Configure any column to format content
  • Configure any column to reorder by drag/drop
  • Configure any column to filter content
  • ADA Compliant

Dependencies

MODULE:
  FlexibleTableModule

EXPORTS:
VocabularyInterface
PipeServiceComponentInterface
StyleServiceInterface
PaginationInfo
FlexibleTableHeader
PaginationType
CellEditInfo
FilteredItemsInfo
ActionEventInfo
ChangedtemsInfo
VisualizationPoint
FlexibleTableComponent
LockTableComponent
TableHeadersGenerator

DEPENDENCIES: 
    "@sedeh/drag-enabled": "^4.3.3",
    "@sedeh/into-pipes": "^4.5.3",
    "font-awesome": "^4.7.0"

Design system

Create a css file with the following and modify its value to fit your application needs. Then include it in root of application css file.

:root {
    --sedeh-text-color: black;
    --sedeh-text-background-color: white;
    --sedeh-marker-color: #fabdab;
    --sedeh-disabled-color: #888;
    --sedeh-margin: 0 5px;
    --sedeh-margin-right: 5px;
    --sedeh-margin-left: 5px;
    --sedeh-margin-bottom: 5px;
    --sedeh-padding: 5px;
    --sedeh-padding-top: 5px;
    --sedeh-padding-bottom: 5px;
    --sedeh-min-width: 25px;
    --sedeh-min-height: 25px;
    --sedeh-shift-right: -2px;
    --sedeh-focus-color: darkblue;
    --sedeh-sected-color: green;
    --sedeh-disapproved-color: red;
    --sedeh-hover-opacity: 0.5;
    --sedeh-box-shadow: 6px 8px 6px -6px #1b1b1b;
    --sedeh-solid-border: 1px solid #999;
    --sedeh-caption-color:  #fff;
    --sedeh-caption-background-color:  cadetblue;
    --sedeh-pagination-color:  #fff;
    --sedeh-pagination-background-color:  cadetblue;
    --sedeh-notice-color: white;
    --sedeh-notice-background-color: rgb(4, 159, 255);
    --sedeh-shim-color: rgba(255, 255, 255, 0.2);
    --sedeh-table-header-color: #bbb;
    --sedeh-table-header-border-color: #ccc;
    --sedeh-table-header-background-color: #eee;
    --sedeh-table-row-border-color: #ddd;
    --sedeh-table-row-hover-background-color: #FFEED2;
    --sedeh-table-cell-border-color: #B1B3B3;
    --sedeh-table-cell-color: #254a5d;
    --sedeh-alert-color: #8b0224;
    --sedeh-alert-border-color: #fff;
}

How to do it?

It is very simple. You have a JSON data to display and you want to allow user to configure columns, plus having ability to paginate, and sort/drag specific columns. All you will need is to add a header JSON and you are set to get the job done. That simple!!

Let's say you have the following data to be displayed:

{
  "guid": "701134c1-82cd-4f24-a867-f896350643f9",
  "isActive": false,
  "balance": "$3,666.56",
  "picture": "https://image.flaticon.com/icons/png/128/701/701997.png",
  "age": 37,
  "eyeColor": "brown",
  "name": "Cecelia Hartman",
  "gender": "female",
  "company": "MOMENTIA",
  "email": "ceceliahartman@momentia.com",
  "phone": "+1 (937) 578-2156",
  "address": {
    "street": "548 Clymer Street",
    "suite": "Apt. 556",
    "city": "Loveland",
    "zipcode": "92998-3641"
  },
  "about": "Est voluptate ea occaecat officia excepteur anim ipsum. Ipsum aliquip pariatur.\r\n",
  "registered": "2016-09-03T07:03:48 +07:00",
  "latitude": -56.348654,
  "longitude": 52.767967,
  "tags": [
    "est",
    "id",
    "ut",
    "sint",
    "cillum",
    "minim",
    "commodo"
  ],
  "friends": [
    {
      "id": 0,
      "name": "Yang Barrera"
    },
    {
      "id": 1,
      "name": "Rosella Lane"
    },
    {
      "id": 2,
      "name": "Doyle Welch"
    }
  ],
  "greeting": "Hello, Cecelia Hartman! You have 5 unread messages.",
  "favoriteFruit": "banana"
}

And you want user ID, name, user-name, the city he/she lives in, and the company works for. All you need is to map your data as it follows:

[
	  {key: "name",value: "Name",present: true, dragable:true, sortable: true},  
	  {key: "isActive",value: "Active",present: true, dragable:true, sortable: true, format: "if:~:true:\"font:fa fa-check:replace\":\"\""},
	  {key: "picture",value: "Picture",present: true, dragable:true, sortable: true, format: "image:auto:32px"},
	  {key: "address.city",value: "City", present: true, dragable:true, sortable: true},  
	  {key: "company",value: "Company",present: true, dragable:true, sortable: true} 
  ]

The above will instruct the table to make the mentioned columns visible and sortable. You can hide anyone of them or disable sorting on any columns. You can make them draggable or have the content of a cell formatted if you add a "format" attribute to the column meta-data you want to be formatted.

For example: "format: 'date:MM/dd/yyyy'" or "format: 'currency'"

Now you need to set the Pagination data To something like:

{
	pageSize:8,
	currentPage:1,
	from:0,
	resetSize: true,
	contentSize: 0
}

AND pagination data should re-evaluate contentSize immediately when data items are available

	this.service.usersList().subscribe(
    	(users) => {
        	this.users = users.json();
        	this.pageInfo.contentSize = this.users.length;
    	}
    )

Now you need to set the table tag in your HTML content:

<flexible-table 
      *ngIf="users" 
      caption="total records found {{users.length}}" 
      [headers]="usersHeader" 
      [items]="users" 
      [inlinePagination]="true"
      [pageInfo]="pageInfo"
      enableIndexing="true"
      actionable="true"
      configurable="true"
      [rowDetailer]="detailer"
      (onconfigurationchange)="onconfigurationchange($event)"
      (onaction)="onaction($event)">
      <div #topCaption>This should be rendered in top cption area</div>
      <div #bottomCaption>This should be rendered in bottom cption area</div>
      </flexible-table>

<ng-template #detailer let-detail="data">
  <div class="custom-class">
    <h3>Detail information about row {{detail.id}}</h3>
    <ol>
      <li>id: {{detail.id}}</li>
      <li>name: {{detail.name}}</li>
      <li>username: {{detail.username}}</li>
      <li>email: {{detail.email | into:'email'}}</li>
      <li>address: {{detail.address | into:'address'}}</li>
      <li>phone: {{detail.phone}}</li>
      <li>website: {{detail.website | into:'link'}}</li>
      <li>company: {{detail.company.name}}</li>
    </ol>
  </div>
</ng-template>

You will also need to implement a few functions

  allowExpanding(item, showIcon) {
    return (item.company || item.address); 
    // or any other way to determine if you can allow expanding of given item in a row
  }
  
  onaction(event) {
    // decide on what to do with the event
  }
  onconfigurationchange(event) {
    // decide on what to do with the event
  }

Interfaces

// service that controls specific cell in the table at a given location.
export interface StylePositionInterface {
    type: string;
    item?: any;
    header?: FlexibleTableHeader;
}
export interface StyleServiceInterface {
    styleFor(location: StylePositionInterface): string;
}

export interface FlexibleTableHeader {
  key: string; // key to identify column
  value: string; // column label
  present: boolean; // if column should be displayrf
  width?: string; // column width
  minwidth?: string; // minimum column width
  format?: string | string[]; // format column content into specified displayable component (use to IntoPipes)
  hideOnPrint?:boolean; // hide column when printing it
  filter?: string; // user editted key to filter rows on the column
  filterOptions?: string[]; // options if filter on column is a dropdown
  selectedFilterOption?: string; // selected option if filter is a dropdown
  dragable?: boolean; // if column can be dragged on
  dropable?: boolean; // if column can be dropped on
  sortable?: boolean; // if column can be sorted
  ascending?: boolean;// column soer order
  descending?: boolean;// column sort order
  class?:string; // apply css class on thecolumn
  locked?:boolean; // if column is locked in a lock tabled
  lockable?: boolean;// if column can be locked/unlocked in a lock table
  active: boolean; // if column can receive tab focun on its rows
  disabled: boolean;// if formatted columns are disabled and are not editable
  validate?: (tem: any, value: any) =>boolean; // if column row changes can be chaned after being validated
}

Attributes (LockTableComponent)

  • Expand / Collapse rows (will not happen for LockTableComponent. But is available on FlexibleTableComponent)

Formatting the table cell content.

We are using "@sedeh/into-pipes" library. to see available formatting options, please follow what is supported by the library.

Attributes (FlexibleTableComponent)

Attribute Status Description
caption Optional Caption to be displayed
action Optional off-screen message to be displayed if click on a row results in an action. If supplied, action column will be displayed and will take effect on user click
actionKeys Optional parameters to feed the action. parameters should exist in headers mapping.
tableClass Optional class name to be assigned to the table.
headers Optional mapping of items to be displayed as headers including instructions on formatting, dragging, ...
items Required items to be displayed
pageInfo Optional pagination information. If is not supplied, pagination will not take place.
tableInfo Optional Information about component owning the table. this information will be passed to the component that will display when a row is expanded.
inlinePagination Optional Flag to make pagination display as a sticky div or stay in a fixed location at the bottom right corner of table.
configurable Optional flag to allow hiding/displaying of specific headers.
enableIndexing Optional flag to display index of rows.
rowDetailer Optional reference to template that should be displayed when a row is expanded.
expandable Optional in component that owns the table which determines in a specific row is expandable. This function is called twice with a flag argument. If flag is false, call is to determine if action icon should be displayed on row. otherwise is to give before expansion opportunity to the owner to perform possible operation before expansion on the table take effect.
expandIf Optional flag to override calling of expandable function.
rowDetailerHeaders Optional If the expanding row should be displayed in another table inside, then this attribute will be passed to the expansion template.
configAddon Optional Template to include additional control items alongside print and configure actions.

Attributes (LockTableComponent)

Attribute Status Description
caption Optional Caption to be displayed
action Optional off-screen message to be displayed if click on a row results in an action. If supplied, action column will be displayed and will take effect on user click
actionKeys Optional parameters to feed the action. parameters should exist in headers mapping.
tableClass Optional class name to be assigned to the table.
headers Optional mapping of items to be displayed as headers including instructions on formatting, dragging, ...
items Required items to be displayed
pageInfo Optional pagination information. If is not supplied, pagination will not take place.
inlinePagination Optional Flag to make pagination display as a sticky div or stay in a fixed location at the bottom right corner of table.
tableInfo Optional Information about component owning the table. this information will be passed to the component that will display when a row is expanded.
configurable Optional flag to allow hiding/displaying of specific headers.
enableIndexing Optional flag to display index of rows.
filterwhiletyping Optional flag to perform filtering while typing in a filter field. If not set will filter only on a hit return after typing.
configAddon Optional Template to include additional control items alongside print and configute actions.

Metadata Rules

Metadata status Description
key Required JSON path to the value to be displayed on a column.
value Required Title of the column on the table.
present Optional Display the column if set. Hide it otherwise.
width Optional Column width.
minwidth Optional Minimum column with.
format Optional How the cell should be displayed. use into-pipe components to make the cell interactive and editable.
filter Optional If undefined, no filtering. Otherwise show filter field for the column.
dragable Optional Should column position be reorganized through drag and drop action?
sortable Optional Should the column be sortable?
class Optional Apply the class to the column.
locked Optional In a lock table, should the column be locked out.
hideOnPrint Optional Should the column be displayed when prinitinf.

Events

Event Description
onaction Will be published on a click action of a row
onfilter Will be published on when user types in something in filter fields to reduce table rows.
onCellContentEdit Will be published when content of an editable cell is modified
onconfigurationchange Will be called when user selects to hide/un-hide some of headers on configuration pop-up

Filtering rules

Operand Example Description
< <5 Perform less than operation
> >5 Perform greater than operation
! !5 Perform not equal operation
= =5 Perform equal to operation
* *Name Perform Ends with operation
* Name* Perform Starts with operation
* * Name* Perform contains with operation
Name Same as contains with operation

Adding custom pipe component to create interactive cell items

import { Component, EventEmitter } from '@angular/core';
import { PipeComponent } from '@sedeh/into-pipes';

@Component({
    selector: 'link-component',
    template: `<a [href]="'http://somewhere.com/?id=' + data.userId" [target]="target" [textContent]="source"></a>`,
    styles: [
        `
        color: blue;
        `
    ]
})
export class CustomLinkComponent implements PipeComponent {
  source: string;
	id: string;
	data: any;
	name: string;
  title: string;
  target: string;
	onIntoComponentChange: EventEmitter<any>;

    transform(source: any, data: any, args: any[]) {
        this.data = data;
        this.source = source;
        this.target = (args && args.length) ? args[0] : "";
        this.title = (args && args.length > 1) ? args[1] : "";
    }
}

Then you need to register it

import { ComponentPool } from '@sedeh/into-pipes';
...
constructor(private pool:ComponentPool){
  // you can also register this as "link" in which it will override default link component.
  this.pool.registerComponent("myLink",new CustomLinkComponent())
}

then you will need to use your formatter in header meta-data

{key:'userName', value:'Name', present: true, format:'myLink'}

Using tags

Sample table tag in your HTML content:

<flexible-table 
      caption="total records found {{users.length}}" 
      action="View details of %name% where ID is %id%"
      actionKeys="%name%,%id%"
      tableInfo="users table"
      persistenceId="usersRecordsTable"
      persistenceKey="users-headers-05012019"
      [filterwhiletyping]="true"
      [headers]="usersHeader" 
      [items]="users" 
      [pageInfo]="userPageInfo"
      [styler]="styler"
      [enableIndexing]="true"
      [showActionable]="showActionable"
      [enableFiltering]="true"
      [configurable]="true"
      [inlinePagination]="true"
      [configAddon]="configAddon"
      [detailers]="{ global: globalDetailer, name: NameDetailer }"
      [expandable]="allowExpanding"
      (onfilter)="onfilter($event)"
      (onCellContentEdit)="onCellEdit($event)"
      (onconfigurationchange)="onconfigurationchange($event)"
      (onaction)="onaction($event)"></flexible-table>

<lock-table 
      caption="total records found {{lockUsers.length}}" 
      action="View details of %name% where ID is %id%"
      actionKeys="%name%,%id%"
      tableInfo="lock users table"
      [styler]="styler"
      [enableIndexing]="true"
      [enableFiltering]="true"
      [configurable]="true"
      [filterwhiletyping]="filterLockTyping"
      [inlinePagination]="inlineLockPagination"
      [headers]="lockHeader" 
      [items]="lockUsers" 
      [pageInfo]="lockPageInfo"
      (onfilter)="onfilter($event)"
      (onCellContentEdit)="onCellEdit($event)"
      (onconfigurationchange)="onconfigurationchange($event)"
      (onaction)="onaction($event)"></lock-table>

And the styler could because

class StylerService implements StyleServiceInterface {
	styleFor(location: StylePositionInterface) {
    switch(location.type) {
      case 'header': return location.header?.key === 'age' ? 'background-color: red;color: black' : 'background-color: #efefef;color: black';
      case 'filters': return location.header?.key === 'age' ?  'background-color: red;color: black' : 'background-color: #efefef;color: black';
      case 'row': return location.item ?
        (location.item.age === 31 ? 
            (location.header?.key === 'age' ? 'background-color: green;color: white' : 'background-color: red;color: white'): 
            (location.header?.key === 'age' ? 'background-color: red;color: white' : '')) :
        '';
      case 'detail': return location.item?.age === 31 ? 'background-color: green;color: white': 'background-color: #eee;';
    }
    return '';
  }
}

Revision History

Version Description
3.2.6 fixed styling and few other logical issues. preparing for serverside pagination on next release.
3.2.5 Enhnced functionality to control row/column colors. Added Design system to chage style per application needs.
3.2.3 Documentation update.
3.2.1 fixed few issues reated to configuration of checkbox and add/remove of pagination.
3.2.0 fixed few issues reated to configuration of columns
3.1.0 fixed few issues reated to auto header generation and drag/drop of columns
3.0.0 Updated to Angular 15 and added functionalities
2.0.1 Fixed issue caused by upgarde to angular 8.
2.0.0 Updated to Angular 8.
1.8.9 Worked on table printing and improved mobile display. Added hideOnPrint option to have control over printing columns.
1.8.8 Updated dependencies.
1.8.7 Added fix for sorting if column is number, date, currency formatted.
1.8.6 fixed sorting numbers if given as strings. fixed pagination to keep sorting order when paginating table.
1.8.5 made filtered event trigger after sort so the items sent would reflect the table row order.
1.8.4 Added onfilter event if there is a need to update some other parts of application when list is filtered.
1.8.3 fixed display issues. upgraded into-pipes library to benefit hover effects over interactive cells.
1.8.2 Updated dependencies.
1.8.0 It was brought to my attention that some users have trouble using my components in their angular 6 environment. Since I had only updated few dependencies when moved to Angular 6, I am thinking dependencies are causing issues. So, for this release, I am updating all dependencies to what Angular 6 applications are expecting to have. Please let me know if this is fixing or not fixing any issues you are facing.
1.7.3 Fixed problem with table. When pagination is not given to the table, an undefined exception was occurring.
1.7.2 rolling to angular 6+ after fixing the dependency issue.
1.7.1 Temporary roll-back to angular 5. I forgot to luck-down the dependencies for angular 5 before upgrading to angular 6. this will cause problem if you are still using angular 5.
1.7.0 Updated libraries to become compatible with Angular 6+.
1.6.0 Fixed issue with filtering while using operational characters. If allowing filter while typing and if type an operation character like "*", "!","=","<", ">" we do not want to filter any row out of tabulating data. Also, modified printing mechanism to print only the current page. In case of 4000 records in a table, we definitely do not want to print all rows to avoid performance degradation.
1.5.6 Made performance improvement for filtering. If there are more than 1000 records and you have set the filterWhileTyping, then there could be performance issues. As a result, removed case insensitivity to perform better. Also, introduced delay filtering for those who type fast!!
1.5.5 Made performance improvements. Upgraded into-pipes version.
1.5.2 Upgraded into-pipes version.
1.5.1 Provided configAddon attribute to include additional control items along side the print and configuration buttons. Consider a situation where you want to have a add row to a table inside a table expandable row. in such a case you would want to place the buttons in right place for each table. to make this happen, create a ng-template for the additional controls and pass a reference to it to the corresponding table thruogh configAddon attribute. For example, You can use the configAddon to give information about filtering operations and print policy or for any other reaon you see it fit.
1.4.7 Upgraded to latest version of into-pipes and introduced onCellContentEdit event which will be triggered when cell content is edited. To make a cell editable, use format attribute of header meta-data. Look at documentation of into-pipes to decide if you want to format a field into a text, a checkbox, a select drop-down or any other formats. If you want to format a cell in a special way that is not supported by into-pipes, you will need to create a custom component and register. For example, lets say you want to display a link and the link href should point to somewhere with other parameters in the road. You would need to import ComponentPool, create your format component, and register it. You will then have to register it and use the registered component name as a format rule. When a cell content is edited, you will receive onCellContentEdit event where you will have opportunity to save the changed cell content in your data source.
1.4.6 Added a flag for filtering lookup to filter while tying vs. filter after a hit return.
1.4.5 Compiled with AOT option and resolved issues.
1.4.0 Fixed few issues and added persistence to table configuration. As a result, if you enable persistence, you will need to give a version number through "persistenceKey". This is necessary for the persistence mechanism to decide if it has to take the stored data or override it because of difference in version number. "persistenceId" is necessary if you are using multiple persistent tables in your application. If persistence is enabled and you are not supplying headers meta-data and flexible table auto generates the headers for you, then auto generation will happen only once and future generations will be lost because persisted headers will override generation of new headers. If you are modifying the headers by adding, removing, or replacing header meta-data; then you have to change the "persistenceKey" as well. Also, an optional minwidth attribute is added to table headers meta-data. this can become handy if you are setting a width on some headers and not others.
1.3.0 Fixed few issues and added ability to print the content of flexible table.. Did not do the same for lock table as it is not an easy thing to do. If you are making a flexible table configurable, you will be able to see two icons side by side.. one for printing and the other for configuring display columns.
1.2.0 Flexible table is now getting more flexible... if you do not supply the headers meta-data, smart table will generate it for you. This will be a good way of flushing unknown JSON into the table and have it displayed. In addition, a filtering mechanism is added. If you enable filtering of a column, then you can filter rows based on what is typed in the filter for that columns. You will need to specifically add blank filter (filter: "") attribute in headers meta-data or enable filter for each header through configuration panel. If smart table is generating headers automatically, it will include filters attribute if filtering is enabled. When requesting to filter on a column, you have option of including the following operands:
1.1.0 With this release you will be able to make table cells editable / intractable.. For more information read into-pipes documentation.
1.0.0 Good news. With this release you will have access to lockable table!!
0.1.0 This release is basically performance improvements and internal arrangement of components to make it possible to provide additional functionalities which will be released soon.
0.0.1 Initial release.

How to include font-awesome in your project?

In your project root folder, find and open the file 'angular-cli.json' in any editor Locate the styles[] array and add font-awesome references directory. like:

"apps": 
	[
        {
            ....
            "styles": [
              "../node_modules/font-awesome/css/font-awesome.css"
              "styles.css"
            ],
            ...
        }
    ]

Package Sidebar

Install

npm i @sedeh/flexible-table

Weekly Downloads

10

Version

3.2.6

License

none

Unpacked Size

894 kB

Total Files

28

Last publish

Collaborators

  • msalehisedeh