Code Monkey home page Code Monkey logo

extended-table's Introduction

ExtendedTable

Node.js CI Performance Tests

Usage

<script>
    import ExtendedTable from "extended-table";
    
    let rows = [
        { startnumber: {number: 1}},
        { startnumber: {number: 2}},
        { startnumber: {number: 3}},
        { startnumber: {number: 4}},
    ];
    
    let columnDefinition = [
        {
            title: 'Start&shy;number',
            propertyPath: 'startnumber.number'
        },
    ];
</script>

<ExtendedTable columns={columnDefinition} data={rows}>
</ExtendedTable>

Examples

Have a look at the examples folder.

Features

Sorting

To make a column sortable, set sortable: true in the column definition. The column needs to have a property path set to make sorting work.

Initial sorting could be controlled via the props initialSortBy and initialSortDirection, where initialSortBy is a property path (string).

In case you want to allow sorting only one column, you need to set multisort={false}.

Flexible Rendering

The easiest way to render a column is to provide a propertyPath. This could even be in a nested Object. Have a look at deep-value to see more ways how to express paths.

To render slightly more complex data you could specify value, that needs to be a function:

    value: (rowData, rowIndex, columnIndex) => `Place ${rowIndex + 1}: ${rowData.name}`

If this is not enough, you could render columns as slots. You could currently specify no more than 20 slots due to a limitation in Svelte. All slots are named column-X, X being the number:

<ExtendedTable columns={columnDefinition} data={rows}>
    <div slot="column-1" let:data={person} let:rowIndex={index}>
        <Person person="{person}" on:edited={event => setValue(event.detail, index)}></Person>
    </div>
</ExtendedTable>

Of course, all three ways can be combined per Table. On a column level you have to decide on one way.

Flexible CSS Classes

Have a look at the theming example where this is explained.

ClickHandlers

To specify what happens when you click on a Row, you could set the onRowClick property. This should be a callback function.

For controlling what happens if you click a table cell, you could add a clickHandler on the column definition.

Collapsible Columns

If you have very large columns, you can render them as collapsible by setting collapsed: false on the column definition.

Auto collapse Columns

When autoCollapse={true} is set, all Columns that are outside of the screen are collapsed automatically. You still could collapse other columns manually, if you want.

Sticky Headers

Just set the stickyHeaders={true} prop, and you are ready. Please note, that specifying an overflow on a parent element will break the stickyness.

Additionally, you could define an offset, if you use fixed elements above (like a navigation header). Set stickyOffset="100px".

Limitations

This component aims for comfort more than for performance. So if you want to display thousands of rows, you may run into performance issues.

FAQ

How to add an extra row with colspan?

This could be done, if you fill the slot additionalRow. You'll get the data as rowData. Example:

    <tr slot="additionalRow" let:rowData={crew} class="keep-together">
        <td colspan="7">
            <MyOtherComponent myProp={crew} />
        </td>
    </tr>

How can I expand all collapsed columns on first click?

If you set expandAll={true}, all collapsed columns will expand at once.

Why is there no pagination?

IMHO, putting a pagination into this component would be too much. This should be done from outside.

How can I filter rows?

Like pagination this should be done from the outside. So its up to you to add a filter.

How can I use my own sorting function?

To use your own sorting function, you can set sortingFunction={yourSortFunction} property. This function gets called when you click on a header column. Parameters are:

  • column (Object) - the current column that was clicked on
  • columns (array) - All columns
  • data (array) - The rows
  • multisort (boolean) - true, if sorting for multiple columns is enabled
  • clearCacheCallback (function) - Callback to clear the caches

Troubleshooting

See Troubleshooting Guide.

Dependencies

Currently there are three dependencies:

Benchmarks

See here

extended-table's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

extended-table's Issues

defaults

Mostly about defaults for sorting, but leaving title to just "defaults" if you like to talk more than sorting.

I'd like to hear your thoughts and your use case on these defaults.

I've changed my local src to set config to { ...defaultConfig, ...config } to override these defaults:

  • sortable - for me, I don't find any reason to disable sorting on a col, so instead of adding sortable=true on every col, I like to just only define sortable=false as needed.
    FYI, the change for mouse-pointer logic is:
  if ((cfg.hasOwnProperty('sortable') && !cfg.sortable)) {
    // don't add mouse-pointer
  } else classes.push('mouse-pointer')

and to add defaults to columns:

  if (!sortingFunction) {
    sortingFunction = (cfg, columns, data, multisort, cacheClearCallback) => {
      cfg.sortable = cfg.hasOwnProperty('sortable') ? cfg.sortable : config.sortable
      return sortByColumn(cfg, columns, data, multisort, cacheClearCallback)
    }
  }
