3.2.6 • Published 2 months ago

@sedeh/flexible-table v3.2.6

Weekly downloads
-
License
-
Repository
-
Last release
2 months ago

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)

AttributeStatusDescription
captionOptionalCaption to be displayed
actionOptionaloff-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
actionKeysOptionalparameters to feed the action. parameters should exist in headers mapping.
tableClassOptionalclass name to be assigned to the table.
headersOptionalmapping of items to be displayed as headers including instructions on formatting, dragging, ...
itemsRequireditems to be displayed
pageInfoOptionalpagination information. If is not supplied, pagination will not take place.
tableInfoOptionalInformation about component owning the table. this information will be passed to the component that will display when a row is expanded.
inlinePaginationOptionalFlag to make pagination display as a sticky div or stay in a fixed location at the bottom right corner of table.
configurableOptionalflag to allow hiding/displaying of specific headers.
enableIndexingOptionalflag to display index of rows.
rowDetailerOptionalreference to template that should be displayed when a row is expanded.
expandableOptionalin 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.
expandIfOptionalflag to override calling of expandable function.
rowDetailerHeadersOptionalIf the expanding row should be displayed in another table inside, then this attribute will be passed to the expansion template.
configAddonOptionalTemplate to include additional control items alongside print and configure actions.

Attributes (LockTableComponent)

AttributeStatusDescription
captionOptionalCaption to be displayed
actionOptionaloff-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
actionKeysOptionalparameters to feed the action. parameters should exist in headers mapping.
tableClassOptionalclass name to be assigned to the table.
headersOptionalmapping of items to be displayed as headers including instructions on formatting, dragging, ...
itemsRequireditems to be displayed
pageInfoOptionalpagination information. If is not supplied, pagination will not take place.
inlinePaginationOptionalFlag to make pagination display as a sticky div or stay in a fixed location at the bottom right corner of table.
tableInfoOptionalInformation about component owning the table. this information will be passed to the component that will display when a row is expanded.
configurableOptionalflag to allow hiding/displaying of specific headers.
enableIndexingOptionalflag to display index of rows.
filterwhiletypingOptionalflag to perform filtering while typing in a filter field. If not set will filter only on a hit return after typing.
configAddonOptionalTemplate to include additional control items alongside print and configute actions.

Metadata Rules

MetadatastatusDescription
keyRequiredJSON path to the value to be displayed on a column.
valueRequiredTitle of the column on the table.
presentOptionalDisplay the column if set. Hide it otherwise.
widthOptionalColumn width.
minwidthOptionalMinimum column with.
formatOptionalHow the cell should be displayed. use into-pipe components to make the cell interactive and editable.
filterOptionalIf undefined, no filtering. Otherwise show filter field for the column.
dragableOptionalShould column position be reorganized through drag and drop action?
sortableOptionalShould the column be sortable?
classOptionalApply the class to the column.
lockedOptionalIn a lock table, should the column be locked out.
hideOnPrintOptionalShould the column be displayed when prinitinf.

Events

EventDescription
onactionWill be published on a click action of a row
onfilterWill be published on when user types in something in filter fields to reduce table rows.
onCellContentEditWill be published when content of an editable cell is modified
onconfigurationchangeWill be called when user selects to hide/un-hide some of headers on configuration pop-up

Filtering rules

OperandExampleDescription
<<5Perform less than operation
>>5Perform greater than operation
!!5Perform not equal operation
==5Perform equal to operation
**NamePerform Ends with operation
*Name*Perform Starts with operation
* NamePerform contains with operation
NameSame 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

VersionDescription
3.2.6fixed styling and few other logical issues. preparing for serverside pagination on next release.
3.2.5Enhnced functionality to control row/column colors. Added Design system to chage style per application needs.
3.2.3Documentation update.
3.2.1fixed few issues reated to configuration of checkbox and add/remove of pagination.
3.2.0fixed few issues reated to configuration of columns
3.1.0fixed few issues reated to auto header generation and drag/drop of columns
3.0.0Updated to Angular 15 and added functionalities
2.0.1Fixed issue caused by upgarde to angular 8.
2.0.0Updated to Angular 8.
1.8.9Worked on table printing and improved mobile display. Added hideOnPrint option to have control over printing columns.
1.8.8Updated dependencies.
1.8.7Added fix for sorting if column is number, date, currency formatted.
1.8.6fixed sorting numbers if given as strings. fixed pagination to keep sorting order when paginating table.
1.8.5made filtered event trigger after sort so the items sent would reflect the table row order.
1.8.4Added onfilter event if there is a need to update some other parts of application when list is filtered.
1.8.3fixed display issues. upgraded into-pipes library to benefit hover effects over interactive cells.
1.8.2Updated dependencies.
1.8.0It 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.3Fixed problem with table. When pagination is not given to the table, an undefined exception was occurring.
1.7.2rolling to angular 6+ after fixing the dependency issue.
1.7.1Temporary 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.0Updated libraries to become compatible with Angular 6+.
1.6.0Fixed 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.6Made 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.5Made performance improvements. Upgraded into-pipes version.
1.5.2Upgraded into-pipes version.
1.5.1Provided 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.7Upgraded 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.6Added a flag for filtering lookup to filter while tying vs. filter after a hit return.
1.4.5Compiled with AOT option and resolved issues.
1.4.0Fixed 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.0Fixed 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.0Flexible 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.0With this release you will be able to make table cells editable / intractable.. For more information read into-pipes documentation.
1.0.0Good news. With this release you will have access to lockable table!!
0.1.0This 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.1Initial 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"
            ],
            ...
        }
    ]
3.2.6

2 months ago

3.2.5

2 months ago

3.2.4

2 months ago

3.2.3

2 months ago

3.2.2

2 months ago

3.2.1

2 months ago

3.2.0

2 months ago

3.1.1

2 months ago

3.1.0

2 months ago

3.0.1

2 months ago

3.0.0

2 months ago

2.0.2

4 years ago

2.0.1

4 years ago

2.0.0

4 years ago

1.8.9

5 years ago

1.8.8

5 years ago

1.8.7

5 years ago

1.8.6

5 years ago

1.8.5

5 years ago

1.8.4

5 years ago

1.8.2

5 years ago