// Need more work if custom `sortingFunction` is passed.
  • multisort - for me, I default it to off because:
  1. the current UX does not help the user understand the multi-sorting
  2. The desire to allow multi-sort even if UX is good is usually no

Fix code duplication because of optional clickhandler on cell

In the code we have

{#if column.clickHandler}
  <td on:click|stopPropagation={() => column.clickHandler(d)} class="{getCellClasses(columnIndex, rowIndex, column, d)}" class:hidden={column.hidden}>
    ...
    <slot ...
    ...
  </td>
{:else}
  <td>
    ....
    <slot ...
    ...
{/if}

So because of the clickhandler we duplicate the config for 20 slots (massive code duplication). Not sure, if there is a way to avoid this.

Unfortunately I need this click handler..

Feature: Allow specifying css class per row, per cell

@dritter Thank you so much for such a great table library. I've looked at all table libraries for Svelte, and this is the best one. I have no idea why you aren't getting the traffic like others.

One feature I see lacking is there isn't a way to add css classes per row or cell other than using slots. It is extremely helpful if that is possible. One eg. of how I see they can be specified is introducing an optional rows prop that is declared similar to columns and className spec on columns props.

const data = [{
  value: 'a',
  count: 1,
  css: 'danger', // className on tr (row) specified
}, {
  value: 'b',
  count: 5,
  css: { count: 'success' }, // className on td (cell) specified
}, ...rest]

// new rows props spec
const rows = [{
    propertyPath: 'css',
    className: 'red', // optional value string or function for className on tr. If omitted, the value obtained via propertyPath is taken
}, ...otherRowsSpec]

const columns = [{ 
    title: 'Count', 
    propertyPath: 'count',
    className: { // new cell props spec
        propertyPath: 'css',
        value: (val) => val==='success' ? 'green' : "", // optional value string or function for className on td.
        // Just like for rows, if omitted, the value obtained via propertyPath is taken.
    }
}, ...otherColsSpec]

I would be thrilled if this is possible and believe others may be as well. Let me know what you think.

Create NPM package

It's about time.. ExtendedTable has reached a maturity level that can be released into the wild.

My edited version

Just want to give back and share my edited version I'm using locally and point out some highlights and why's of the changes.

https://gist.github.com/fuzzthink/2b39d046ea1efca393623fc8c0af5687

Highlights of changes:

  1. Use as single config object with key-vals of columns, rows, and pretty much all other configs. I've only added multisort because I want to override it to false.
  • The main benefit is the source code is now rowsCfg.forEach((cfg) =>, {#each config.columns as cfg, iCol}, cfg.something, etc. This makes reading the code much easier as it takes no brain power to see it is a config, whereas column.something and row.something does -- it takes that extra brain power to recall it's config, and that's not a good thing. Yes, the code can be changed to this w/o changing the interface, but why not introduce this benefit to the caller too?
  • The counterpart to it is the caller, it is much simpler <ExtTable data={rows} {config}>. And definition of config is clearly about config as well.
  const columns = [
    { propertyPath: 'acct', title: 'Acct', sortable: true },
   ...
  ]
  const config = {
    columns,
    rows: [...],
    ...rest,
  }
  1. Take out the classNames code into its own file. I love how short your code is, but it short as it is, it can be better extracting non-related code into its own file. tableClassNames.js is just that.
  2. Take advantage of js tooling and use ?. to simplify the logic. The current PR can be much easier to read with ?.. Take a look at tableClassNames.js, the logic is just 4 flat conditionals, no need for nesting ifs.
  3. Repeating the same code just because one has a on:click|stopPropagation and one doesn't is code smell to me. 90% of errors happens because we forget to apply the same fix needed to all the different places. I'm probably missing the need for the stopPropagation, but until I run into that problem, I'm not going to let that mess up my code. And if I do run into it, I believe there should be better solutions.
  4. Don't build something YAGNI. Supporting 20 columns of slots added 80 lines (40 lines if you take away the repeated code above). If you do need 20 cols of slots, don't make any changes (until svelte supports dynamic slot names). But don't ruin your code for something maybe one user out of 100/1000s may use it. For me, I think supporting just 1-3 cols in the start and end is enough.
  5. Minor stuff, mostly dev preferences, but I like keeping var names short as long as it is more readable to me, using const over let to show intention, using if (...) instead of (...) && -- much easier to read imho, see tableClassNames.js, and using ternaries more (getOddEvenClass).

With these changes, the main file is just 200 lines and 260 if classNames logic is not extracted. More importantly is readability, which imho, has been enhanced.

Please don't take this the wrong way, I've already mentioned how much I like your library. Just want to share my thoughts so you can take some of these suggestions if you think they are sound.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.